diff --git a/.gitignore b/.gitignore
index fd3a355..a36edcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -112,3 +112,7 @@ all.config
 
 # Kdevelop4
 *.kdev4
+
+# dtb objects
+*.dtb
+*.dtbo
diff --git b/Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr b/Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr
new file mode 100644
index 0000000..e2df613
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr
@@ -0,0 +1,63 @@
+What:		/sys/devices/platform/bone_capemgr/slots
+Date:		May 2015
+KernelVersion:	4.0
+Contact:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Description:
+		READ:
+		  Describe the state of all the slots of the beaglebone capemgr.
+		  Each line of the output describes a slot:
+		  The slot format is as following:
+		  <slot-id>: [P-][F-][O-][l-][L-][D-] \
+			  <overlay-id> <board-name>,<version>,
+			  <manufacturer>,<part-number>
+
+		Where the flags are:
+		P: Slot has been probed
+		F: Slot has failed probing (i.e. no EEPROM detected)
+		O: Slot has been overridden by the user
+		l: Slot is current loading
+		L: Slot has completed loading and is ready
+		D: Slot has been disabled
+
+		Example:
+		0: P---L-  -1 BeagleBone RS232 CAPE,00A1,Beagleboardtoys,BB-BONE-SERL-03
+		1: PF----  -1
+		2: PF----  -1
+		3: PF----  -1
+
+		WRITE:
+		  Writing a string of the form <part-number>[:version] issues a request to
+		  load a firmware blob containing an overlay. The name of the firmware blob
+		  is <part-number>-[version|00A0].dtbo. This act is defined as a slot override.
+
+		  Writing a negative slot id removes the slot if it was an overridden one, or
+		  unloads a slot that was probed.
+
+What:		/sys/devices/platform/bone_capemgr/baseboard/<eeprom-field>
+Date:		May 2015
+KernelVersion:	4.0
+Contact:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Description:	Contains the probed base board EEPROM field; one of:
+		board-name		- board-name as stored in cape EEPROM
+		dc-supplied		- whether the cape draws or supplies DC
+		eeprom-format-revision	- EEPROM format rev, only 00A0 supported
+		header			- header; should be 'aa 55 33 ee'
+		manufacturer		- manufacturer string
+		part-number		- part-number of the cape
+		serial-number		- serial number of the cape
+		version			- version of the cape, i.e. 00A0
+		number-of-pins		- displayed but ignored
+		pin-usage		- displayed but ignored
+		sys-5v			- displayed but ignored
+		vdd-3v3exp		- displayed but ignored
+		vdd-5v			- displayed but ignored
+What:		/sys/devices/platform/bone_capemgr/slot-<n>/<eeprom-field>
+Date:		May 2015
+KernelVersion:	4.0
+Contact:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Description:	Contains the probed cape's EEPROM field; the field is one of:
+		board-name		- baseboard name i.e. A335BNLT
+		header			- header; should be 'aa 55 33 ee'
+		revision		- baseboard revision
+		serial-number		- baseboard serial number
+		config-option		- displayed but ignored
diff --git b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
new file mode 100644
index 0000000..88d1549
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-devicetree-overlays
@@ -0,0 +1,52 @@
+What:		/sys/firmware/devicetree/overlays/
+Date:		October 2015
+Contact:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Description:
+		This directory contains the applied device tree overlays of
+		the running system, as directories of the overlay id.
+
+What:		/sys/firmware/devicetree/overlays/enable
+Date:		October 2015
+Contact:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Description:
+		The master enable switch, by default is 1, and when
+		set to 0 it cannot be re-enabled for security reasons.
+
+		The discussion about this switch takes place in:
+		http://comments.gmane.org/gmane.linux.drivers.devicetree/101871
+
+		Kees Cook:
+		"Coming from the perspective of drawing a bright line between
+		kernel and the root user (which tends to start with disabling
+		kernel module loading), I would say that there at least needs
+		to be a high-level one-way "off" switch for the interface so
+		that systems that have this interface can choose to turn it off
+		during initial boot, etc."
+
+What:		/sys/firmware/devicetree/overlays/<id>
+Date:		October 2015
+Contact:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Description:
+		Each directory represents an applied overlay, containing
+		the following attribute files.
+
+What:		/sys/firmware/devicetree/overlays/<id>/can_remove
+Date:		October 2015
+Contact:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Description:
+		The attribute set to 1 means that the overlay can be removed,
+		while 0 means that the overlay is being overlapped therefore
+		removal is prohibited.
+
+What:		/sys/firmware/devicetree/overlays/<id>/<fragment-name>/
+Date:		October 2015
+Contact:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Description:
+		Each of these directories contain information about of the
+		particular overlay fragment.
+
+What:		/sys/firmware/devicetree/overlays/<id>/<fragment-name>/target
+Date:		October 2015
+Contact:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+Description:
+		The full-path of the target of the fragment
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
index 21e71a5..383f6e2 100644
--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -24,6 +24,8 @@ Optional properties:
 - ti,no-reset-on-init: When present, the module should not be reset at init
 - ti,no-idle-on-init: When present, the module should not be idled at init
 - ti,no-idle: When present, the module is never allowed to idle.
+- ti,deassert-hard-reset: list of hwmod and hardware reset line name pairs
+  (ascii strings) to be deasserted upon device instantiation.
 
 Example:
 
diff --git b/Documentation/devicetree/bindings/misc/bone_capemgr.txt b/Documentation/devicetree/bindings/misc/bone_capemgr.txt
new file mode 100644
index 0000000..7e4fbc9
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/bone_capemgr.txt
@@ -0,0 +1,111 @@
+* Beaglebone cape manager driver
+
+Required properties:
+- compatible: "ti,bone-capemgr"
+- eeprom: phandle to the EEPROM baseboard.
+          The EEPROM framework interface is use to obtain the data.
+
+Required children nodes:
+
+- baseboardmaps: Contains nodes, which each of the them defines a mapping from
+		 the baseboard EEPROM board-name ID to a DT friendly compatible
+		 string.
+
+  - board-name:      The baseboard EEPROM board name, i.e. A335BONE for the
+                     original beaglebone white.
+  - compatible-name: The DT friendly compatible string to be used for matching
+		     compatible capes, i.e. "ti,beaglebone"
+
+
+ - nvmem-cells: Defines the phandles of the nvmem cells of the baseboard and the
+                slots.
+ - nvmem-cells: Defines the names of the nvmem cells. Required to have at
+                least a baseboard cell name.
+
+ - #slots:	Defines how many slots are there.
+
+- Example of a beaglebone cape-manager:
+
+bone_capemgr {
+	compatible = "ti,bone-capemgr";
+	status = "okay";
+
+	nvmem-cell = <&baseboard_data
+		      &cape0_data &cape1_data &cape2_data &cape3_data>;
+	nvmem-cell-names = "baseboard", "slot0", "slot1", "slot2", "slot3";
+
+	#slots = <4>;
+
+	/* map board revisions to compatible definitions */
+	baseboardmaps {
+		baseboard_beaglebone: board@0 {
+			board-name = "A335BONE";
+			compatible-name = "ti,beaglebone";
+		};
+
+		baseboard_beaglebone_black: board@1 {
+			board-name = "A335BNLT";
+			compatible-name = "ti,beaglebone-black";
+		};
+	};
+};
+
+The format of the cape to be loaded is in a standard overlay format with
+the following root properties that are interpreted by the cape manager:
+
+Required properties:
+ - compatible: Should be compatible to the baseboard according to the
+               baseboard map value, i.e. "ti,beaglebone".
+ - part-numer: Should contain the part-number as stored in the EEPROM.
+ - version:    Should contain a list of all the version that are supported
+               by the single cape dtbo, i.e. "00A1".
+
+Optional properties:
+ - exclusive-use: A string list which state the resources this cape requires.
+                  No processing or matching to anything regarding the internal
+		  kernel state is performed; it's purpose is to guard against
+		  conflicts with other capes.
+ - priority:      A priority to be assigned when loading a cape. A lower value
+                  has higher priority. The purpose of the priority is to control
+		  which cape is loaded first in case of a conflict.
+
+- Example of a serial cape:
+
+/dts-v1/;
+/plugin/;
+/ {
+        compatible = "ti,beaglebone", "ti,beaglebone-black";
+
+        /* identification */
+        part-number = "BB-BONE-SERL-03";
+        version = "00A1";
+
+        /* state the resources this cape uses */
+        exclusive-use =
+                /* the pin header uses */
+                "P9.21",        /* uart2_txd */
+                "P9.22",        /* uart2_rxd */
+                /* the hardware ip uses */
+                "uart2";
+
+        fragment@0 {
+                target = <&am33xx_pinmux>;
+                __overlay__ {
+                        bb_uart2_pins: pinmux_bb_uart2_pins {
+                                pinctrl-single,pins = <
+                                        0x150 0x21      /* spi0_sclk.uart2_rxd | MODE1 */
+                                        0x154 0x01      /* spi0_d0.uart2_txd | MODE1 */
+                                >;
+                        };
+                };
+        };
+
+        fragment@1 {
+                target = <&uart2>;
+                __overlay__ {
+                        status = "okay";
+                        pinctrl-names = "default";
+                        pinctrl-0 = <&bb_uart2_pins>;
+                };
+        };
+};
diff --git b/Documentation/devicetree/bindings/pinctrl/ti,iodelay-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ti,iodelay-pinctrl.txt
new file mode 100644
index 0000000..e12f4e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ti,iodelay-pinctrl.txt
@@ -0,0 +1,86 @@
+Texas Instruments I/O Delay module configuration pinctrl definition
+
+Used in conjunction with Documentation/devicetree/bindings/pinctrl/ti,omap-pinctrl.txt
+
+Required Properties:
+- compatible: Should be:
+  "ti,dra7-iodelay" - I/O delay configuration for DRA7
+- reg	- must be the register address range of IODelay module
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Important note: Use of "ti,dra7-iodelay" compatible definition need to be
+carefully evaluated due to the expectation of glitch during configuration.
+
+Example:
+
+dra7_iodelay_core: padconf@4844a000 {
+	compatible = "ti,dra7-iodelay";
+	reg = <0x4844a000 0x0d1c>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+};
+
+Configuration definition follows similar model as the pinctrl-single:
+The groups of pin configuration are defined under "pinctrl-single,pins"
+
+&dra7_iodelay_core {
+	mmc2_iodelay_3v3_conf: mmc2_iodelay_3v3_conf {
+		pinctrl-single,pins = <
+			0x18c (A_DELAY(0) | G_DELAY(120))	/* CFG_GPMC_A19_IN */
+			0x1a4 (A_DELAY(265) | G_DELAY(360))	/* CFG_GPMC_A20_IN */
+			0x1b0 (A_DELAY(0) | G_DELAY(120))	/* CFG_GPMC_A21_IN */
+			0x1bc (A_DELAY(0) | G_DELAY(120))	/* CFG_GPMC_A22_IN */
+			0x1c8 (A_DELAY(287) | G_DELAY(420))	/* CFG_GPMC_A23_IN */
+			0x1d4 (A_DELAY(144) | G_DELAY(240))	/* CFG_GPMC_A24_IN */
+			0x1e0 (A_DELAY(0) | G_DELAY(0))		/* CFG_GPMC_A25_IN */
+			0x1ec (A_DELAY(120) | G_DELAY(0))	/* CFG_GPMC_A26_IN */
+			0x1f8 (A_DELAY(120) | G_DELAY(180))	/* CFG_GPMC_A27_IN */
+			0x360 (A_DELAY(0) | G_DELAY(0))		/* CFG_GPMC_CS1_IN */
+		>;
+	};
+};
+
+Usage in conjunction with pinctrl single:
+
+For a complete description of the pins both the regular muxing as well as the
+iodelay configuration is necessary. For example:
+
+&dra7_pmx_core {
+	mmc2_pins_default: mmc2_pins_default {
+		pinctrl-single,pins = <
+			0x9c (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a23.mmc2_clk */
+			0xb0 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
+			0xa0 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
+			0xa4 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
+			0xa8 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
+			0xac (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
+			0x8c (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
+			0x90 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
+			0x94 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
+			0x98 (PIN_INPUT_PULLUP | MANUAL_MODE | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
+		>;
+	};
+};
+
+&dra7_iodelay_core {
+	mmc2_iodelay_3v3_conf: mmc2_iodelay_3v3_conf {
+		pinctrl-single,pins = <
+			0x18c (A_DELAY(0) | G_DELAY(120))	/* CFG_GPMC_A19_IN */
+			0x1a4 (A_DELAY(265) | G_DELAY(360))	/* CFG_GPMC_A20_IN */
+			0x1b0 (A_DELAY(0) | G_DELAY(120))	/* CFG_GPMC_A21_IN */
+			0x1bc (A_DELAY(0) | G_DELAY(120))	/* CFG_GPMC_A22_IN */
+			0x1c8 (A_DELAY(287) | G_DELAY(420))	/* CFG_GPMC_A23_IN */
+			0x1d4 (A_DELAY(144) | G_DELAY(240))	/* CFG_GPMC_A24_IN */
+			0x1e0 (A_DELAY(0) | G_DELAY(0))		/* CFG_GPMC_A25_IN */
+			0x1ec (A_DELAY(120) | G_DELAY(0))	/* CFG_GPMC_A26_IN */
+			0x1f8 (A_DELAY(120) | G_DELAY(180))	/* CFG_GPMC_A27_IN */
+			0x360 (A_DELAY(0) | G_DELAY(0))		/* CFG_GPMC_CS1_IN */
+		>;
+	};
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_pins_default &mmc2_iodelay_3v3_conf>;
+};
diff --git b/Documentation/devicetree/bindings/usb/generic-onboard-device.txt b/Documentation/devicetree/bindings/usb/generic-onboard-device.txt
new file mode 100644
index 0000000..4dd7bca
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/generic-onboard-device.txt
@@ -0,0 +1,31 @@
+Generic Onboard USB Device
+
+The node should be located at USB host controller's node or
+any USB HUB's node.
+
+Required properties:
+- compatible: should be "generic-onboard-device"
+
+Optional properties:
+- clocks: the input clock for USB device.
+- clock-frequency: the frequency for device's clock.
+- reset-gpios: Should specify the GPIO for reset.
+- reset-duration-us: the duration for assert reset signal, the time unit
+  is microsecond.
+
+Example:
+
+&usbh1 {
+	vbus-supply = <&reg_usb_h1_vbus>;
+        status = "okay";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+	hub: usb2415@01 {
+	       compatible = "generic-onboard-device";
+	       reg = <0x01>;
+	       clocks = <&clks IMX6QDL_CLK_CKO>;
+	       reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
+	       reset-duration-us = <10>;
+	};
+};
diff --git b/Documentation/devicetree/configfs-overlays.txt b/Documentation/devicetree/configfs-overlays.txt
new file mode 100644
index 0000000..5fa43e0
--- /dev/null
+++ b/Documentation/devicetree/configfs-overlays.txt
@@ -0,0 +1,31 @@
+Howto use the configfs overlay interface.
+
+A device-tree configfs entry is created in /config/device-tree/overlays
+and and it is manipulated using standard file system I/O.
+Note that this is a debug level interface, for use by developers and
+not necessarily something accessed by normal users due to the
+security implications of having direct access to the kernel's device tree.
+
+* To create an overlay you mkdir the directory:
+
+	# mkdir /config/device-tree/overlays/foo
+
+* Either you echo the overlay firmware file to the path property file.
+
+	# echo foo.dtbo >/config/device-tree/overlays/foo/path
+
+* Or you cat the contents of the overlay to the dtbo file
+
+	# cat foo.dtbo >/config/device-tree/overlays/foo/dtbo
+
+The overlay file will be applied, and devices will be created/destroyed
+as required.
+
+To remove it simply rmdir the directory.
+
+	# rmdir /config/device-tree/overlays/foo
+
+The rationalle of the dual interface (firmware & direct copy) is that each is
+better suited to different use patterns. The firmware interface is what's
+intended to be used by hardware managers in the kernel, while the copy interface
+make sense for developers (since it avoids problems with namespaces).
diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
index d418a6c..00ede57 100644
--- a/Documentation/devicetree/overlay-notes.txt
+++ b/Documentation/devicetree/overlay-notes.txt
@@ -100,6 +100,14 @@ Finally, if you need to remove all overlays in one-go, just call
 of_overlay_destroy_all() which will remove every single one in the correct
 order.
 
+If your board has multiple slots/places where a single overlay can work
+and each slot is defined by a node, you can use the of_overlay_create_indirect()
+method to select the target.
+
+For overlays on probeable busses, use the of_overlay_create_target_root() method
+in which you supply a device node as a target root, and which all target
+references in the overlay are performed relative to that node.
+
 Overlay DTS Format
 ------------------
 
@@ -113,6 +121,11 @@ The DTS of an overlay should have the following format:
 		target=<phandle>;	/* phandle target of the overlay */
 	or
 		target-path="/path";	/* target path of the overlay */
+	or
+		target-indirect {	/* indirect target selector */
+			foo { target|target-path ... };
+			bar { .... };
+		};
 
 		__overlay__ {
 			property-a;	/* add property-a to the target */
@@ -131,3 +144,11 @@ Using the non-phandle based target method allows one to use a base DT which does
 not contain a __symbols__ node, i.e. it was not compiled with the -@ option.
 The __symbols__ node is only required for the target=<phandle> method, since it
 contains the information required to map from a phandle to a tree location.
+
+The indirect target requires the use of a selector target on the call to
+of_overlay_create_indirect(). I.e. passing the "foo" id will select the target
+in the foo node, "bar" in bar node, etc.
+
+Note that when using the target root create method all target references must
+lie under the target root node. I.e. the overlay is not allowed to 'break' out
+of the root.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 0b3de80..cc8d434 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -90,6 +90,7 @@ parameter is applicable:
 	NET	Appropriate network support is enabled.
 	NUMA	NUMA support is enabled.
 	NFS	Appropriate NFS support is enabled.
+	OF	Open Firmware support (device tree) is enabled.
 	OSS	OSS sound support is enabled.
 	PV_OPS	A paravirtualized kernel is enabled.
 	PARIDE	The ParIDE (parallel port IDE) subsystem is enabled.
@@ -2715,6 +2716,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			This can be set from sysctl after boot.
 			See Documentation/sysctl/vm.txt for details.
 
+	of_overlay_disable	[OF] Disable device tree overlays at boot time.
+
 	ohci1394_dma=early	[HW] enable debugging via the ohci1394 driver.
 			See Documentation/debugging-via-ohci1394.txt for more
 			info.
diff --git b/Documentation/misc-devices/bone_capemgr.txt b/Documentation/misc-devices/bone_capemgr.txt
new file mode 100644
index 0000000..2a8c766
--- /dev/null
+++ b/Documentation/misc-devices/bone_capemgr.txt
@@ -0,0 +1,63 @@
+---------------------------
+  Beaglebone Cape-Manager
+---------------------------
+
+The beaglebone cape manager driver allows the automatic use of external
+peripheral capes to be automatically supported by Linux without any manual
+setup required by the user.
+
+Each beaglebone cape should contain an EEPROM that describes
+it in a fixed I2C address on the i2c2 bus of the baseboard.
+The format of the EEPROM is defined in the beaglebone reference
+manual at:
+http://beagleboard.org/static/beaglebone/latest/Docs/Hardware/BONE_SRM.pdf
+
+Reading the part number and revision information the manager
+requests a firmware file formatted as a device tree overlay blob.
+
+Applying the overlay the devices are instantiated and the cape is
+ready to be used.
+
+For instance if the part-number is BB-BONE-SERL-03 and the version is 00A1
+the firmware file requested will be BB-BONE-SERL-03-00A1-00A1.dtbo
+It will be located by the in-kernel firmware
+loader in the usual place, i.e.  /lib/firmware/`uname -r`, /lib/firmware etc.
+
+The driver supports the following parameters (either as part of the kernel
+command line or supplied at module insertion time).
+
+disable_partno:   A comma delimited list of PART-NUMBER[:REV] of
+                  disabled capes.
+enable_partno:    A comma delimited list of PART-NUMBER[:REV[:PRIO]] of
+                  enabled capes.
+boot_scan_period: The boot scan period in ms. When the cape manager is built-in
+                  the kernel image, the firmware loader cannot find the files
+		  before the rootfs is mounted. This parameter controls the
+		  period with which the boot state is checked in that case.
+
+There's a sysfs control interface which is defined at the ABI documentation
+area.
+
+Theory of operation:
+--------------------
+
+On driver probe the I2C EEPROM of the baseboard is read and information about
+the current baseboard is retrieved. This information includes the mapping from
+baseboard board name to DT friendly compatible string. I.e. the "A335BONE" board
+name from EEPROM is mapped to the "ti,beaglebone" compatible string which should
+be present in the dtbo to be loaded.
+
+Afterwards the EEPROMs declared in each slot are probed, and the EEPROMs found
+are decoded keeping track the cape part-number and version data.
+
+Using the part-number and version a firmware file is requested (the firmware
+file requested is <part-number>-<version>.dtbo).
+
+The dtbo is unflattend and the resulting device tree is matched against a
+compatible baseboard, and in case of multiple parallel loading capes the
+priorities defined are honored.  That means that when there are multiple capes
+being loaded in parallel the ones with the lowest priority number are loaded
+first.
+
+Applying the device tree overlay makes the cape operational, as if it was part
+of the kernel's booting device tree.
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index 5962949..d1ba882 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -324,10 +324,49 @@ Network device features:
 
 	Passed by reference.
 
+Command from struct task_struct
+
+	%pT	ls
+
+	For printing executable name excluding path from struct
+	task_struct.
+
+	Passed by reference.
+
+Device tree nodes:
+
+	%pO[fnpPcCFr]
+
+	For printing device tree nodes. The optional arguments are:
+            f device node full_name
+            n device node name
+            p device node phandle
+            P device node path spec (name + @unit)
+            F device node flags
+            c major compatible string
+            C full compatible string
+            r node reference count
+	Without any arguments prints full_name (same as %pOf)
+	The separator when using multiple arguments is '|'
+
+	Examples:
+
+	%pO	/foo/bar@0			- Node full name
+	%pOf	/foo/bar@0			- Same as above
+	%pOfp	/foo/bar@0|10			- Node full name + phandle
+	%pOfcF	/foo/bar@0|foo,device|--P-	- Node full name +
+	                                          major compatible string +
+						  node flags
+							D - dynamic
+							d - detached
+							P - Populated
+							B - Populated bus
+
+	Passed by reference
+
 If you add other %p extensions, please extend lib/test_printf.c with
 one or more test cases, if at all feasible.
 
-
 Thank you for your cooperation and attention.
 
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 9c567a4..159fe4b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2231,6 +2231,14 @@ W:	https://linuxtv.org
 S:	Supported
 F:	drivers/media/platform/sti/bdisp
 
+BEAGLEBONE CAPEMANAGER
+M:	Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+S:	Maintained
+F:	drivers/misc/beaglebone-capemgr.c
+F:	Documentation/misc-devices/bone_capemgr.txt
+F:	Documentation/devicetree/bindings/misc/bone_capemgr.txt
+F:	Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr
+
 BEFS FILE SYSTEM
 S:	Orphan
 F:	Documentation/filesystems/befs.txt
@@ -11606,6 +11614,13 @@ S:	Maintained
 F:	Documentation/usb/ohci.txt
 F:	drivers/usb/host/ohci*
 
+USB Generic Onboard Device Driver
+M:	Peter Chen <Peter.Chen@freescale.com>
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
+L:	linux-usb@vger.kernel.org
+S:	Maintained
+F:	drivers/usb/misc/generic_onboard_device.c
+
 USB OTG FSM (Finite State Machine)
 M:	Peter Chen <Peter.Chen@nxp.com>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index 48fab15..88bd756 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -27,6 +27,10 @@ export ZRELADDR INITRD_PHYS PARAMS_PHYS
 
 targets := Image zImage xipImage bootpImage uImage
 
+ifeq ($(CONFIG_OF_OVERLAY),y)
+DTC_FLAGS += -@
+endif
+
 ifeq ($(CONFIG_XIP_KERNEL),y)
 
 $(obj)/xipImage: vmlinux FORCE
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 95c1923..2cd8f0f 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -1,5 +1,9 @@
 ifeq ($(CONFIG_OF),y)
 
+ifeq ($(CONFIG_OF_OVERLAY),y)
+DTC_FLAGS += -@
+endif
+
 dtb-$(CONFIG_ARCH_ALPINE) += \
 	alpine-db.dtb
 dtb-$(CONFIG_MACH_ARTPEC6) += \
@@ -112,6 +116,7 @@ dtb-$(CONFIG_ARCH_DIGICOLOR) += \
 dtb-$(CONFIG_ARCH_EFM32) += \
 	efm32gg-dk3750.dtb
 dtb-$(CONFIG_ARCH_EXYNOS3) += \
+	exynos3250-artik5-eval.dtb \
 	exynos3250-monk.dtb \
 	exynos3250-rinato.dtb
 dtb-$(CONFIG_ARCH_EXYNOS4) += \
@@ -319,6 +324,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
 	imx6dl-sabreauto.dtb \
 	imx6dl-sabrelite.dtb \
 	imx6dl-sabresd.dtb \
+	imx6dl-sabresd-wl1835.dtb \
 	imx6dl-tx6dl-comtft.dtb \
 	imx6dl-tx6u-801x.dtb \
 	imx6dl-tx6u-811x.dtb \
@@ -332,6 +338,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
 	imx6q-b650v3.dtb \
 	imx6q-b850v3.dtb \
 	imx6q-cm-fx6.dtb \
+	imx6q-ccimx6sbc.dtb \
 	imx6q-cubox-i.dtb \
 	imx6q-dfi-fs700-m60.dtb \
 	imx6q-dmo-edmqmx6.dtb \
@@ -354,6 +361,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
 	imx6q-sabreauto.dtb \
 	imx6q-sabrelite.dtb \
 	imx6q-sabresd.dtb \
+	imx6q-sabresd-wl1835.dtb \
 	imx6q-sbc6x.dtb \
 	imx6q-tbs2910.dtb \
 	imx6q-tx6q-1010.dtb \
@@ -368,13 +376,15 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
 	imx6qp-sabresd.dtb
 dtb-$(CONFIG_SOC_IMX6SL) += \
 	imx6sl-evk.dtb \
+	imx6sl-evk-wl1835.dtb \
 	imx6sl-warp.dtb
 dtb-$(CONFIG_SOC_IMX6SX) += \
 	imx6sx-sabreauto.dtb \
 	imx6sx-sdb-reva.dtb \
 	imx6sx-sdb.dtb
 dtb-$(CONFIG_SOC_IMX6UL) += \
-	imx6ul-14x14-evk.dtb
+	imx6ul-14x14-evk.dtb \
+	imx6ul-14x14-evk-ism43362-b81-evb.dtb
 dtb-$(CONFIG_SOC_IMX7D) += \
 	imx7d-cl-som-imx7.dtb \
 	imx7d-sbc-imx7.dtb \
@@ -489,6 +499,22 @@ dtb-$(CONFIG_SOC_AM33XX) += \
 	am335x-base0033.dtb \
 	am335x-bone.dtb \
 	am335x-boneblack.dtb \
+	am335x-sancloud-bbe.dtb \
+	am335x-boneblack-bbb-exp-r.dtb \
+	am335x-boneblack-bbb-exp-c.dtb \
+	am335x-boneblack-bbbmini.dtb \
+	am335x-boneblack-wl1835mod.dtb \
+	am335x-boneblack-cape-bone-argus.dtb \
+	am335x-bone-cape-bone-argus.dtb \
+	am335x-arduino-tre.dtb \
+	am335x-bonegreen-wireless.dtb \
+	am335x-olimex-som.dtb \
+	am335x-abbbi.dtb \
+	am335x-bonegreen-overlay.dtb \
+	am335x-boneblack-overlay.dtb \
+	am335x-boneblack-nhdmi-overlay.dtb \
+	am335x-boneblack-hdmi-overlay.dtb \
+	am335x-boneblack-emmc-overlay.dtb \
 	am335x-bonegreen.dtb \
 	am335x-chiliboard.dtb \
 	am335x-cm-t335.dtb \
@@ -506,6 +532,7 @@ dtb-$(CONFIG_ARCH_OMAP4) += \
 	omap4-panda.dtb \
 	omap4-panda-a4.dtb \
 	omap4-panda-es.dtb \
+	omap4-panda-es-b3.dtb \
 	omap4-sdp.dtb \
 	omap4-sdp-es23plus.dtb \
 	omap4-var-dvk-om44.dtb \
diff --git b/arch/arm/boot/dts/am335x-abbbi.dts b/arch/arm/boot/dts/am335x-abbbi.dts
new file mode 100644
index 0000000..5fa9349
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-abbbi.dts
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright 2015 Konsulko Group
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
+
+/ {
+	model = "Arrow BeagleBone Black Industrial";
+	compatible = "arrow,am335x-abbbi", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+	vmmc-supply = <&vmmcsd_fixed>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_pins>;
+	bus-width = <8>;
+	status = "okay";
+};
+
+&am33xx_pinmux {
+	adi_hdmi_bbbi_pins: adi_hdmi_bbbi_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+			AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data0.lcd_data0 */
+			AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data1.lcd_data1 */
+			AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data2.lcd_data2 */
+			AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)		/* lcd_data3.lcd_data3 */
+			AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data4.lcd_data4 */
+			AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data5.lcd_data5 */
+			AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data6.lcd_data6 */
+			AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data7.lcd_data7 */
+			AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data8.lcd_data8 */
+			AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data9.lcd_data9 */
+			AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data10.lcd_data10 */
+			AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data11.lcd_data11 */
+			AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data12.lcd_data12 */
+			AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data13.lcd_data13 */
+			AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data14.lcd_data14 */
+			AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data15.lcd_data15 */
+			AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_vsync.lcd_vsync */
+			AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_hsync.lcd_hsync */
+			AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_pclk.lcd_pclk */
+			AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_ac_bias_en.lcd_ac_bias_en */
+		>;
+	};
+	adi_hdmi_bbbi_off_pins: adi_hdmi_bbbi_off_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+		>;
+	};
+
+	mcasp0_pins: mcasp0_pins {
+		pinctrl-single,pins = <
+			0x1ac (PIN_INPUT_PULLUP | MUX_MODE0)	/* mcasp0_ahclkx.mcasp0_ahclkx */
+			0x19c (PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mcasp0_ahclkr.mcasp0_axr2 */
+			0x194 (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* mcasp0_fsx.mcasp0_fsx */
+			0x190 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mcasp0_aclkx.mcasp0_aclkx */
+			0x06c (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_a11.GPIO1_27 */
+		>;
+	};
+
+	mcasp0_pins_sleep: mcasp0_pins_sleep {
+		pinctrl-single,pins = <
+			0x1ac (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* mcasp0_ahclkx.mcasp0_ahclkx */
+			0x19c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* mcasp0_ahclkr.mcasp0_axr2 */
+			0x194 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* mcasp0_fsx.mcasp0_fsx */
+			0x190 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* mcasp0_aclkx.mcasp0_aclkx */
+			0x06c (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* gpmc_a11.GPIO1_27 */
+		>;
+	};
+};
+
+&lcdc {
+	status = "okay";
+	port {
+		lcdc_0: endpoint@0 {
+			remote-endpoint = <&hdmi_0>;
+		};
+	};
+};
+
+&i2c0 {
+	adv7511w {
+		compatible = "adi,adv7511w";
+		reg = <0x39>;
+		pinctrl-names = "default", "off";
+		pinctrl-0 = <&adi_hdmi_bbbi_pins>;
+		pinctrl-1 = <&adi_hdmi_bbbi_off_pins>;
+
+		port {
+			hdmi_0: endpoint@0 {
+				remote-endpoint = <&lcdc_0>;
+			};
+		};
+	};
+};
+
+&mcasp0	{
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&mcasp0_pins>;
+	pinctrl-1 = <&mcasp0_pins_sleep>;
+	status = "okay";
+	op-mode = <0>;	/* MCASP_IIS_MODE */
+	tdm-slots = <2>;
+	serial-dir = <	/* 0: INACTIVE, 1: TX, 2: RX */
+			0 0 1 0
+		>;
+	tx-num-evt = <1>;
+	rx-num-evt = <1>;
+};
+
+/ {
+	clk_mcasp0_fixed: clk_mcasp0_fixed {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <24576000>;
+	};
+
+	clk_mcasp0: clk_mcasp0 {
+		#clock-cells = <0>;
+		compatible = "gpio-gate-clock";
+		clocks = <&clk_mcasp0_fixed>;
+		enable-gpios = <&gpio1 27 0>; /* BeagleBone Black Clk enable on GPIO1_27 */
+	};
+
+	hdmi_audio: hdmi_audio@0 {
+		compatible = "linux,hdmi-audio";
+		status = "okay";
+	};
+
+	sound {
+		compatible = "ti,beaglebone-black-audio";
+		ti,model = "TI BeagleBone Black";
+		ti,audio-codec = <&hdmi_audio>;
+		ti,mcasp-controller = <&mcasp0>;
+		ti,audio-routing =
+			"HDMI Out",	"TX";
+		clocks = <&clk_mcasp0>;
+		clock-names = "mclk";
+	};
+};
+
+&rtc {
+	system-power-controller;
+};
diff --git b/arch/arm/boot/dts/am335x-arduino-tre.dts b/arch/arm/boot/dts/am335x-arduino-tre.dts
new file mode 100644
index 0000000..0e6b364
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-arduino-tre.dts
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+
+/ {
+	model = "TI AM335x Arduino Tre";
+	compatible = "ti,am335x-arduino-tre", "ti,am335x-boneblack", "ti,am335x-bone", "ti,am33xx";
+
+	cpus {
+		cpu@0 {
+			cpu0-supply = <&dcdc2_reg>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x10000000>; /* 512 MB */
+	};
+
+	leds {
+		pinctrl-names = "default";
+		pinctrl-0 = <&userled_pins>;
+
+		compatible = "gpio-leds";
+
+		led@0 {
+			label = "arduino_tre:yel:usr0";
+			gpios = <&gpio1 21 0>;
+			linux,default-trigger = "mmc0";
+			default-state = "off";
+		};
+
+		led@1 {
+			label = "arduino_tre:red:usr1";
+			gpios = <&gpio1 22 0>;
+			linux,default-trigger = "none";
+			default-state = "off";
+		};
+
+		led@2 {
+			label = "arduino_tre:blu:usr2";
+			gpios = <&gpio1 23 0>;
+			linux,default-trigger = "none";
+			default-state = "off";
+		};
+
+		led@3 {
+			label = "arduino_tre:grn:usr3";
+			gpios = <&gpio1 24 0>;
+			linux,default-trigger = "cpu0";
+			default-state = "off";
+		};
+	};
+
+	hdmi {
+		compatible = "ti,tilcdc,slave";
+		i2c = <&i2c0>;
+		pinctrl-names = "default", "off";
+		pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
+		pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
+		status = "okay";
+	};
+
+	sound {
+		compatible = "ti,da830-evm-audio";
+		ti,model = "DA830 EVM";
+		ti,audio-codec = <&tlv320aic3x>;
+		ti,mcasp-controller = <&mcasp0>;
+		ti,codec-clock-rate = <12000000>;
+		ti,audio-routing =
+			"Headphone Jack",       "HPLOUT",
+			"Headphone Jack",       "HPROUT",
+			"LINE2L",               "Line In",
+			"LINE2R",               "Line In";
+	};
+
+	vmmcsd_fixed: fixedregulator@0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vmmcsd_fixed";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+};
+
+&am33xx_pinmux {
+	pinctrl-names = "default";
+	pinctrl-0 = <&userled_pins>;
+
+	userled_pins: pinmux_userled_pins {
+		pinctrl-single,pins = <
+			0x54 0x7        /* gpmc_a5.gpio1_21, OUTPUT	  | MODE7 */
+			0x58 0x17       /* gpmc_a6.gpio1_22, OUTPUT_PULLUP | MODE7 */
+			0x5c 0x7        /* gpmc_a7.gpio1_23, OUTPUT	  | MODE7 */
+			0x60 0x17       /* gpmc_a8.gpio1_24, OUTPUT_PULLUP | MODE7 */
+		>;
+	};
+
+	can_bus_pins: pinmux_can_bus_pins {
+		pinctrl-single,pins = <
+			0x120 0x31	/* DCAN0_RX	MODE1 */
+			0x11c 0x01	/* DCAN0_TX	MODE1 */
+		>;
+	};
+
+	cpsw_default: cpsw_default {
+		pinctrl-single,pins = <
+			/* Slave 1 */
+			0x110 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxerr.mii1_rxerr */
+			0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txen.mii1_txen */
+			0x118 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxdv.mii1_rxdv */
+			0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd3.mii1_txd3 */
+			0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd2.mii1_txd2 */
+			0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd1.mii1_txd1 */
+			0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd0.mii1_txd0 */
+			0x12c (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_txclk.mii1_txclk */
+			0x130 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxclk.mii1_rxclk */
+			0x134 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd3.mii1_rxd3 */
+			0x138 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd2.mii1_rxd2 */
+			0x13c (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd1.mii1_rxd1 */
+			0x140 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd0.mii1_rxd0 */
+		>;
+	};
+
+	cpsw_sleep: cpsw_sleep {
+		pinctrl-single,pins = <
+			/* Slave 1 reset value */
+			0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	emac_rmii1_pins: pinmux_emac_rmii1_pins {
+		pinctrl-single,pins = <
+			0x10c (PIN_INPUT_PULLDOWN | MUX_MODE1)	/* mii1_crs.rmii1_crs_dv */
+			0x110 (PIN_INPUT_PULLDOWN | MUX_MODE1)	/* mii1_rxerr.rmii1_rxerr */
+			0x114 (PIN_OUTPUT | MUX_MODE1)		/* mii1_txen.rmii1_txen */
+			0x124 (PIN_OUTPUT | MUX_MODE1)		/* mii1_txd1.rmii1_txd1 */
+			0x128 (PIN_OUTPUT | MUX_MODE1)		/* mii1_txd0.rmii1_txd0 */
+			0x13c (PIN_INPUT_PULLDOWN | MUX_MODE1)	/* mii1_rxd1.rmii1_rxd1 */
+			0x140 (PIN_INPUT_PULLDOWN | MUX_MODE1)	/* mii1_rxd0.rmii1_rxd0 */
+			0x144 (PIN_INPUT_PULLDOWN | MUX_MODE0)	/* rmii1_refclk.rmii1_refclk */
+		>;
+	};
+
+	davinci_mdio_default: davinci_mdio_default {
+		pinctrl-single,pins = <
+			/* MDIO */
+			0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
+			0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0)			/* mdio_clk.mdio_clk */
+		>;
+	};
+
+	davinci_mdio_sleep: davinci_mdio_sleep {
+		pinctrl-single,pins = <
+			/* MDIO reset value */
+			0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	i2c0_pins: pinmux_i2c0_pins {
+		pinctrl-single,pins = <
+			0x188 0x70      /* i2c0_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
+			0x18c 0x70      /* i2c0_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE0 */
+		>;
+	};
+
+	i2c1_pins: pinmux_i2c1_pins {
+		pinctrl-single,pins = <
+			0x158 0x72 	/*spi0_d1-i2c1_sda,SLEWCTRL_SLOW | INPUT_PULLUP | MODE2*/
+			0x15c 0x72	/*spi0_cs0-i2c1_scl,SLEWCTRL_SLOW | INPUT_PULLUP |MODE2*/
+		>;
+	};
+
+	i2c2_pins: pinmux_i2c2_pins {
+		pinctrl-single,pins = <
+			0x150 0x72 	/*spi0_scl.i2c2_sda,SLEWCTRL_SLOW | INPUT_PULLUP |MODE2*/
+			0x154 0x72	/*spi0_d0.i2c2_scl,SLEWCTRL_SLOW | INPUT_PULLUP | MODE2*/
+		>;
+	};
+
+	mmc1_pins_default: pinmux_mmc1_pins {
+		pinctrl-single,pins = <
+			0x0F0 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat3.mmc0_dat3 */
+			0x0F4 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat2.mmc0_dat2 */
+			0x0F8 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat1.mmc0_dat1 */
+			0x0FC (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat0.mmc0_dat0 */
+			0x100 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_clk.mmc0_clk */
+			0x104 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_cmd.mmc0_cmd */
+			0x1A0 (PIN_INPUT_PULLUP | MUX_MODE7)	/* mcasp0_aclkr.gpio3_18 */
+			0x160 (PIN_INPUT | MUX_MODE7)		/* spi0_cs1.gpio0_6 */
+		>;
+	};
+
+	mmc1_pins_sleep: pinmux_mmc1_pins_sleep {
+		pinctrl-single,pins = <
+			0x0F0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x0F4 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x0F8 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x0FC (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x100 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x104 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x1A0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	tre_ehrpwm1_pins: pinmux_tre_ehrpwm1_pins {
+		pinctrl-single,pins = <
+			0x48 0x06	/* PWM1A	~102	MODE6 */
+			0x4c 0x06	/* PWM1B	~103	MODE6 */
+		>;
+	};
+
+	tre_ehrpwm2_pins: pinmux_tre_ehrpwm2_pins {
+		pinctrl-single,pins = <
+			0x20 0x04	/* PWM2A	~100	MODE4 */
+			0x24 0x04	/* PWM2B	~101	MODE4 */
+		>;
+	};
+
+	nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
+		pinctrl-single,pins = <
+			0x1b0 0x03      /* xdma_event_intr0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT */
+			0xa0 0x08       /* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xa4 0x08       /* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xa8 0x08       /* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xac 0x08       /* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xb0 0x08       /* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xb4 0x08       /* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xb8 0x08       /* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xbc 0x08       /* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xc0 0x08       /* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xc4 0x08       /* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xc8 0x08       /* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xcc 0x08       /* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xd0 0x08       /* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xd4 0x08       /* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xd8 0x08       /* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xdc 0x08       /* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xe0 0x00       /* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+			0xe4 0x00       /* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+			0xe8 0x00       /* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+			0xec 0x00       /* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+		>;
+	};
+
+	nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
+		pinctrl-single,pins = <
+			0x1b0 0x03      /* xdma_event_intr0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT */
+		>;
+	};
+
+	tre_audio_pins: pinmux_tre_audio_pins {
+		pinctrl-single,pins = <
+			0x1ac 0x00	/*mcasp0_ahclkx       (AUD_MCLK)->12MHz, INPUT | MODE0*/
+			0x190 0x20	/* mcasp0_aclkx        (AUD_BCLK)->, 	 INPUT | MODE0*/
+			0x194 0x20	/* mcasp0_fsx          (AUD_FSX)-> , 	 INPUT | MODE0*/
+			0x198 0x20	/* mcasp0_axr0         (AUD_DIN)<-, 	 INPUT | MODE0*/
+			0x19c 0x22	/* mcasp0_ahclkr-_axr2 (AUD_DOUT)->, 	       | MODE2*/
+		>;
+	};
+
+	spi1_pins: pinmux_spi1_pins {
+		pinctrl-single,pins = <
+			0x168 0x14 	/* MOSI1 OUTPUT_PULLUP | MODE0 */
+			0x16c 0x34	/* MISO1 INPUT_PULLUP | MODE0 */
+			0x108 0x12 	/* SCK1	 OUTPUT_PULLUP | MODE0 */
+			0x164 0x12	/* SS1	 OUTPUT_PULLUP | MODE0 */
+		>;
+	};
+
+	uart0_pins: pinmux_uart0_pins {
+		pinctrl-single,pins = <
+			0x170 (PIN_INPUT_PULLUP | MUX_MODE0)	/* uart0_rxd.uart0_rxd */
+			0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart0_txd.uart0_txd */
+		>;
+	};
+
+	uart1_pins: pinmux_uart1_pins {
+		pinctrl-single,pins = <
+			0x180 0x30	/* UART1_rxd PULL_UP | MODE0 */
+			0x184 0x00	/* UART1_txd 	MODE0 */
+		>;
+	};
+
+	uart2_pins: pinmux_uart2_pins {
+		pinctrl-single,pins = <
+			0x12c 0x31	/* UART2_rxd PULL_UP | MODE1 */
+			0x130 0x01	/* UART2_txd 	MODE1 */
+		>;
+	};
+
+	uart4_pins: pinmux_uart4_pins {
+		pinctrl-single,pins = <
+			0x70 0x36	/* UART4_rxd PULL_UP | MODE6 */
+			0x74 0x06	/* UART4_txd 	MODE6 */
+		>;
+	};
+};
+
+&dcan0 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&can_bus_pins>;
+};
+
+&i2c0 {
+	status = "okay";
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+
+	tps: tps@24 {
+		reg = <0x24>;
+	};
+
+	rtc@6f {
+		compatible = "microchip,mcp7941x";
+		reg = <0x6f>;
+	};
+
+	tlv320aic3x: tlv320aic3x@18 {
+		compatible = "ti,tlv320aic3x";
+		reg = <0x18>;
+		status = "okay";
+	};
+};
+
+&i2c1 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+
+	clock-frequency = <100000>;
+};
+
+&i2c2 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+
+	clock-frequency = <100000>;
+};
+
+&epwmss1 {
+	status = "okay";
+};
+
+&ehrpwm1 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&tre_ehrpwm1_pins>;
+};
+
+&epwmss2 {
+	status = "okay";
+};
+
+&ehrpwm2 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&tre_ehrpwm2_pins>;
+};
+
+&lcdc {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins>;
+
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins>;
+
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins>;
+
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+
+	control@44e10620 {
+		status = "okay";
+	};
+
+	usb-phy@47401300 {
+		status = "okay";
+	};
+
+	usb-phy@47401b00 {
+		status = "okay";
+	};
+
+	usb@47401000 {
+		status = "okay";
+		dr_mode = "peripheral";
+	};
+
+	usb@47401800 {
+		status = "okay";
+		dr_mode = "host";
+	};
+
+	dma-controller@47402000  {
+		status = "okay";
+	};
+};
+
+&tps {
+	compatible = "ti,tps65217";
+	ti,pmic-shutdown-controller;
+
+	interrupt-parent = <&intc>;
+	interrupts = <7>;	/* NNMI */
+
+	regulators {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		dcdc1_reg: regulator@0 {
+			reg = <0>;
+			regulator-name = "vdd_ddr";
+			regulator-min-microvolt = <1350000>;
+			regulator-max-microvolt = <1350000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		dcdc2_reg: regulator@1 {
+			reg = <1>;
+			/* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
+			regulator-name = "vdd_mpu";
+			regulator-min-microvolt = <925000>;
+			regulator-max-microvolt = <1325000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		dcdc3_reg: regulator@2 {
+			reg = <2>;
+			/* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
+			regulator-name = "vdd_core";
+			regulator-min-microvolt = <925000>;
+			regulator-max-microvolt = <1150000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		ldo1_reg: regulator@3 {
+			reg = <3>;
+			regulator-always-on;
+		};
+
+		ldo2_reg: regulator@4 {
+			reg = <4>;
+			regulator-always-on;
+		};
+
+		ldo3_reg: regulator@5 {
+			reg = <5>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			regulator-always-on;
+		};
+
+		ldo4_reg: regulator@6 {
+			reg = <6>;
+			regulator-always-on;
+		};
+
+		rtc@44e3e000 {
+			ti,system-power-controller;
+		};
+	};
+};
+
+&mcasp0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&tre_audio_pins>;
+
+	status = "okay";
+
+	op-mode = <0>;          /* MCASP_IIS_MODE */
+	tdm-slots = <2>;
+	num-serializer = <16>;
+	serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
+		2 0 1 0
+		0 0 0 0
+		0 0 0 0
+		0 0 0 0
+	>;
+	tx-num-evt = <1>;
+	rx-num-evt = <1>;
+};
+
+&mac {
+	slaves = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emac_rmii1_pins>;
+	status = "okay";
+};
+
+&davinci_mdio {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&davinci_mdio_default>;
+	pinctrl-1 = <&davinci_mdio_sleep>;
+	status = "okay";
+};
+
+&cpsw_emac0 {
+	phy_id = <&davinci_mdio>, <0>;
+	phy-mode = "rmii";
+};
+
+&phy_sel {
+	rmii-clock-ext;
+};
+
+&mmc1 {
+	status = "okay";
+	bus-width = <0x4>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&mmc1_pins_default>;
+	pinctrl-1 = <&mmc1_pins_sleep>;
+	cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&rtc {
+	system-power-controller;
+};
+
+&sham {
+	status = "okay";
+};
+
+&aes {
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-bone-argus.dtsi b/arch/arm/boot/dts/am335x-bone-argus.dtsi
new file mode 100644
index 0000000..21afad3
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-argus.dtsi
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+
+/ {
+	ocp {
+		P8_07_pinmux {
+			/* gpio2[2] */
+			status = "disabled";
+		};
+		P8_08_pinmux {
+			/* gpio2[3] */
+			status = "disabled";
+		};
+		P8_09_pinmux {
+			/* gpio2[5] */
+			status = "disabled";
+		};
+		P8_10_pinmux {
+			/* gpio2[4] */
+			status = "disabled";
+		};
+		P9_11_pinmux {
+			/* gpio0[30] */
+			status = "disabled";
+		};
+		P9_17_pinmux {
+			/* gpio0[5] */
+			status = "disabled";
+		};
+		P9_18_pinmux {
+			/* gpio0[4] */
+			status = "disabled";
+		};
+		P9_41_pinmux {
+			/* gpio0[20] */
+			status = "disabled";
+		};
+		P9_42_pinmux {
+			/* gpio0[7] */
+			status = "disabled";
+		};
+	};
+};
+
+/ {
+	argus-ups {
+		compatible = "argus-ups";
+		status = "okay";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&argus_ups_pins>; /* Refer to previous label */
+		/* This section communicates the gpio numbers to the driver module */
+		/* Note that gpio controllers appear to be numbered from 1-n here rather than 0-(n-1)????? */
+		gpios = <&gpio0 30 0>,  /* Request */
+			<&gpio0 5 0>,  	/* Acknowledge */
+			<&gpio0 4 0>,   /* Watchdog */
+			<&gpio2 2 0>, 	/* LED 1 Green */
+			<&gpio2 3 0>, 	/* LED 1 Red */
+			<&gpio2 5 0>, 	/* LED 2 Green */
+			<&gpio2 4 0>, 	/* LED 2 Red */
+			<&gpio0 20 0>,	/* General Output #1 */
+			<&gpio0 7 0>;	/* General Output #2 */
+		debug = <1>;
+		shutdown = <1>;
+	};
+};
+
+&am33xx_pinmux {
+	argus_ups_pins: pinmux_argus_ups_pins { /* Set up pinmux */
+		pinctrl-single,pins = <
+			0x070 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_wait0.gpio0_30 */
+			0x15c (PIN_OUTPUT_PULLUP | MUX_MODE7) /* spi0_cs0.gpio0_5 */
+			0x158 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* spi0_d1.gpio0_4 */
+			0x090 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_advn_ale.gpio_2 */
+			0x094 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_oen_ren.gpio2_3 */
+			0x09c (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_ben0_cle.gpio2_5 */
+			0x098 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_gpmc_wen.gpio2_4 */
+			0x1b4 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* xdma_event_intr1.gpio0_20 */
+			0x164 (PIN_OUTPUT_PULLUP | MUX_MODE7) /* ecap0_in_pwm0_out.gpio0_7 */
+		>;
+	};
+
+	i2c2_pins: pinmux_i2c2_pins {
+		pinctrl-single,pins = <
+			BONE_P9_20 0x73 /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) uart1_ctsn.i2c2_sda */
+			BONE_P9_19 0x73 /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) uart1_rtsn.i2c2_scl */
+		>;
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+
+	status = "okay";
+	clock-frequency = <100000>;
+
+	rtc@68 {
+		compatible = "maxim,ds1307";
+		reg = <0x68>;
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-bone-cape-bone-argus.dts b/arch/arm/boot/dts/am335x-bone-cape-bone-argus.dts
new file mode 100644
index 0000000..82218f5
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-cape-bone-argus.dts
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am335x-bone-common-no-capemgr.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone";
+	compatible = "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&ldo3_reg>;
+};
+
+#include "am335x-bone-argus.dtsi"
diff --git b/arch/arm/boot/dts/am335x-bone-common-no-capemgr.dtsi b/arch/arm/boot/dts/am335x-bone-common-no-capemgr.dtsi
new file mode 100644
index 0000000..fa5311f
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-common-no-capemgr.dtsi
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+/ {
+	cpus {
+		cpu@0 {
+			cpu0-supply = <&dcdc2_reg>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x10000000>; /* 256 MB */
+	};
+
+	leds {
+		pinctrl-names = "default";
+		pinctrl-0 = <&user_leds_s0>;
+
+		compatible = "gpio-leds";
+
+		led@2 {
+			label = "beaglebone:green:usr0";
+			gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+			default-state = "off";
+		};
+
+		led@3 {
+			label = "beaglebone:green:usr1";
+			gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "mmc0";
+			default-state = "off";
+		};
+
+		led@4 {
+			label = "beaglebone:green:usr2";
+			gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "cpu0";
+			default-state = "off";
+		};
+
+		led@5 {
+			label = "beaglebone:green:usr3";
+			gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "mmc1";
+			default-state = "off";
+		};
+	};
+
+	vmmcsd_fixed: fixedregulator@0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vmmcsd_fixed";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+};
+
+&am33xx_pinmux {
+	user_leds_s0: user_leds_s0 {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_a5.gpio1_21 */
+			AM33XX_IOPAD(0x858, PIN_OUTPUT_PULLUP | MUX_MODE7)	/* gpmc_a6.gpio1_22 */
+			AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_a7.gpio1_23 */
+			AM33XX_IOPAD(0x860, PIN_OUTPUT_PULLUP | MUX_MODE7)	/* gpmc_a8.gpio1_24 */
+		>;
+	};
+
+	i2c0_pins: pinmux_i2c0_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0)	/* i2c0_sda.i2c0_sda */
+			AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0)	/* i2c0_scl.i2c0_scl */
+		>;
+	};
+
+	i2c2_pins: pinmux_i2c2_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3)	/* uart1_ctsn.i2c2_sda */
+			AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3)	/* uart1_rtsn.i2c2_scl */
+		>;
+	};
+
+	uart0_pins: pinmux_uart0_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0)	/* uart0_rxd.uart0_rxd */
+			AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart0_txd.uart0_txd */
+		>;
+	};
+
+	cpsw_default: cpsw_default {
+		pinctrl-single,pins = <
+			/* Slave 1 */
+			0x108 (PIN_INPUT | MUX_MODE0)		/* mii1_col.mii1_col */
+			0x10c (PIN_INPUT | MUX_MODE0)		/* mii1_crs.mii1_crs */
+			AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxerr.mii1_rxerr */
+			AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txen.mii1_txen */
+			AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxdv.mii1_rxdv */
+			AM33XX_IOPAD(0x91c, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd3.mii1_txd3 */
+			AM33XX_IOPAD(0x920, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd2.mii1_txd2 */
+			AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd1.mii1_txd1 */
+			AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd0.mii1_txd0 */
+			AM33XX_IOPAD(0x92c, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_txclk.mii1_txclk */
+			AM33XX_IOPAD(0x930, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxclk.mii1_rxclk */
+			AM33XX_IOPAD(0x934, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd3.mii1_rxd3 */
+			AM33XX_IOPAD(0x938, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd2.mii1_rxd2 */
+			AM33XX_IOPAD(0x93c, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd1.mii1_rxd1 */
+			AM33XX_IOPAD(0x940, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd0.mii1_rxd0 */
+		>;
+	};
+
+	cpsw_sleep: cpsw_sleep {
+		pinctrl-single,pins = <
+			/* Slave 1 reset value */
+			0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x91c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x920, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x92c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x930, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x934, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x938, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	davinci_mdio_default: davinci_mdio_default {
+		pinctrl-single,pins = <
+			/* MDIO */
+			AM33XX_IOPAD(0x948, PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
+			AM33XX_IOPAD(0x94c, PIN_OUTPUT_PULLUP | MUX_MODE0)			/* mdio_clk.mdio_clk */
+		>;
+	};
+
+	davinci_mdio_sleep: davinci_mdio_sleep {
+		pinctrl-single,pins = <
+			/* MDIO reset value */
+			AM33XX_IOPAD(0x948, PIN_INPUT_PULLDOWN | MUX_MODE7)
+			AM33XX_IOPAD(0x94c, PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	mmc1_pins: pinmux_mmc1_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x960, PIN_INPUT | MUX_MODE7) /* GPIO0_6 */
+		>;
+	};
+
+	emmc_pins: pinmux_emmc_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x880, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+			AM33XX_IOPAD(0x884, PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+			AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+			AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+			AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+			AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+			AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+			AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+			AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+			AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+		>;
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins>;
+
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+};
+
+&usb_ctrl_mod {
+	status = "okay";
+};
+
+&usb0_phy {
+	status = "okay";
+};
+
+&usb1_phy {
+	status = "okay";
+};
+
+&usb0 {
+	status = "okay";
+	dr_mode = "peripheral";
+};
+
+&usb1 {
+	status = "okay";
+	dr_mode = "host";
+};
+
+&cppi41dma  {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+
+	status = "okay";
+	clock-frequency = <400000>;
+
+	tps: tps@24 {
+		reg = <0x24>;
+	};
+
+	baseboard_eeprom: baseboard_eeprom@50 {
+		compatible = "at,24c256";
+		reg = <0x50>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+		baseboard_data: baseboard_data@0 {
+			reg = <0 0x100>;
+		};
+	};
+};
+
+/include/ "tps65217.dtsi"
+
+&tps {
+	/*
+	 * Configure pmic to enter OFF-state instead of SLEEP-state ("RTC-only
+	 * mode") at poweroff.  Most BeagleBone versions do not support RTC-only
+	 * mode and risk hardware damage if this mode is entered.
+	 *
+	 * For details, see linux-omap mailing list May 2015 thread
+	 *	[PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller
+	 * In particular, messages:
+	 *	http://www.spinics.net/lists/linux-omap/msg118585.html
+	 *	http://www.spinics.net/lists/linux-omap/msg118615.html
+	 *
+	 * You can override this later with
+	 *	&tps {  /delete-property/ ti,pmic-shutdown-controller;  }
+	 * if you want to use RTC-only mode and made sure you are not affected
+	 * by the hardware problems. (Tip: double-check by performing a current
+	 * measurement after shutdown: it should be less than 1 mA.)
+	 */
+	ti,pmic-shutdown-controller;
+
+	interrupt-parent = <&intc>;
+	interrupts = <7>;	/* NNMI */
+
+	regulators {
+		dcdc1_reg: regulator@0 {
+			regulator-name = "vdds_dpr";
+			regulator-always-on;
+		};
+
+		dcdc2_reg: regulator@1 {
+			/* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
+			regulator-name = "vdd_mpu";
+			regulator-min-microvolt = <925000>;
+			regulator-max-microvolt = <1325000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		dcdc3_reg: regulator@2 {
+			/* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
+			regulator-name = "vdd_core";
+			regulator-min-microvolt = <925000>;
+			regulator-max-microvolt = <1150000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		ldo1_reg: regulator@3 {
+			regulator-name = "vio,vrtc,vdds";
+			regulator-always-on;
+		};
+
+		ldo2_reg: regulator@4 {
+			regulator-name = "vdd_3v3aux";
+			regulator-always-on;
+		};
+
+		ldo3_reg: regulator@5 {
+			regulator-name = "vdd_1v8";
+			regulator-always-on;
+		};
+
+		ldo4_reg: regulator@6 {
+			regulator-name = "vdd_3v3a";
+			regulator-always-on;
+		};
+	};
+};
+
+&cpsw_emac0 {
+	phy_id = <&davinci_mdio>, <0>;
+	phy-mode = "mii";
+};
+
+&mac {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&cpsw_default>;
+	pinctrl-1 = <&cpsw_sleep>;
+	slaves = <1>;
+	status = "okay";
+};
+
+&davinci_mdio {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&davinci_mdio_default>;
+	pinctrl-1 = <&davinci_mdio_sleep>;
+	status = "okay";
+};
+
+&mmc1 {
+	status = "okay";
+	bus-width = <0x4>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins>;
+	cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
+};
+
+&aes {
+	status = "okay";
+};
+
+&sham {
+	status = "okay";
+};
+
+&rtc {
+	system-power-controller;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-common-universal.dtsi b/arch/arm/boot/dts/am335x-bone-common-universal.dtsi
new file mode 100644
index 0000000..781e33f
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-common-universal.dtsi
@@ -0,0 +1,2052 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&am33xx_pinmux {
+	/************************/
+	/* P8 Header            */
+	/************************/
+
+	/* P8_01                GND     */
+	/* P8_02                GND     */
+	/* P8_03 (ZCZ ball R9 ) emmc    */
+	/* P8_04 (ZCZ ball T9 ) emmc    */
+	/* P8_05 (ZCZ ball R8 ) emmc    */
+	/* P8_06 (ZCZ ball T8 ) emmc    */
+
+	/* P8_07 (ZCZ ball R7 ) */
+	P8_07_default_pin: pinmux_P8_07_default_pin {
+		pinctrl-single,pins = <0x090  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_07_gpio_pin: pinmux_P8_07_gpio_pin {
+		pinctrl-single,pins = <0x090  0x2F>; };     /* Mode 7, RxActive */
+	P8_07_gpio_pu_pin: pinmux_P8_07_gpio_pu_pin {
+		pinctrl-single,pins = <0x090  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_07_gpio_pd_pin: pinmux_P8_07_gpio_pd_pin {
+		pinctrl-single,pins = <0x090  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_07_timer_pin: pinmux_P8_07_timer_pin {
+		pinctrl-single,pins = <0x090  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+
+	/* P8_08 (ZCZ ball T7 ) */
+	P8_08_default_pin: pinmux_P8_08_default_pin {
+		pinctrl-single,pins = <0x094  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_08_gpio_pin: pinmux_P8_08_gpio_pin {
+		pinctrl-single,pins = <0x094  0x2F>; };     /* Mode 7, RxActive */
+	P8_08_gpio_pu_pin: pinmux_P8_08_gpio_pu_pin {
+		pinctrl-single,pins = <0x094  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_08_gpio_pd_pin: pinmux_P8_08_gpio_pd_pin {
+		pinctrl-single,pins = <0x094  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_08_timer_pin: pinmux_P8_08_timer_pin {
+		pinctrl-single,pins = <0x094  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+
+	/* P8_09 (ZCZ ball T6 ) */
+	P8_09_default_pin: pinmux_P8_09_default_pin {
+		pinctrl-single,pins = <0x09c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_09_gpio_pin: pinmux_P8_09_gpio_pin {
+		pinctrl-single,pins = <0x09c  0x2F>; };     /* Mode 7, RxActive */
+	P8_09_gpio_pu_pin: pinmux_P8_09_gpio_pu_pin {
+		pinctrl-single,pins = <0x09c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_09_gpio_pd_pin: pinmux_P8_09_gpio_pd_pin {
+		pinctrl-single,pins = <0x09c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_09_timer_pin: pinmux_P8_09_timer_pin {
+		pinctrl-single,pins = <0x09c  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+
+	/* P8_10 (ZCZ ball U6 ) */
+	P8_10_default_pin: pinmux_P8_10_default_pin {
+		pinctrl-single,pins = <0x098  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_10_gpio_pin: pinmux_P8_10_gpio_pin {
+		pinctrl-single,pins = <0x098  0x2F>; };     /* Mode 7, RxActive */
+	P8_10_gpio_pu_pin: pinmux_P8_10_gpio_pu_pin {
+		pinctrl-single,pins = <0x098  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_10_gpio_pd_pin: pinmux_P8_10_gpio_pd_pin {
+		pinctrl-single,pins = <0x098  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_10_timer_pin: pinmux_P8_10_timer_pin {
+		pinctrl-single,pins = <0x098  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+
+	/* P8_11 (ZCZ ball R12) */
+	P8_11_default_pin: pinmux_P8_11_default_pin {
+		pinctrl-single,pins = <0x034  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_11_gpio_pin: pinmux_P8_11_gpio_pin {
+		pinctrl-single,pins = <0x034  0x2F>; };     /* Mode 7, RxActive */
+	P8_11_gpio_pu_pin: pinmux_P8_11_gpio_pu_pin {
+		pinctrl-single,pins = <0x034  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_11_gpio_pd_pin: pinmux_P8_11_gpio_pd_pin {
+		pinctrl-single,pins = <0x034  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_11_pruout_pin: pinmux_P8_11_pruout_pin {
+		pinctrl-single,pins = <0x034  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_11_qep_pin: pinmux_P8_11_qep_pin {
+		pinctrl-single,pins = <0x034  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+
+	/* P8_12 (ZCZ ball T12) */
+	P8_12_default_pin: pinmux_P8_12_default_pin {
+		pinctrl-single,pins = <0x030  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_12_gpio_pin: pinmux_P8_12_gpio_pin {
+		pinctrl-single,pins = <0x030  0x2F>; };     /* Mode 7, RxActive */
+	P8_12_gpio_pu_pin: pinmux_P8_12_gpio_pu_pin {
+		pinctrl-single,pins = <0x030  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_12_gpio_pd_pin: pinmux_P8_12_gpio_pd_pin {
+		pinctrl-single,pins = <0x030  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_12_pruout_pin: pinmux_P8_12_pruout_pin {
+		pinctrl-single,pins = <0x030  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_12_qep_pin: pinmux_P8_12_qep_pin {
+		pinctrl-single,pins = <0x030  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+
+	/* P8_13 (ZCZ ball T10) */
+	P8_13_default_pin: pinmux_P8_13_default_pin {
+		pinctrl-single,pins = <0x024  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_13_gpio_pin: pinmux_P8_13_gpio_pin {
+		pinctrl-single,pins = <0x024  0x2F>; };     /* Mode 7, RxActive */
+	P8_13_gpio_pu_pin: pinmux_P8_13_gpio_pu_pin {
+		pinctrl-single,pins = <0x024  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_13_gpio_pd_pin: pinmux_P8_13_gpio_pd_pin {
+		pinctrl-single,pins = <0x024  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_13_pwm_pin: pinmux_P8_13_pwm_pin {
+		pinctrl-single,pins = <0x024  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+
+	/* P8_14 (ZCZ ball T11) */
+	P8_14_default_pin: pinmux_P8_14_default_pin {
+		pinctrl-single,pins = <0x028  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_14_gpio_pin: pinmux_P8_14_gpio_pin {
+		pinctrl-single,pins = <0x028  0x2F>; };     /* Mode 7, RxActive */
+	P8_14_gpio_pu_pin: pinmux_P8_14_gpio_pu_pin {
+		pinctrl-single,pins = <0x028  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_14_gpio_pd_pin: pinmux_P8_14_gpio_pd_pin {
+		pinctrl-single,pins = <0x028  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_14_pwm_pin: pinmux_P8_14_pwm_pin {
+		pinctrl-single,pins = <0x028  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+
+	/* P8_15 (ZCZ ball U13) */
+	P8_15_default_pin: pinmux_P8_15_default_pin {
+		pinctrl-single,pins = <0x03c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_15_gpio_pin: pinmux_P8_15_gpio_pin {
+		pinctrl-single,pins = <0x03c  0x2F>; };     /* Mode 7, RxActive */
+	P8_15_gpio_pu_pin: pinmux_P8_15_gpio_pu_pin {
+		pinctrl-single,pins = <0x03c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_15_gpio_pd_pin: pinmux_P8_15_gpio_pd_pin {
+		pinctrl-single,pins = <0x03c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_15_pruin_pin: pinmux_P8_15_pruin_pin {
+		pinctrl-single,pins = <0x03c  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_15_qep_pin: pinmux_P8_15_qep_pin {
+		pinctrl-single,pins = <0x03c  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+
+	/* P8_16 (ZCZ ball V13) */
+	P8_16_default_pin: pinmux_P8_16_default_pin {
+		pinctrl-single,pins = <0x038  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_16_gpio_pin: pinmux_P8_16_gpio_pin {
+		pinctrl-single,pins = <0x038  0x2F>; };     /* Mode 7, RxActive */
+	P8_16_gpio_pu_pin: pinmux_P8_16_gpio_pu_pin {
+		pinctrl-single,pins = <0x038  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_16_gpio_pd_pin: pinmux_P8_16_gpio_pd_pin {
+		pinctrl-single,pins = <0x038  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_16_pruin_pin: pinmux_P8_16_pruin_pin {
+		pinctrl-single,pins = <0x038  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_16_qep_pin: pinmux_P8_16_qep_pin {
+		pinctrl-single,pins = <0x038  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+
+	/* P8_17 (ZCZ ball U12) */
+	P8_17_default_pin: pinmux_P8_17_default_pin {
+		pinctrl-single,pins = <0x02c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_17_gpio_pin: pinmux_P8_17_gpio_pin {
+		pinctrl-single,pins = <0x02c  0x2F>; };     /* Mode 7, RxActive */
+	P8_17_gpio_pu_pin: pinmux_P8_17_gpio_pu_pin {
+		pinctrl-single,pins = <0x02c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_17_gpio_pd_pin: pinmux_P8_17_gpio_pd_pin {
+		pinctrl-single,pins = <0x02c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_17_pwm_pin: pinmux_P8_17_pwm_pin {
+		pinctrl-single,pins = <0x02c  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+
+	/* P8_18 (ZCZ ball V12) */
+	P8_18_default_pin: pinmux_P8_18_default_pin {
+		pinctrl-single,pins = <0x08c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_18_gpio_pin: pinmux_P8_18_gpio_pin {
+		pinctrl-single,pins = <0x08c  0x2F>; };     /* Mode 7, RxActive */
+	P8_18_gpio_pu_pin: pinmux_P8_18_gpio_pu_pin {
+		pinctrl-single,pins = <0x08c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_18_gpio_pd_pin: pinmux_P8_18_gpio_pd_pin {
+		pinctrl-single,pins = <0x08c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+
+	/* P8_19 (ZCZ ball U10) */
+	P8_19_default_pin: pinmux_P8_19_default_pin {
+		pinctrl-single,pins = <0x020  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_19_gpio_pin: pinmux_P8_19_gpio_pin {
+		pinctrl-single,pins = <0x020  0x2F>; };     /* Mode 7, RxActive */
+	P8_19_gpio_pu_pin: pinmux_P8_19_gpio_pu_pin {
+		pinctrl-single,pins = <0x020  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_19_gpio_pd_pin: pinmux_P8_19_gpio_pd_pin {
+		pinctrl-single,pins = <0x020  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_19_pwm_pin: pinmux_P8_19_pwm_pin {
+		pinctrl-single,pins = <0x020  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+
+	/* P8_20 (ZCZ ball V9 ) emmc    */
+	/* P8_21 (ZCZ ball U9 ) emmc    */
+	/* P8_22 (ZCZ ball V8 ) emmc    */
+	/* P8_23 (ZCZ ball U8 ) emmc    */
+	/* P8_24 (ZCZ ball V7 ) emmc    */
+	/* P8_25 (ZCZ ball U7 ) emmc    */
+
+	/* P8_26 (ZCZ ball V6 ) */
+	P8_26_default_pin: pinmux_P8_26_default_pin {
+		pinctrl-single,pins = <0x07c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_26_gpio_pin: pinmux_P8_26_gpio_pin {
+		pinctrl-single,pins = <0x07c  0x2F>; };     /* Mode 7, RxActive */
+	P8_26_gpio_pu_pin: pinmux_P8_26_gpio_pu_pin {
+		pinctrl-single,pins = <0x07c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_26_gpio_pd_pin: pinmux_P8_26_gpio_pd_pin {
+		pinctrl-single,pins = <0x07c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+
+	/* P8_27 (ZCZ ball U5 ) hdmi    */
+	P8_27_default_pin: pinmux_P8_27_default_pin {
+		pinctrl-single,pins = <0x0e0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_27_gpio_pin: pinmux_P8_27_gpio_pin {
+		pinctrl-single,pins = <0x0e0  0x2F>; };     /* Mode 7, RxActive */
+	P8_27_gpio_pu_pin: pinmux_P8_27_gpio_pu_pin {
+		pinctrl-single,pins = <0x0e0  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_27_gpio_pd_pin: pinmux_P8_27_gpio_pd_pin {
+		pinctrl-single,pins = <0x0e0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_27_pruout_pin: pinmux_P8_27_pruout_pin {
+		pinctrl-single,pins = <0x0e0  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_27_pruin_pin: pinmux_P8_27_pruin_pin {
+		pinctrl-single,pins = <0x0e0  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_27_hdmi_pin: pinmux_P8_27_hdmi_pin {
+		pinctrl-single,pins = <0x0e0  0x00>; };     /* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+
+	/* P8_28 (ZCZ ball V5 ) hdmi    */
+	P8_28_default_pin: pinmux_P8_28_default_pin {
+		pinctrl-single,pins = <0x0e8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_28_gpio_pin: pinmux_P8_28_gpio_pin {
+		pinctrl-single,pins = <0x0e8  0x2F>; };     /* Mode 7, RxActive */
+	P8_28_gpio_pu_pin: pinmux_P8_28_gpio_pu_pin {
+		pinctrl-single,pins = <0x0e8  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_28_gpio_pd_pin: pinmux_P8_28_gpio_pd_pin {
+		pinctrl-single,pins = <0x0e8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_28_pruout_pin: pinmux_P8_28_pruout_pin {
+		pinctrl-single,pins = <0x0e8  0x05>; };     /* Mode 5, Pull-Down */
+	P8_28_pruin_pin: pinmux_P8_28_pruin_pin {
+		pinctrl-single,pins = <0x0e8  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_28_hdmi_pin: pinmux_P8_28_hdmi_pin {
+		pinctrl-single,pins = <0x0e8  0x00>; };     /* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+
+	/* P8_29 (ZCZ ball R5 ) hdmi    */
+	P8_29_default_pin: pinmux_P8_29_default_pin {
+		pinctrl-single,pins = <0x0e4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_29_gpio_pin: pinmux_P8_29_gpio_pin {
+		pinctrl-single,pins = <0x0e4  0x2F>; };     /* Mode 7, RxActive */
+	P8_29_gpio_pu_pin: pinmux_P8_29_gpio_pu_pin {
+		pinctrl-single,pins = <0x0e4  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_29_gpio_pd_pin: pinmux_P8_29_gpio_pd_pin {
+		pinctrl-single,pins = <0x0e4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_29_pruout_pin: pinmux_P8_29_pruout_pin {
+		pinctrl-single,pins = <0x0e4  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_29_pruin_pin: pinmux_P8_29_pruin_pin {
+		pinctrl-single,pins = <0x0e4  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_29_hdmi_pin: pinmux_P8_29_hdmi_pin {
+		pinctrl-single,pins = <0x0e4  0x00>; };     /* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+
+	/* P8_30 (ZCZ ball R6 ) hdmi    */
+	P8_30_default_pin: pinmux_P8_30_default_pin {
+		pinctrl-single,pins = <0x0ec  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_30_gpio_pin: pinmux_P8_30_gpio_pin {
+		pinctrl-single,pins = <0x0ec  0x2F>; };     /* Mode 7, RxActive */
+	P8_30_gpio_pu_pin: pinmux_P8_30_gpio_pu_pin {
+		pinctrl-single,pins = <0x0ec  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_30_gpio_pd_pin: pinmux_P8_30_gpio_pd_pin {
+		pinctrl-single,pins = <0x0ec  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_30_pruout_pin: pinmux_P8_30_pruout_pin {
+		pinctrl-single,pins = <0x0ec  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_30_pruin_pin: pinmux_P8_30_pruin_pin {
+		pinctrl-single,pins = <0x0ec  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_30_hdmi_pin: pinmux_P8_30_hdmi_pin {
+		pinctrl-single,pins = <0x0ec  0x00>; };     /* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+
+	/* P8_31 (ZCZ ball V4 ) hdmi    */
+	P8_31_default_pin: pinmux_P8_31_default_pin {
+		pinctrl-single,pins = <0x0d8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_31_gpio_pin: pinmux_P8_31_gpio_pin {
+		pinctrl-single,pins = <0x0d8  0x2F>; };     /* Mode 7, RxActive */
+	P8_31_gpio_pu_pin: pinmux_P8_31_gpio_pu_pin {
+		pinctrl-single,pins = <0x0d8  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_31_gpio_pd_pin: pinmux_P8_31_gpio_pd_pin {
+		pinctrl-single,pins = <0x0d8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_31_uart_pin: pinmux_P8_31_uart_pin {
+		pinctrl-single,pins = <0x0d8  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+	P8_31_hdmi_pin: pinmux_P8_31_hdmi_pin {
+		pinctrl-single,pins = <0x0d8  0x08>; };     /* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_32 (ZCZ ball T5 ) hdmi    */
+	P8_32_default_pin: pinmux_P8_32_default_pin {
+		pinctrl-single,pins = <0x0dc  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_32_gpio_pin: pinmux_P8_32_gpio_pin {
+		pinctrl-single,pins = <0x0dc  0x2F>; };     /* Mode 7, RxActive */
+	P8_32_gpio_pu_pin: pinmux_P8_32_gpio_pu_pin {
+		pinctrl-single,pins = <0x0dc  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_32_gpio_pd_pin: pinmux_P8_32_gpio_pd_pin {
+		pinctrl-single,pins = <0x0dc  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_32_uart_pin: pinmux_P8_32_uart_pin {
+		pinctrl-single,pins = <0x0dc  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_32_hdmi_pin: pinmux_P8_32_hdmi_pin {
+		pinctrl-single,pins = <0x0dc  0x08>; };     /* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_33 (ZCZ ball V3 ) hdmi    */
+	P8_33_default_pin: pinmux_P8_33_default_pin {
+		pinctrl-single,pins = <0x0d4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_33_gpio_pin: pinmux_P8_33_gpio_pin {
+		pinctrl-single,pins = <0x0d4  0x2F>; };     /* Mode 7, RxActive */
+	P8_33_gpio_pu_pin: pinmux_P8_33_gpio_pu_pin {
+		pinctrl-single,pins = <0x0d4  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_33_gpio_pd_pin: pinmux_P8_33_gpio_pd_pin {
+		pinctrl-single,pins = <0x0d4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_33_hdmi_pin: pinmux_P8_33_hdmi_pin {
+		pinctrl-single,pins = <0x0d4  0x08>; };     /* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_34 (ZCZ ball U4 ) hdmi    */
+	P8_34_default_pin: pinmux_P8_34_default_pin {
+		pinctrl-single,pins = <0x0cc  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_34_gpio_pin: pinmux_P8_34_gpio_pin {
+		pinctrl-single,pins = <0x0cc  0x2F>; };     /* Mode 7, RxActive */
+	P8_34_gpio_pu_pin: pinmux_P8_34_gpio_pu_pin {
+		pinctrl-single,pins = <0x0cc  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_34_gpio_pd_pin: pinmux_P8_34_gpio_pd_pin {
+		pinctrl-single,pins = <0x0cc  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_34_pwm_pin: pinmux_P8_34_pwm_pin {
+		pinctrl-single,pins = <0x0cc  0x22>; };     /* Mode 2, Pull-Down, RxActive */
+	P8_34_hdmi_pin: pinmux_P8_34_hdmi_pin {
+		pinctrl-single,pins = <0x0cc  0x08>; };     /* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_35 (ZCZ ball V2 ) hdmi    */
+	P8_35_default_pin: pinmux_P8_35_default_pin {
+		pinctrl-single,pins = <0x0d0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_35_gpio_pin: pinmux_P8_35_gpio_pin {
+		pinctrl-single,pins = <0x0d0  0x2F>; };     /* Mode 7, RxActive */
+	P8_35_gpio_pu_pin: pinmux_P8_35_gpio_pu_pin {
+		pinctrl-single,pins = <0x0d0  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_35_gpio_pd_pin: pinmux_P8_35_gpio_pd_pin {
+		pinctrl-single,pins = <0x0d0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_35_hdmi_pin: pinmux_P8_35_hdmi_pin {
+		pinctrl-single,pins = <0x0d0  0x08>; };     /* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_36 (ZCZ ball U3 ) hdmi    */
+	P8_36_default_pin: pinmux_P8_36_default_pin {
+		pinctrl-single,pins = <0x0c8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_36_gpio_pin: pinmux_P8_36_gpio_pin {
+		pinctrl-single,pins = <0x0c8  0x2F>; };     /* Mode 7, RxActive */
+	P8_36_gpio_pu_pin: pinmux_P8_36_gpio_pu_pin {
+		pinctrl-single,pins = <0x0c8  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_36_gpio_pd_pin: pinmux_P8_36_gpio_pd_pin {
+		pinctrl-single,pins = <0x0c8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_36_pwm_pin: pinmux_P8_36_pwm_pin {
+		pinctrl-single,pins = <0x0c8  0x22>; };     /* Mode 2, Pull-Down, RxActive */
+	P8_36_hdmi_pin: pinmux_P8_36_hdmi_pin {
+		pinctrl-single,pins = <0x0c8  0x08>; };     /* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_37 (ZCZ ball U1 ) hdmi    */
+	P8_37_default_pin: pinmux_P8_37_default_pin {
+		pinctrl-single,pins = <0x0c0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_37_gpio_pin: pinmux_P8_37_gpio_pin {
+		pinctrl-single,pins = <0x0c0  0x2F>; };     /* Mode 7, RxActive */
+	P8_37_gpio_pu_pin: pinmux_P8_37_gpio_pu_pin {
+		pinctrl-single,pins = <0x0c0  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_37_gpio_pd_pin: pinmux_P8_37_gpio_pd_pin {
+		pinctrl-single,pins = <0x0c0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_37_uart_pin: pinmux_P8_37_uart_pin {
+		pinctrl-single,pins = <0x0c0  0x04>; };     /* Mode 4, Pull-Down*/
+	P8_37_pwm_pin: pinmux_P8_37_pwm_pin {
+		pinctrl-single,pins = <0x0c0  0x02>; };     /* Mode 2, Pull-Down*/
+	P8_37_hdmi_pin: pinmux_P8_37_hdmi_pin {
+		pinctrl-single,pins = <0x0c0  0x08>; };     /* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+
+	/* P8_38 (ZCZ ball U2 ) hdmi    */
+	P8_38_default_pin: pinmux_P8_38_default_pin {
+		pinctrl-single,pins = <0x0c4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_38_gpio_pin: pinmux_P8_38_gpio_pin {
+		pinctrl-single,pins = <0x0c4  0x2F>; };     /* Mode 7, RxActive */
+	P8_38_gpio_pu_pin: pinmux_P8_38_gpio_pu_pin {
+		pinctrl-single,pins = <0x0c4  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_38_gpio_pd_pin: pinmux_P8_38_gpio_pd_pin {
+		pinctrl-single,pins = <0x0c4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_38_uart_pin: pinmux_P8_38_uart_pin {
+		pinctrl-single,pins = <0x0c4  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+	P8_38_pwm_pin: pinmux_P8_38_pwm_pin {
+		pinctrl-single,pins = <0x0c4  0x22>; };     /* Mode 2, Pull-Down, RxActive */
+	P8_38_hdmi_pin: pinmux_P8_38_hdmi_pin {
+		pinctrl-single,pins = <0x0c4  0x08>; };     /* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+
+	/* P8_39 (ZCZ ball T3 ) hdmi    */
+	P8_39_default_pin: pinmux_P8_39_default_pin {
+		pinctrl-single,pins = <0x0b8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_39_gpio_pin: pinmux_P8_39_gpio_pin {
+		pinctrl-single,pins = <0x0b8  0x2F>; };     /* Mode 7, RxActive */
+	P8_39_gpio_pu_pin: pinmux_P8_39_gpio_pu_pin {
+		pinctrl-single,pins = <0x0b8  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_39_gpio_pd_pin: pinmux_P8_39_gpio_pd_pin {
+		pinctrl-single,pins = <0x0b8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_39_pruout_pin: pinmux_P8_39_pruout_pin {
+		pinctrl-single,pins = <0x0b8  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_39_pruin_pin: pinmux_P8_39_pruin_pin {
+		pinctrl-single,pins = <0x0b8  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_39_hdmi_pin: pinmux_P8_39_hdmi_pin {
+		pinctrl-single,pins = <0x0b8  0x08>; };     /* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_40 (ZCZ ball T4 ) hdmi    */
+	P8_40_default_pin: pinmux_P8_40_default_pin {
+		pinctrl-single,pins = <0x0bc  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_40_gpio_pin: pinmux_P8_40_gpio_pin {
+		pinctrl-single,pins = <0x0bc  0x2F>; };     /* Mode 7, RxActive */
+	P8_40_gpio_pu_pin: pinmux_P8_40_gpio_pu_pin {
+		pinctrl-single,pins = <0x0bc  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_40_gpio_pd_pin: pinmux_P8_40_gpio_pd_pin {
+		pinctrl-single,pins = <0x0bc  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_40_pruout_pin: pinmux_P8_40_pruout_pin {
+		pinctrl-single,pins = <0x0bc  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_40_pruin_pin: pinmux_P8_40_pruin_pin {
+		pinctrl-single,pins = <0x0bc  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_40_hdmi_pin: pinmux_P8_40_hdmi_pin {
+		pinctrl-single,pins = <0x0bc  0x08>; };     /* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_41 (ZCZ ball T1 ) hdmi    */
+	P8_41_default_pin: pinmux_P8_41_default_pin {
+		pinctrl-single,pins = <0x0b0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_41_gpio_pin: pinmux_P8_41_gpio_pin {
+		pinctrl-single,pins = <0x0b0  0x2F>; };     /* Mode 7, RxActive */
+	P8_41_gpio_pu_pin: pinmux_P8_41_gpio_pu_pin {
+		pinctrl-single,pins = <0x0b0  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_41_gpio_pd_pin: pinmux_P8_41_gpio_pd_pin {
+		pinctrl-single,pins = <0x0b0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_41_pruout_pin: pinmux_P8_41_pruout_pin {
+		pinctrl-single,pins = <0x0b0  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_41_pruin_pin: pinmux_P8_41_pruin_pin {
+		pinctrl-single,pins = <0x0b0  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_41_hdmi_pin: pinmux_P8_41_hdmi_pin {
+		pinctrl-single,pins = <0x0b0  0x08>; };     /* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_42 (ZCZ ball T2 ) hdmi    */
+	P8_42_default_pin: pinmux_P8_42_default_pin {
+		pinctrl-single,pins = <0x0b4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_42_gpio_pin: pinmux_P8_42_gpio_pin {
+		pinctrl-single,pins = <0x0b4  0x2F>; };     /* Mode 7, RxActive */
+	P8_42_gpio_pu_pin: pinmux_P8_42_gpio_pu_pin {
+		pinctrl-single,pins = <0x0b4  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_42_gpio_pd_pin: pinmux_P8_42_gpio_pd_pin {
+		pinctrl-single,pins = <0x0b4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_42_pruout_pin: pinmux_P8_42_pruout_pin {
+		pinctrl-single,pins = <0x0b4  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_42_pruin_pin: pinmux_P8_42_pruin_pin {
+		pinctrl-single,pins = <0x0b4  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_42_hdmi_pin: pinmux_P8_42_hdmi_pin {
+		pinctrl-single,pins = <0x0b4  0x08>; };     /* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_43 (ZCZ ball R3 ) hdmi    */
+	P8_43_default_pin: pinmux_P8_43_default_pin {
+		pinctrl-single,pins = <0x0a8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_43_gpio_pin: pinmux_P8_43_gpio_pin {
+		pinctrl-single,pins = <0x0a8  0x2F>; };     /* Mode 7, RxActive */
+	P8_43_gpio_pu_pin: pinmux_P8_43_gpio_pu_pin {
+		pinctrl-single,pins = <0x0a8  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_43_gpio_pd_pin: pinmux_P8_43_gpio_pd_pin {
+		pinctrl-single,pins = <0x0a8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_43_pruout_pin: pinmux_P8_43_pruout_pin {
+		pinctrl-single,pins = <0x0a8  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_43_pruin_pin: pinmux_P8_43_pruin_pin {
+		pinctrl-single,pins = <0x0a8  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_43_pwm_pin: pinmux_P8_43_pwm_pin {
+		pinctrl-single,pins = <0x0a8  0x03>; };     /* Mode 3, Pull-Down  */
+	P8_43_hdmi_pin: pinmux_P8_43_hdmi_pin {
+		pinctrl-single,pins = <0x0a8  0x08>; };     /* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_44 (ZCZ ball R4 ) hdmi    */
+	P8_44_default_pin: pinmux_P8_44_default_pin {
+		pinctrl-single,pins = <0x0ac  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_44_gpio_pin: pinmux_P8_44_gpio_pin {
+		pinctrl-single,pins = <0x0ac  0x2F>; };     /* Mode 7, RxActive */
+	P8_44_gpio_pu_pin: pinmux_P8_44_gpio_pu_pin {
+		pinctrl-single,pins = <0x0ac  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_44_gpio_pd_pin: pinmux_P8_44_gpio_pd_pin {
+		pinctrl-single,pins = <0x0ac  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_44_pruout_pin: pinmux_P8_44_pruout_pin {
+		pinctrl-single,pins = <0x0ac  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_44_pruin_pin: pinmux_P8_44_pruin_pin {
+		pinctrl-single,pins = <0x0ac  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_44_pwm_pin: pinmux_P8_44_pwm_pin {
+		pinctrl-single,pins = <0x0ac  0x23>; };     /* Mode 3, Pull-Down, RxActive */
+	P8_44_hdmi_pin: pinmux_P8_44_hdmi_pin {
+		pinctrl-single,pins = <0x0ac  0x08>; };     /* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_45 (ZCZ ball R1 ) hdmi    */
+	P8_45_default_pin: pinmux_P8_45_default_pin {
+		pinctrl-single,pins = <0x0a0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_45_gpio_pin: pinmux_P8_45_gpio_pin {
+		pinctrl-single,pins = <0x0a0  0x2F>; };     /* Mode 7, RxActive */
+	P8_45_gpio_pu_pin: pinmux_P8_45_gpio_pu_pin {
+		pinctrl-single,pins = <0x0a0  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_45_gpio_pd_pin: pinmux_P8_45_gpio_pd_pin {
+		pinctrl-single,pins = <0x0a0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_45_pruout_pin: pinmux_P8_45_pruout_pin {
+		pinctrl-single,pins = <0x0a0  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_45_pruin_pin: pinmux_P8_45_pruin_pin {
+		pinctrl-single,pins = <0x0a0  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_45_pwm_pin: pinmux_P8_45_pwm_pin {
+		pinctrl-single,pins = <0x0a0  0x03>; };     /* Mode 3, Pull-Down*/
+	P8_45_hdmi_pin: pinmux_P8_45_hdmi_pin {
+		pinctrl-single,pins = <0x0a0  0x08>; };     /* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/* P8_46 (ZCZ ball R2 ) hdmi    */
+	P8_46_default_pin: pinmux_P8_46_default_pin {
+		pinctrl-single,pins = <0x0a4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_46_gpio_pin: pinmux_P8_46_gpio_pin {
+		pinctrl-single,pins = <0x0a4  0x2F>; };     /* Mode 7, RxActive */
+	P8_46_gpio_pu_pin: pinmux_P8_46_gpio_pu_pin {
+		pinctrl-single,pins = <0x0a4  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P8_46_gpio_pd_pin: pinmux_P8_46_gpio_pd_pin {
+		pinctrl-single,pins = <0x0a4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P8_46_pruout_pin: pinmux_P8_46_pruout_pin {
+		pinctrl-single,pins = <0x0a4  0x05>; };     /* Mode 5, Pull-Down*/
+	P8_46_pruin_pin: pinmux_P8_46_pruin_pin {
+		pinctrl-single,pins = <0x0a4  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P8_46_pwm_pin: pinmux_P8_46_pwm_pin {
+		pinctrl-single,pins = <0x0a4  0x03>; };     /* Mode 3, Pull-Down*/
+	P8_46_hdmi_pin: pinmux_P8_46_hdmi_pin {
+		pinctrl-single,pins = <0x0a4  0x08>; };     /* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+
+	/************************/
+	/* P9 Header            */
+	/************************/
+
+	/* P9_01                GND     */
+	/* P9_02                GND     */
+	/* P9_03                3.3V    */
+	/* P9_04                3.3V    */
+	/* P9_05                VDD_5V  */
+	/* P9_06                VDD_5V  */
+	/* P9_07                SYS_5V  */
+	/* P9_08                SYS_5V  */
+	/* P9_09                PWR_BUT */
+	/* P9_10 (ZCZ ball A10) RESETn  */
+
+	/* P9_11 (ZCZ ball T17) */
+	P9_11_default_pin: pinmux_P9_11_default_pin {
+		pinctrl-single,pins = <0x070  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_11_gpio_pin: pinmux_P9_11_gpio_pin {
+		pinctrl-single,pins = <0x070  0x2F>; };     /* Mode 7, RxActive */
+	P9_11_gpio_pu_pin: pinmux_P9_11_gpio_pu_pin {
+		pinctrl-single,pins = <0x070  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_11_gpio_pd_pin: pinmux_P9_11_gpio_pd_pin {
+		pinctrl-single,pins = <0x070  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_11_uart_pin: pinmux_P9_11_uart_pin {
+		pinctrl-single,pins = <0x070  0x36>; };     /* Mode 6, Pull-Up, RxActive */
+
+	/* P9_12 (ZCZ ball U18) */
+	P9_12_default_pin: pinmux_P9_12_default_pin {
+		pinctrl-single,pins = <0x078  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_12_gpio_pin: pinmux_P9_12_gpio_pin {
+		pinctrl-single,pins = <0x078  0x2F>; };     /* Mode 7, RxActive */
+	P9_12_gpio_pu_pin: pinmux_P9_12_gpio_pu_pin {
+		pinctrl-single,pins = <0x078  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_12_gpio_pd_pin: pinmux_P9_12_gpio_pd_pin {
+		pinctrl-single,pins = <0x078  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+
+	/* P9_13 (ZCZ ball U17) */
+	P9_13_default_pin: pinmux_P9_13_default_pin {
+		pinctrl-single,pins = <0x074  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_13_gpio_pin: pinmux_P9_13_gpio_pin {
+		pinctrl-single,pins = <0x074  0x2F>; };     /* Mode 7, RxActive */
+	P9_13_gpio_pu_pin: pinmux_P9_13_gpio_pu_pin {
+		pinctrl-single,pins = <0x074  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_13_gpio_pd_pin: pinmux_P9_13_gpio_pd_pin {
+		pinctrl-single,pins = <0x074  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_13_uart_pin: pinmux_P9_13_uart_pin {
+		pinctrl-single,pins = <0x074  0x36>; };     /* Mode 6, Pull-Up, RxActive */
+
+	/* P9_14 (ZCZ ball U14) */
+	P9_14_default_pin: pinmux_P9_14_default_pin {
+		pinctrl-single,pins = <0x048  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_14_gpio_pin: pinmux_P9_14_gpio_pin {
+		pinctrl-single,pins = <0x048  0x2F>; };     /* Mode 7, RxActive */
+	P9_14_gpio_pu_pin: pinmux_P9_14_gpio_pu_pin {
+		pinctrl-single,pins = <0x048  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_14_gpio_pd_pin: pinmux_P9_14_gpio_pd_pin {
+		pinctrl-single,pins = <0x048  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_14_pwm_pin: pinmux_P9_14_pwm_pin {
+		pinctrl-single,pins = <0x048  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+
+	/* P9_15 (ZCZ ball R13) */
+	P9_15_default_pin: pinmux_P9_15_default_pin {
+		pinctrl-single,pins = <0x040  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_15_gpio_pin: pinmux_P9_15_gpio_pin {
+		pinctrl-single,pins = <0x040  0x2F>; };     /* Mode 7, RxActive */
+	P9_15_gpio_pu_pin: pinmux_P9_15_gpio_pu_pin {
+		pinctrl-single,pins = <0x040  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_15_gpio_pd_pin: pinmux_P9_15_gpio_pd_pin {
+		pinctrl-single,pins = <0x040  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_15_pwm_pin: pinmux_P9_15_pwm_pin {
+		pinctrl-single,pins = <0x040  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+
+	/* P9_16 (ZCZ ball T14) */
+	P9_16_default_pin: pinmux_P9_16_default_pin {
+		pinctrl-single,pins = <0x04c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_16_gpio_pin: pinmux_P9_16_gpio_pin {
+		pinctrl-single,pins = <0x04c  0x2F>; };     /* Mode 7, RxActive */
+	P9_16_gpio_pu_pin: pinmux_P9_16_gpio_pu_pin {
+		pinctrl-single,pins = <0x04c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_16_gpio_pd_pin: pinmux_P9_16_gpio_pd_pin {
+		pinctrl-single,pins = <0x04c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_16_pwm_pin: pinmux_P9_16_pwm_pin {
+		pinctrl-single,pins = <0x04c  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+
+	/* P9_17 (ZCZ ball A16) */
+	P9_17_default_pin: pinmux_P9_17_default_pin {
+		pinctrl-single,pins = <0x15c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_17_gpio_pin: pinmux_P9_17_gpio_pin {
+		pinctrl-single,pins = <0x15c  0x2F>; };     /* Mode 7, RxActive */
+	P9_17_gpio_pu_pin: pinmux_P9_17_gpio_pu_pin {
+		pinctrl-single,pins = <0x15c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_17_gpio_pd_pin: pinmux_P9_17_gpio_pd_pin {
+		pinctrl-single,pins = <0x15c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_17_spi_pin: pinmux_P9_17_spi_pin {
+		pinctrl-single,pins = <0x15c  0x30>; };     /* Mode 0, Pull-Up, RxActive */
+	P9_17_i2c_pin: pinmux_P9_17_i2c_pin {
+		pinctrl-single,pins = <0x15c  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+	P9_17_pwm_pin: pinmux_P9_17_pwm_pin {
+		pinctrl-single,pins = <0x15c  0x33>; };     /* Mode 3, Pull-Up, RxActive */
+
+	/* P9_18 (ZCZ ball B16) */
+	P9_18_default_pin: pinmux_P9_18_default_pin {
+		pinctrl-single,pins = <0x158  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_18_gpio_pin: pinmux_P9_18_gpio_pin {
+		pinctrl-single,pins = <0x158  0x2F>; };     /* Mode 7, RxActive */
+	P9_18_gpio_pu_pin: pinmux_P9_18_gpio_pu_pin {
+		pinctrl-single,pins = <0x158  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_18_gpio_pd_pin: pinmux_P9_18_gpio_pd_pin {
+		pinctrl-single,pins = <0x158  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_18_spi_pin: pinmux_P9_18_spi_pin {
+		pinctrl-single,pins = <0x158  0x30>; };     /* Mode 0, Pull-Up, RxActive */
+	P9_18_i2c_pin: pinmux_P9_18_i2c_pin {
+		pinctrl-single,pins = <0x158  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+	P9_18_pwm_pin: pinmux_P9_18_pwm_pin {
+		pinctrl-single,pins = <0x158  0x33>; };     /* Mode 3, Pull-Up, RxActive */
+
+	/* P9_19 (ZCZ ball D17) */
+	P9_19_default_pin: pinmux_P9_19_default_pin {
+		pinctrl-single,pins = <0x17c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_19_gpio_pin: pinmux_P9_19_gpio_pin {
+		pinctrl-single,pins = <0x17c  0x2F>; };     /* Mode 7, RxActive */
+	P9_19_gpio_pu_pin: pinmux_P9_19_gpio_pu_pin {
+		pinctrl-single,pins = <0x17c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_19_gpio_pd_pin: pinmux_P9_19_gpio_pd_pin {
+		pinctrl-single,pins = <0x17c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_19_can_pin: pinmux_P9_19_can_pin {
+		pinctrl-single,pins = <0x17c  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+	P9_19_i2c_pin: pinmux_P9_19_i2c_pin {
+		pinctrl-single,pins = <0x17c  0x73>; };     /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) */
+
+	/* P9_20 (ZCZ ball D18) */
+	P9_20_default_pin: pinmux_P9_20_default_pin {
+		pinctrl-single,pins = <0x178  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_20_gpio_pin: pinmux_P9_20_gpio_pin {
+		pinctrl-single,pins = <0x178  0x2F>; };     /* Mode 7, RxActive */
+	P9_20_gpio_pu_pin: pinmux_P9_20_gpio_pu_pin {
+		pinctrl-single,pins = <0x178  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_20_gpio_pd_pin: pinmux_P9_20_gpio_pd_pin {
+		pinctrl-single,pins = <0x178  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_20_can_pin: pinmux_P9_20_can_pin {
+		pinctrl-single,pins = <0x178  0x12>; };     /* Mode 2, Pull-Up, RxActive */
+	P9_20_i2c_pin: pinmux_P9_20_i2c_pin {
+		pinctrl-single,pins = <0x178  0x73>; };     /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) */
+
+	/* P9_21 (ZCZ ball B17) */
+	P9_21_default_pin: pinmux_P9_21_default_pin {
+		pinctrl-single,pins = <0x154  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_21_gpio_pin: pinmux_P9_21_gpio_pin {
+		pinctrl-single,pins = <0x154  0x2F>; };     /* Mode 7, RxActive */
+	P9_21_gpio_pu_pin: pinmux_P9_21_gpio_pu_pin {
+		pinctrl-single,pins = <0x154  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_21_gpio_pd_pin: pinmux_P9_21_gpio_pd_pin {
+		pinctrl-single,pins = <0x154  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_21_spi_pin: pinmux_P9_21_spi_pin {
+		pinctrl-single,pins = <0x154  0x30>; };     /* Mode 0, Pull-Up, RxActive */
+	P9_21_uart_pin: pinmux_P9_21_uart_pin {
+		pinctrl-single,pins = <0x154  0x31>; };     /* Mode 1, Pull-Up, RxActive */
+	P9_21_i2c_pin: pinmux_P9_21_i2c_pin {
+		pinctrl-single,pins = <0x154  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+	P9_21_pwm_pin: pinmux_P9_21_pwm_pin {
+		pinctrl-single,pins = <0x154  0x33>; };     /* Mode 3, Pull-Up, RxActive */
+
+	/* P9_22 (ZCZ ball A17) */
+	P9_22_default_pin: pinmux_P9_22_default_pin {
+		pinctrl-single,pins = <0x150  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_22_gpio_pin: pinmux_P9_22_gpio_pin {
+		pinctrl-single,pins = <0x150  0x2F>; };     /* Mode 7, RxActive */
+	P9_22_gpio_pu_pin: pinmux_P9_22_gpio_pu_pin {
+		pinctrl-single,pins = <0x150  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_22_gpio_pd_pin: pinmux_P9_22_gpio_pd_pin {
+		pinctrl-single,pins = <0x150  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_22_spi_pin: pinmux_P9_22_spi_pin {
+		pinctrl-single,pins = <0x150  0x30>; };     /* Mode 0, Pull-Up, RxActive */
+	P9_22_uart_pin: pinmux_P9_22_uart_pin {
+		pinctrl-single,pins = <0x150  0x31>; };     /* Mode 1, Pull-Up, RxActive */
+	P9_22_i2c_pin: pinmux_P9_22_i2c_pin {
+		pinctrl-single,pins = <0x150  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+	P9_22_pwm_pin: pinmux_P9_22_pwm_pin {
+		pinctrl-single,pins = <0x150  0x33>; };     /* Mode 3, Pull-Up, RxActive */
+
+	/* P9_23 (ZCZ ball V14) */
+	P9_23_default_pin: pinmux_P9_23_default_pin {
+		pinctrl-single,pins = <0x044  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_23_gpio_pin: pinmux_P9_23_gpio_pin {
+		pinctrl-single,pins = <0x044  0x2F>; };     /* Mode 7, RxActive */
+	P9_23_gpio_pu_pin: pinmux_P9_23_gpio_pu_pin {
+		pinctrl-single,pins = <0x044  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_23_gpio_pd_pin: pinmux_P9_23_gpio_pd_pin {
+		pinctrl-single,pins = <0x044  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_23_pwm_pin: pinmux_P9_23_pwm_pin {
+		pinctrl-single,pins = <0x044  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+
+	/* P9_24 (ZCZ ball D15) */
+	P9_24_default_pin: pinmux_P9_24_default_pin {
+		pinctrl-single,pins = <0x184  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_24_gpio_pin: pinmux_P9_24_gpio_pin {
+		pinctrl-single,pins = <0x184  0x2F>; };     /* Mode 7, RxActive */
+	P9_24_gpio_pu_pin: pinmux_P9_24_gpio_pu_pin {
+		pinctrl-single,pins = <0x184  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_24_gpio_pd_pin: pinmux_P9_24_gpio_pd_pin {
+		pinctrl-single,pins = <0x184  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_24_uart_pin: pinmux_P9_24_uart_pin {
+		pinctrl-single,pins = <0x184  0x30>; };     /* Mode 0, Pull-Up, RxActive */
+	P9_24_can_pin: pinmux_P9_24_can_pin {
+		pinctrl-single,pins = <0x184  0x32>; };     /* Mode 2, Pull-Up, RxActive */
+	P9_24_i2c_pin: pinmux_P9_24_i2c_pin {
+		pinctrl-single,pins = <0x184  0x33>; };     /* Mode 3, Pull-Up, RxActive */
+	P9_24_pruin_pin: pinmux_P9_24_pruin_pin {
+		pinctrl-single,pins = <0x184  0x36>; };     /* Mode 6, Pull-Up, RxActive */
+
+	/* P9_25 (ZCZ ball A14) Audio   */
+	P9_25_default_pin: pinmux_P9_25_default_pin {
+		pinctrl-single,pins = <0x1ac  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_25_gpio_pin: pinmux_P9_25_gpio_pin {
+		pinctrl-single,pins = <0x1ac  0x2F>; };     /* Mode 7, RxActive */
+	P9_25_gpio_pu_pin: pinmux_P9_25_gpio_pu_pin {
+		pinctrl-single,pins = <0x1ac  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_25_gpio_pd_pin: pinmux_P9_25_gpio_pd_pin {
+		pinctrl-single,pins = <0x1ac  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_25_qep_pin: pinmux_P9_25_qep_pin {
+		pinctrl-single,pins = <0x1ac  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+	P9_25_pruout_pin: pinmux_P9_25_pruout_pin {
+		pinctrl-single,pins = <0x1ac  0x25>; };     /* Mode 5, Pull-Down, RxActive */
+	P9_25_pruin_pin: pinmux_P9_25_pruin_pin {
+		pinctrl-single,pins = <0x1ac  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P9_25_audio_pin: pinmux_P9_25_audio_pin {
+		pinctrl-single,pins = <0x1ac  (PIN_INPUT_PULLUP | MUX_MODE0)>; };	/* mcasp0_ahclkx.mcasp0_ahclkx */
+
+	/* P9_26 (ZCZ ball D16) */
+	P9_26_default_pin: pinmux_P9_26_default_pin {
+		pinctrl-single,pins = <0x180  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_26_gpio_pin: pinmux_P9_26_gpio_pin {
+		pinctrl-single,pins = <0x180  0x2F>; };     /* Mode 7, RxActive */
+	P9_26_gpio_pu_pin: pinmux_P9_26_gpio_pu_pin {
+		pinctrl-single,pins = <0x180  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_26_gpio_pd_pin: pinmux_P9_26_gpio_pd_pin {
+		pinctrl-single,pins = <0x180  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_26_uart_pin: pinmux_P9_26_uart_pin {
+		pinctrl-single,pins = <0x180  0x30>; };     /* Mode 0, Pull-Up, RxActive */
+	P9_26_can_pin: pinmux_P9_26_can_pin {
+		pinctrl-single,pins = <0x180  0x12>; };     /* Mode 2, Pull-Up, RxActive */
+	P9_26_i2c_pin: pinmux_P9_26_i2c_pin {
+		pinctrl-single,pins = <0x180  0x33>; };     /* Mode 3, Pull-Up, RxActive */
+	P9_26_pruin_pin: pinmux_P9_26_pruin_pin {
+		pinctrl-single,pins = <0x180  0x36>; };     /* Mode 6, Pull-Up, RxActive */
+
+	/* P9_27 (ZCZ ball C13) */
+	P9_27_default_pin: pinmux_P9_27_default_pin {
+		pinctrl-single,pins = <0x1a4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_27_gpio_pin: pinmux_P9_27_gpio_pin {
+		pinctrl-single,pins = <0x1a4  0x2F>; };     /* Mode 7, RxActive */
+	P9_27_gpio_pu_pin: pinmux_P9_27_gpio_pu_pin {
+		pinctrl-single,pins = <0x1a4  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_27_gpio_pd_pin: pinmux_P9_27_gpio_pd_pin {
+		pinctrl-single,pins = <0x1a4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_27_qep_pin: pinmux_P9_27_qep_pin {
+		pinctrl-single,pins = <0x1a4  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+	P9_27_pruout_pin: pinmux_P9_27_pruout_pin {
+		pinctrl-single,pins = <0x1a4  0x25>; };     /* Mode 5, Pull-Down, RxActive */
+	P9_27_pruin_pin: pinmux_P9_27_pruin_pin {
+		pinctrl-single,pins = <0x1a4  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+
+	/* P9_28 (ZCZ ball C12) Audio   */
+	P9_28_default_pin: pinmux_P9_28_default_pin {
+		pinctrl-single,pins = <0x19c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_28_gpio_pin: pinmux_P9_28_gpio_pin {
+		pinctrl-single,pins = <0x19c  0x2F>; };     /* Mode 7, RxActive */
+	P9_28_gpio_pu_pin: pinmux_P9_28_gpio_pu_pin {
+		pinctrl-single,pins = <0x19c  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_28_gpio_pd_pin: pinmux_P9_28_gpio_pd_pin {
+		pinctrl-single,pins = <0x19c  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_28_pwm_pin: pinmux_P9_28_pwm_pin {
+		pinctrl-single,pins = <0x19c  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+	P9_28_spi_pin: pinmux_P9_28_spi_pin {
+		pinctrl-single,pins = <0x19c  0x23>; };     /* Mode 3, Pull-Down, RxActive */
+	P9_28_pwm2_pin: pinmux_P9_28_pwm2_pin {
+		pinctrl-single,pins = <0x19c  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+	P9_28_pruout_pin: pinmux_P9_28_pruout_pin {
+		pinctrl-single,pins = <0x19c  0x25>; };     /* Mode 5, Pull-Down, RxActive */
+	P9_28_pruin_pin: pinmux_P9_28_pruin_pin {
+		pinctrl-single,pins = <0x19c  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P9_28_audio_pin: pinmux_P9_28_audio_pin {
+		pinctrl-single,pins = <0x19c  (PIN_OUTPUT_PULLDOWN | MUX_MODE2)>; };	/* mcasp0_ahclkr.mcasp0_axr2 */
+
+	/* P9_29 (ZCZ ball B13) Audio   */
+	P9_29_default_pin: pinmux_P9_29_default_pin {
+		pinctrl-single,pins = <0x194  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_29_gpio_pin: pinmux_P9_29_gpio_pin {
+		pinctrl-single,pins = <0x194  0x2F>; };     /* Mode 7, RxActive */
+	P9_29_gpio_pu_pin: pinmux_P9_29_gpio_pu_pin {
+		pinctrl-single,pins = <0x194  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_29_gpio_pd_pin: pinmux_P9_29_gpio_pd_pin {
+		pinctrl-single,pins = <0x194  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_29_pwm_pin: pinmux_P9_29_pwm_pin {
+		pinctrl-single,pins = <0x194  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+	P9_29_spi_pin: pinmux_P9_29_spi_pin {
+		pinctrl-single,pins = <0x194  0x23>; };     /* Mode 3, Pull-Down, RxActive */
+	P9_29_pruout_pin: pinmux_P9_29_pruout_pin {
+		pinctrl-single,pins = <0x194  0x25>; };     /* Mode 5, Pull-Down, RxActive */
+	P9_29_pruin_pin: pinmux_P9_29_pruin_pin {
+		pinctrl-single,pins = <0x194  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P9_29_audio_pin: pinmux_P9_29_audio_pin {
+		pinctrl-single,pins = <0x194  (PIN_OUTPUT_PULLUP | MUX_MODE0)>; };	/* mcasp0_fsx.mcasp0_fsx */
+
+	/* P9_30 (ZCZ ball D12) */
+	P9_30_default_pin: pinmux_P9_30_default_pin {
+		pinctrl-single,pins = <0x198  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_30_gpio_pin: pinmux_P9_30_gpio_pin {
+		pinctrl-single,pins = <0x198  0x2F>; };     /* Mode 7, RxActive */
+	P9_30_gpio_pu_pin: pinmux_P9_30_gpio_pu_pin {
+		pinctrl-single,pins = <0x198  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_30_gpio_pd_pin: pinmux_P9_30_gpio_pd_pin {
+		pinctrl-single,pins = <0x198  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_30_pwm_pin: pinmux_P9_30_pwm_pin {
+		pinctrl-single,pins = <0x198  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+	P9_30_spi_pin: pinmux_P9_30_spi_pin {
+		pinctrl-single,pins = <0x198  0x23>; };     /* Mode 3, Pull-Down, RxActive */
+	P9_30_pruout_pin: pinmux_P9_30_pruout_pin {
+		pinctrl-single,pins = <0x198  0x25>; };     /* Mode 5, Pull-Down, RxActive */
+	P9_30_pruin_pin: pinmux_P9_30_pruin_pin {
+		pinctrl-single,pins = <0x198  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+
+	/* P9_31 (ZCZ ball A13) Audio   */
+	P9_31_default_pin: pinmux_P9_31_default_pin {
+		pinctrl-single,pins = <0x190  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_31_gpio_pin: pinmux_P9_31_gpio_pin {
+		pinctrl-single,pins = <0x190  0x2F>; };     /* Mode 7, RxActive */
+	P9_31_gpio_pu_pin: pinmux_P9_31_gpio_pu_pin {
+		pinctrl-single,pins = <0x190  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_31_gpio_pd_pin: pinmux_P9_31_gpio_pd_pin {
+		pinctrl-single,pins = <0x190  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_31_pwm_pin: pinmux_P9_31_pwm_pin {
+		pinctrl-single,pins = <0x190  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+	P9_31_spi_pin: pinmux_P9_31_spi_pin {
+		pinctrl-single,pins = <0x190  0x23>; };     /* Mode 3, Pull-Down, RxActive */
+	P9_31_pruout_pin: pinmux_P9_31_pruout_pin {
+		pinctrl-single,pins = <0x190  0x25>; };     /* Mode 5, Pull-Down, RxActive */
+	P9_31_pruin_pin: pinmux_P9_31_pruin_pin {
+		pinctrl-single,pins = <0x190  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+	P9_31_audio_pin: pinmux_P9_31_audio_pin {
+		pinctrl-single,pins = <0x190  (PIN_OUTPUT_PULLDOWN | MUX_MODE0)>; };	/* mcasp0_aclkx.mcasp0_aclkx */
+
+	/* P9_32                VADC    */
+	/* P9_33 (ZCZ ball C8 ) AIN4    */
+	/* P9_34                AGND    */
+	/* P9_35 (ZCZ ball A8 ) AIN6    */
+	/* P9_36 (ZCZ ball B8 ) AIN5    */
+	/* P9_37 (ZCZ ball B7 ) AIN2    */
+	/* P9_38 (ZCZ ball A7 ) AIN3    */
+	/* P9_39 (ZCZ ball B6 ) AIN0    */
+	/* P9_40 (ZCZ ball C7 ) AIN1    */
+
+	/* P9_41 (ZCZ ball D14) */
+	P9_41_default_pin: pinmux_P9_41_default_pin {
+		pinctrl-single,pins = <0x1b4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_41_gpio_pin: pinmux_P9_41_gpio_pin {
+		pinctrl-single,pins = <0x1b4  0x2F>; };     /* Mode 7, RxActive */
+	P9_41_gpio_pu_pin: pinmux_P9_41_gpio_pu_pin {
+		pinctrl-single,pins = <0x1b4  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_41_gpio_pd_pin: pinmux_P9_41_gpio_pd_pin {
+		pinctrl-single,pins = <0x1b4  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_41_timer_pin: pinmux_P9_41_timer_pin {
+		pinctrl-single,pins = <0x1b4  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+	P9_41_pruin_pin: pinmux_P9_41_pruin_pin {
+		pinctrl-single,pins = <0x1b4  0x25>; };     /* Mode 5, Pull-Down, RxActive */
+
+	/* P9_41.1              */
+	/* P9_91 (ZCZ ball D13) */
+	P9_91_default_pin: pinmux_P9_91_default_pin {
+		pinctrl-single,pins = <0x1a8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_91_gpio_pin: pinmux_P9_91_gpio_pin {
+		pinctrl-single,pins = <0x1a8  0x2F>; };     /* Mode 7, RxActive */
+	P9_91_gpio_pu_pin: pinmux_P9_91_gpio_pu_pin {
+		pinctrl-single,pins = <0x1a8  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_91_gpio_pd_pin: pinmux_P9_91_gpio_pd_pin {
+		pinctrl-single,pins = <0x1a8  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_91_qep_pin: pinmux_P9_91_qep_pin {
+		pinctrl-single,pins = <0x1a8  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+	P9_91_pruout_pin: pinmux_P9_91_pruout_pin {
+		pinctrl-single,pins = <0x1a8  0x25>; };     /* Mode 5, Pull-Down, RxActive */
+	P9_91_pruin_pin: pinmux_P9_91_pruin_pin {
+		pinctrl-single,pins = <0x1a8  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+
+	/* P9_42 (ZCZ ball C18) */
+	P9_42_default_pin: pinmux_P9_42_default_pin {
+		pinctrl-single,pins = <0x164  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_42_gpio_pin: pinmux_P9_42_gpio_pin {
+		pinctrl-single,pins = <0x164  0x2F>; };     /* Mode 7, RxActive */
+	P9_42_gpio_pu_pin: pinmux_P9_42_gpio_pu_pin {
+		pinctrl-single,pins = <0x164  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_42_gpio_pd_pin: pinmux_P9_42_gpio_pd_pin {
+		pinctrl-single,pins = <0x164  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_42_pwm_pin: pinmux_P9_42_pwm_pin {
+		pinctrl-single,pins = <0x164  0x20>; };     /* Mode 0, Pull-Down, RxActive */
+	P9_42_uart_pin: pinmux_P9_42_uart_pin {
+		pinctrl-single,pins = <0x164  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+	P9_42_spics_pin: pinmux_P9_42_spics_pin {
+		pinctrl-single,pins = <0x164  0x22>; };     /* Mode 2, Pull-Down, RxActive */
+	P9_42_spiclk_pin: pinmux_P9_42_spiclk_pin {
+		pinctrl-single,pins = <0x164  0x24>; };     /* Mode 4, Pull-Down, RxActive */
+
+	/* P9_42.1              */
+	/* P9_92 (ZCZ ball B12) */
+	P9_92_default_pin: pinmux_P9_92_default_pin {
+		pinctrl-single,pins = <0x1a0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_92_gpio_pin: pinmux_P9_92_gpio_pin {
+		pinctrl-single,pins = <0x1a0  0x2F>; };     /* Mode 7, RxActive */
+	P9_92_gpio_pu_pin: pinmux_P9_92_gpio_pu_pin {
+		pinctrl-single,pins = <0x1a0  0x37>; };     /* Mode 7, Pull-Up, RxActive */
+	P9_92_gpio_pd_pin: pinmux_P9_92_gpio_pd_pin {
+		pinctrl-single,pins = <0x1a0  0x27>; };     /* Mode 7, Pull-Down, RxActive */
+	P9_92_qep_pin: pinmux_P9_92_qep_pin {
+		pinctrl-single,pins = <0x1a0  0x21>; };     /* Mode 1, Pull-Down, RxActive */
+	P9_92_pruout_pin: pinmux_P9_92_pruout_pin {
+		pinctrl-single,pins = <0x1a0  0x25>; };     /* Mode 5, Pull-Down, RxActive */
+	P9_92_pruin_pin: pinmux_P9_92_pruin_pin {
+		pinctrl-single,pins = <0x1a0  0x26>; };     /* Mode 6, Pull-Down, RxActive */
+
+	/* P9_43                GND     */
+	/* P9_44                GND     */
+	/* P9_45                GND     */
+	/* P9_46                GND     */
+};
+
+/**********************************************************************/
+/* Pin Multiplex Helpers                                              */
+/*                                                                    */
+/* These provide userspace runtime pin configuration for the          */
+/* BeagleBone cape expansion headers                                  */
+/**********************************************************************/
+
+&ocp {
+	/************************/
+	/* P8 Header            */
+	/************************/
+
+	P8_07_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer";
+		pinctrl-0 = <&P8_07_default_pin>;
+		pinctrl-1 = <&P8_07_gpio_pin>;
+		pinctrl-2 = <&P8_07_gpio_pu_pin>;
+		pinctrl-3 = <&P8_07_gpio_pd_pin>;
+		pinctrl-4 = <&P8_07_timer_pin>;
+	};
+
+	P8_08_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer";
+		pinctrl-0 = <&P8_08_default_pin>;
+		pinctrl-1 = <&P8_08_gpio_pin>;
+		pinctrl-2 = <&P8_08_gpio_pu_pin>;
+		pinctrl-3 = <&P8_08_gpio_pd_pin>;
+		pinctrl-4 = <&P8_08_timer_pin>;
+	};
+
+	P8_09_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer";
+		pinctrl-0 = <&P8_09_default_pin>;
+		pinctrl-1 = <&P8_09_gpio_pin>;
+		pinctrl-2 = <&P8_09_gpio_pu_pin>;
+		pinctrl-3 = <&P8_09_gpio_pd_pin>;
+		pinctrl-4 = <&P8_09_timer_pin>;
+	};
+
+	P8_10_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer";
+		pinctrl-0 = <&P8_10_default_pin>;
+		pinctrl-1 = <&P8_10_gpio_pin>;
+		pinctrl-2 = <&P8_10_gpio_pu_pin>;
+		pinctrl-3 = <&P8_10_gpio_pd_pin>;
+		pinctrl-4 = <&P8_10_timer_pin>;
+	};
+
+	P8_11_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "qep";
+		pinctrl-0 = <&P8_11_default_pin>;
+		pinctrl-1 = <&P8_11_gpio_pin>;
+		pinctrl-2 = <&P8_11_gpio_pu_pin>;
+		pinctrl-3 = <&P8_11_gpio_pd_pin>;
+		pinctrl-4 = <&P8_11_pruout_pin>;
+		pinctrl-5 = <&P8_11_qep_pin>;
+	};
+
+	P8_12_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "qep";
+		pinctrl-0 = <&P8_12_default_pin>;
+		pinctrl-1 = <&P8_12_gpio_pin>;
+		pinctrl-2 = <&P8_12_gpio_pu_pin>;
+		pinctrl-3 = <&P8_12_gpio_pd_pin>;
+		pinctrl-4 = <&P8_12_pruout_pin>;
+		pinctrl-5 = <&P8_12_qep_pin>;
+	};
+
+	P8_13_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
+		pinctrl-0 = <&P8_13_default_pin>;
+		pinctrl-1 = <&P8_13_gpio_pin>;
+		pinctrl-2 = <&P8_13_gpio_pu_pin>;
+		pinctrl-3 = <&P8_13_gpio_pd_pin>;
+		pinctrl-4 = <&P8_13_pwm_pin>;
+	};
+
+	P8_14_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
+		pinctrl-0 = <&P8_14_default_pin>;
+		pinctrl-1 = <&P8_14_gpio_pin>;
+		pinctrl-2 = <&P8_14_gpio_pu_pin>;
+		pinctrl-3 = <&P8_14_gpio_pd_pin>;
+		pinctrl-4 = <&P8_14_pwm_pin>;
+	};
+
+	P8_15_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruin", "qep";
+		pinctrl-0 = <&P8_15_default_pin>;
+		pinctrl-1 = <&P8_15_gpio_pin>;
+		pinctrl-2 = <&P8_15_gpio_pu_pin>;
+		pinctrl-3 = <&P8_15_gpio_pd_pin>;
+		pinctrl-4 = <&P8_15_pruin_pin>;
+		pinctrl-5 = <&P8_15_qep_pin>;
+	};
+
+	P8_16_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruin", "qep";
+		pinctrl-0 = <&P8_16_default_pin>;
+		pinctrl-1 = <&P8_16_gpio_pin>;
+		pinctrl-2 = <&P8_16_gpio_pu_pin>;
+		pinctrl-3 = <&P8_16_gpio_pd_pin>;
+		pinctrl-4 = <&P8_16_pruin_pin>;
+		pinctrl-5 = <&P8_16_qep_pin>;
+	};
+
+	P8_17_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
+		pinctrl-0 = <&P8_17_default_pin>;
+		pinctrl-1 = <&P8_17_gpio_pin>;
+		pinctrl-2 = <&P8_17_gpio_pu_pin>;
+		pinctrl-3 = <&P8_17_gpio_pd_pin>;
+		pinctrl-4 = <&P8_17_pwm_pin>;
+	};
+
+	P8_18_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio";
+		pinctrl-0 = <&P8_18_default_pin>;
+		pinctrl-1 = <&P8_18_gpio_pin>;
+		pinctrl-2 = <&P8_18_gpio_pu_pin>;
+		pinctrl-3 = <&P8_18_gpio_pd_pin>;
+	};
+
+	P8_19_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
+		pinctrl-0 = <&P8_19_default_pin>;
+		pinctrl-1 = <&P8_19_gpio_pin>;
+		pinctrl-2 = <&P8_19_gpio_pu_pin>;
+		pinctrl-3 = <&P8_19_gpio_pd_pin>;
+		pinctrl-4 = <&P8_19_pwm_pin>;
+	};
+
+	P8_26_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio";
+		pinctrl-0 = <&P8_26_default_pin>;
+		pinctrl-1 = <&P8_26_gpio_pin>;
+		pinctrl-2 = <&P8_26_gpio_pu_pin>;
+		pinctrl-3 = <&P8_26_gpio_pd_pin>;
+	};
+
+	P8_27_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
+		pinctrl-0 = <&P8_27_default_pin>;
+		pinctrl-1 = <&P8_27_gpio_pin>;
+		pinctrl-2 = <&P8_27_gpio_pu_pin>;
+		pinctrl-3 = <&P8_27_gpio_pd_pin>;
+		pinctrl-4 = <&P8_27_pruout_pin>;
+		pinctrl-5 = <&P8_27_pruin_pin>;
+		pinctrl-6 = <&P8_27_hdmi_pin>;
+	};
+
+	P8_28_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
+		pinctrl-0 = <&P8_28_default_pin>;
+		pinctrl-1 = <&P8_28_gpio_pin>;
+		pinctrl-2 = <&P8_28_gpio_pu_pin>;
+		pinctrl-3 = <&P8_28_gpio_pd_pin>;
+		pinctrl-4 = <&P8_28_pruout_pin>;
+		pinctrl-5 = <&P8_28_pruin_pin>;
+		pinctrl-6 = <&P8_28_hdmi_pin>;
+	};
+
+	P8_29_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
+		pinctrl-0 = <&P8_29_default_pin>;
+		pinctrl-1 = <&P8_29_gpio_pin>;
+		pinctrl-2 = <&P8_29_gpio_pu_pin>;
+		pinctrl-3 = <&P8_29_gpio_pd_pin>;
+		pinctrl-4 = <&P8_29_pruout_pin>;
+		pinctrl-5 = <&P8_29_pruin_pin>;
+		pinctrl-6 = <&P8_29_hdmi_pin>;
+	};
+
+	P8_30_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
+		pinctrl-0 = <&P8_30_default_pin>;
+		pinctrl-1 = <&P8_30_gpio_pin>;
+		pinctrl-2 = <&P8_30_gpio_pu_pin>;
+		pinctrl-3 = <&P8_30_gpio_pd_pin>;
+		pinctrl-4 = <&P8_30_pruout_pin>;
+		pinctrl-5 = <&P8_30_pruin_pin>;
+		pinctrl-6 = <&P8_30_hdmi_pin>;
+	};
+
+	P8_31_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","uart", "hdmi";
+		pinctrl-0 = <&P8_31_default_pin>;
+		pinctrl-1 = <&P8_31_gpio_pin>;
+		pinctrl-2 = <&P8_31_gpio_pu_pin>;
+		pinctrl-3 = <&P8_31_gpio_pd_pin>;
+		pinctrl-4 = <&P8_31_uart_pin>;
+		pinctrl-5 = <&P8_31_hdmi_pin>;
+	};
+
+	P8_32_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "hdmi";
+		pinctrl-0 = <&P8_32_default_pin>;
+		pinctrl-1 = <&P8_32_gpio_pin>;
+		pinctrl-2 = <&P8_32_gpio_pu_pin>;
+		pinctrl-3 = <&P8_32_gpio_pd_pin>;
+		pinctrl-4 = <&P8_32_hdmi_pin>;
+	};
+
+	P8_33_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "hdmi";
+		pinctrl-0 = <&P8_33_default_pin>;
+		pinctrl-1 = <&P8_33_gpio_pin>;
+		pinctrl-2 = <&P8_33_gpio_pu_pin>;
+		pinctrl-3 = <&P8_33_gpio_pd_pin>;
+		pinctrl-4 = <&P8_33_hdmi_pin>;
+	};
+
+	P8_34_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","pwm", "hdmi";
+		pinctrl-0 = <&P8_34_default_pin>;
+		pinctrl-1 = <&P8_34_gpio_pin>;
+		pinctrl-2 = <&P8_34_gpio_pu_pin>;
+		pinctrl-3 = <&P8_34_gpio_pd_pin>;
+		pinctrl-4 = <&P8_34_pwm_pin>;
+		pinctrl-5 = <&P8_34_hdmi_pin>;
+	};
+
+	P8_35_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "hdmi";
+		pinctrl-0 = <&P8_35_default_pin>;
+		pinctrl-1 = <&P8_35_gpio_pin>;
+		pinctrl-2 = <&P8_35_gpio_pu_pin>;
+		pinctrl-3 = <&P8_35_gpio_pd_pin>;
+		pinctrl-4 = <&P8_35_hdmi_pin>;
+	};
+
+	P8_36_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","pwm", "hdmi";
+		pinctrl-0 = <&P8_36_default_pin>;
+		pinctrl-1 = <&P8_36_gpio_pin>;
+		pinctrl-2 = <&P8_36_gpio_pu_pin>;
+		pinctrl-3 = <&P8_36_gpio_pd_pin>;
+		pinctrl-4 = <&P8_36_pwm_pin>;
+		pinctrl-5 = <&P8_36_hdmi_pin>;
+	};
+
+	P8_37_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","uart","pwm", "hdmi";
+		pinctrl-0 = <&P8_37_default_pin>;
+		pinctrl-1 = <&P8_37_gpio_pin>;
+		pinctrl-2 = <&P8_37_gpio_pu_pin>;
+		pinctrl-3 = <&P8_37_gpio_pd_pin>;
+		pinctrl-4 = <&P8_37_uart_pin>;
+		pinctrl-5 = <&P8_37_pwm_pin>;
+		pinctrl-6 = <&P8_37_hdmi_pin>;
+	};
+
+	P8_38_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd","uart","pwm", "hdmi";
+		pinctrl-0 = <&P8_38_default_pin>;
+		pinctrl-1 = <&P8_38_gpio_pin>;
+		pinctrl-2 = <&P8_38_gpio_pu_pin>;
+		pinctrl-3 = <&P8_38_gpio_pd_pin>;
+		pinctrl-4 = <&P8_38_uart_pin>;
+		pinctrl-5 = <&P8_38_pwm_pin>;
+		pinctrl-6 = <&P8_38_hdmi_pin>;
+	};
+
+	P8_39_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
+		pinctrl-0 = <&P8_39_default_pin>;
+		pinctrl-1 = <&P8_39_gpio_pin>;
+		pinctrl-2 = <&P8_39_gpio_pu_pin>;
+		pinctrl-3 = <&P8_39_gpio_pd_pin>;
+		pinctrl-4 = <&P8_39_pruout_pin>;
+		pinctrl-5 = <&P8_39_pruin_pin>;
+		pinctrl-6 = <&P8_39_hdmi_pin>;
+	};
+
+	P8_40_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
+		pinctrl-0 = <&P8_40_default_pin>;
+		pinctrl-1 = <&P8_40_gpio_pin>;
+		pinctrl-2 = <&P8_40_gpio_pu_pin>;
+		pinctrl-3 = <&P8_40_gpio_pd_pin>;
+		pinctrl-4 = <&P8_40_pruout_pin>;
+		pinctrl-5 = <&P8_40_pruin_pin>;
+		pinctrl-6 = <&P8_40_hdmi_pin>;
+	};
+
+	P8_41_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
+		pinctrl-0 = <&P8_41_default_pin>;
+		pinctrl-1 = <&P8_41_gpio_pin>;
+		pinctrl-2 = <&P8_41_gpio_pu_pin>;
+		pinctrl-3 = <&P8_41_gpio_pd_pin>;
+		pinctrl-4 = <&P8_41_pruout_pin>;
+		pinctrl-5 = <&P8_41_pruin_pin>;
+		pinctrl-6 = <&P8_41_hdmi_pin>;
+	};
+
+	P8_42_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin", "hdmi";
+		pinctrl-0 = <&P8_42_default_pin>;
+		pinctrl-1 = <&P8_42_gpio_pin>;
+		pinctrl-2 = <&P8_42_gpio_pu_pin>;
+		pinctrl-3 = <&P8_42_gpio_pd_pin>;
+		pinctrl-4 = <&P8_42_pruout_pin>;
+		pinctrl-5 = <&P8_42_pruin_pin>;
+		pinctrl-6 = <&P8_42_hdmi_pin>;
+	};
+
+	P8_43_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm", "hdmi";
+		pinctrl-0 = <&P8_43_default_pin>;
+		pinctrl-1 = <&P8_43_gpio_pin>;
+		pinctrl-2 = <&P8_43_gpio_pu_pin>;
+		pinctrl-3 = <&P8_43_gpio_pd_pin>;
+		pinctrl-4 = <&P8_43_pruout_pin>;
+		pinctrl-5 = <&P8_43_pruin_pin>;
+		pinctrl-6 = <&P8_43_pwm_pin>;
+		pinctrl-7 = <&P8_43_hdmi_pin>;
+	};
+
+	P8_44_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm", "hdmi";
+		pinctrl-0 = <&P8_44_default_pin>;
+		pinctrl-1 = <&P8_44_gpio_pin>;
+		pinctrl-2 = <&P8_44_gpio_pu_pin>;
+		pinctrl-3 = <&P8_44_gpio_pd_pin>;
+		pinctrl-4 = <&P8_44_pruout_pin>;
+		pinctrl-5 = <&P8_44_pruin_pin>;
+		pinctrl-6 = <&P8_44_pwm_pin>;
+		pinctrl-7 = <&P8_44_hdmi_pin>;
+	};
+
+	P8_45_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm", "hdmi";
+		pinctrl-0 = <&P8_45_default_pin>;
+		pinctrl-1 = <&P8_45_gpio_pin>;
+		pinctrl-2 = <&P8_45_gpio_pu_pin>;
+		pinctrl-3 = <&P8_45_gpio_pd_pin>;
+		pinctrl-4 = <&P8_45_pruout_pin>;
+		pinctrl-5 = <&P8_45_pruin_pin>;
+		pinctrl-6 = <&P8_45_pwm_pin>;
+		pinctrl-7 = <&P8_45_hdmi_pin>;
+	};
+
+	P8_46_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pruout", "pruin","pwm", "hdmi";
+		pinctrl-0 = <&P8_46_default_pin>;
+		pinctrl-1 = <&P8_46_gpio_pin>;
+		pinctrl-2 = <&P8_46_gpio_pu_pin>;
+		pinctrl-3 = <&P8_46_gpio_pd_pin>;
+		pinctrl-4 = <&P8_46_pruout_pin>;
+		pinctrl-5 = <&P8_46_pruin_pin>;
+		pinctrl-6 = <&P8_46_pwm_pin>;
+		pinctrl-7 = <&P8_46_hdmi_pin>;
+	};
+
+	/************************/
+	/* P9 Header	        */
+	/************************/
+
+	P9_11_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart";
+		pinctrl-0 = <&P9_11_default_pin>;
+		pinctrl-1 = <&P9_11_gpio_pin>;
+		pinctrl-2 = <&P9_11_gpio_pu_pin>;
+		pinctrl-3 = <&P9_11_gpio_pd_pin>;
+		pinctrl-4 = <&P9_11_uart_pin>;
+	};
+
+	P9_12_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio";
+		pinctrl-0 = <&P9_12_default_pin>;
+		pinctrl-1 = <&P9_12_gpio_pin>;
+		pinctrl-2 = <&P9_12_gpio_pu_pin>;
+		pinctrl-3 = <&P9_12_gpio_pd_pin>;
+	};
+
+	P9_13_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart";
+		pinctrl-0 = <&P9_13_default_pin>;
+		pinctrl-1 = <&P9_13_gpio_pin>;
+		pinctrl-2 = <&P9_13_gpio_pu_pin>;
+		pinctrl-3 = <&P9_13_gpio_pd_pin>;
+		pinctrl-4 = <&P9_13_uart_pin>;
+	};
+
+	P9_14_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
+		pinctrl-0 = <&P9_14_default_pin>;
+		pinctrl-1 = <&P9_14_gpio_pin>;
+		pinctrl-2 = <&P9_14_gpio_pu_pin>;
+		pinctrl-3 = <&P9_14_gpio_pd_pin>;
+		pinctrl-4 = <&P9_14_pwm_pin>;
+	};
+
+	P9_15_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
+		pinctrl-0 = <&P9_15_default_pin>;
+		pinctrl-1 = <&P9_15_gpio_pin>;
+		pinctrl-2 = <&P9_15_gpio_pu_pin>;
+		pinctrl-3 = <&P9_15_gpio_pd_pin>;
+		pinctrl-4 = <&P9_15_pwm_pin>;
+	};
+
+	P9_16_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
+		pinctrl-0 = <&P9_16_default_pin>;
+		pinctrl-1 = <&P9_16_gpio_pin>;
+		pinctrl-2 = <&P9_16_gpio_pu_pin>;
+		pinctrl-3 = <&P9_16_gpio_pd_pin>;
+		pinctrl-4 = <&P9_16_pwm_pin>;
+	};
+
+	P9_17_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "i2c", "pwm";
+		pinctrl-0 = <&P9_17_default_pin>;
+		pinctrl-1 = <&P9_17_gpio_pin>;
+		pinctrl-2 = <&P9_17_gpio_pu_pin>;
+		pinctrl-3 = <&P9_17_gpio_pd_pin>;
+		pinctrl-4 = <&P9_17_spi_pin>;
+		pinctrl-5 = <&P9_17_i2c_pin>;
+		pinctrl-6 = <&P9_17_pwm_pin>;
+	};
+
+	P9_18_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "i2c", "pwm";
+		pinctrl-0 = <&P9_18_default_pin>;
+		pinctrl-1 = <&P9_18_gpio_pin>;
+		pinctrl-2 = <&P9_18_gpio_pu_pin>;
+		pinctrl-3 = <&P9_18_gpio_pd_pin>;
+		pinctrl-4 = <&P9_18_spi_pin>;
+		pinctrl-5 = <&P9_18_i2c_pin>;
+		pinctrl-6 = <&P9_18_pwm_pin>;
+	};
+
+	P9_19_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "can", "i2c";
+		pinctrl-0 = <&P9_19_default_pin>;
+		pinctrl-1 = <&P9_19_gpio_pin>;
+		pinctrl-2 = <&P9_19_gpio_pu_pin>;
+		pinctrl-3 = <&P9_19_gpio_pd_pin>;
+		pinctrl-4 = <&P9_19_can_pin>;
+		pinctrl-5 = <&P9_19_i2c_pin>;
+	};
+
+	P9_20_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "can", "i2c";
+		pinctrl-0 = <&P9_20_default_pin>;
+		pinctrl-1 = <&P9_20_gpio_pin>;
+		pinctrl-2 = <&P9_20_gpio_pu_pin>;
+		pinctrl-3 = <&P9_20_gpio_pd_pin>;
+		pinctrl-4 = <&P9_20_can_pin>;
+		pinctrl-5 = <&P9_20_i2c_pin>;
+	};
+
+	P9_21_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm";
+		pinctrl-0 = <&P9_21_default_pin>;
+		pinctrl-1 = <&P9_21_gpio_pin>;
+		pinctrl-2 = <&P9_21_gpio_pu_pin>;
+		pinctrl-3 = <&P9_21_gpio_pd_pin>;
+		pinctrl-4 = <&P9_21_spi_pin>;
+		pinctrl-5 = <&P9_21_uart_pin>;
+		pinctrl-6 = <&P9_21_i2c_pin>;
+		pinctrl-7 = <&P9_21_pwm_pin>;
+	};
+
+	P9_22_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "spi", "uart", "i2c", "pwm";
+		pinctrl-0 = <&P9_22_default_pin>;
+		pinctrl-1 = <&P9_22_gpio_pin>;
+		pinctrl-2 = <&P9_22_gpio_pu_pin>;
+		pinctrl-3 = <&P9_22_gpio_pd_pin>;
+		pinctrl-4 = <&P9_22_spi_pin>;
+		pinctrl-5 = <&P9_22_uart_pin>;
+		pinctrl-6 = <&P9_22_i2c_pin>;
+		pinctrl-7 = <&P9_22_pwm_pin>;
+	};
+
+	P9_23_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm";
+		pinctrl-0 = <&P9_23_default_pin>;
+		pinctrl-1 = <&P9_23_gpio_pin>;
+		pinctrl-2 = <&P9_23_gpio_pu_pin>;
+		pinctrl-3 = <&P9_23_gpio_pd_pin>;
+		pinctrl-4 = <&P9_23_pwm_pin>;
+	};
+
+	P9_24_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pruin";
+		pinctrl-0 = <&P9_24_default_pin>;
+		pinctrl-1 = <&P9_24_gpio_pin>;
+		pinctrl-2 = <&P9_24_gpio_pu_pin>;
+		pinctrl-3 = <&P9_24_gpio_pd_pin>;
+		pinctrl-4 = <&P9_24_uart_pin>;
+		pinctrl-5 = <&P9_24_can_pin>;
+		pinctrl-6 = <&P9_24_i2c_pin>;
+		pinctrl-7 = <&P9_24_pruin_pin>;
+	};
+
+	P9_25_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "qep", "pruout", "pruin", "audio";
+		pinctrl-0 = <&P9_25_default_pin>;
+		pinctrl-1 = <&P9_25_gpio_pin>;
+		pinctrl-2 = <&P9_25_gpio_pu_pin>;
+		pinctrl-3 = <&P9_25_gpio_pd_pin>;
+		pinctrl-4 = <&P9_25_qep_pin>;
+		pinctrl-5 = <&P9_25_pruout_pin>;
+		pinctrl-6 = <&P9_25_pruin_pin>;
+		pinctrl-7 = <&P9_25_audio_pin>;
+	};
+
+	P9_26_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "uart", "can", "i2c", "pruin";
+		pinctrl-0 = <&P9_26_default_pin>;
+		pinctrl-1 = <&P9_26_gpio_pin>;
+		pinctrl-2 = <&P9_26_gpio_pu_pin>;
+		pinctrl-3 = <&P9_26_gpio_pd_pin>;
+		pinctrl-4 = <&P9_26_uart_pin>;
+		pinctrl-5 = <&P9_26_can_pin>;
+		pinctrl-6 = <&P9_26_i2c_pin>;
+		pinctrl-7 = <&P9_26_pruin_pin>;
+	};
+
+	P9_27_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "qep", "pruout", "pruin";
+		pinctrl-0 = <&P9_27_default_pin>;
+		pinctrl-1 = <&P9_27_gpio_pin>;
+		pinctrl-2 = <&P9_27_gpio_pu_pin>;
+		pinctrl-3 = <&P9_27_gpio_pd_pin>;
+		pinctrl-4 = <&P9_27_qep_pin>;
+		pinctrl-5 = <&P9_27_pruout_pin>;
+		pinctrl-6 = <&P9_27_pruin_pin>;
+	};
+
+	P9_28_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pwm2", "pruout", "pruin", "audio";
+		pinctrl-0 = <&P9_28_default_pin>;
+		pinctrl-1 = <&P9_28_gpio_pin>;
+		pinctrl-2 = <&P9_28_gpio_pu_pin>;
+		pinctrl-3 = <&P9_28_gpio_pd_pin>;
+		pinctrl-4 = <&P9_28_pwm_pin>;
+		pinctrl-5 = <&P9_28_spi_pin>;
+		pinctrl-6 = <&P9_28_pwm2_pin>;
+		pinctrl-7 = <&P9_28_pruout_pin>;
+		pinctrl-8 = <&P9_28_pruin_pin>;
+		pinctrl-9 = <&P9_28_audio_pin>;
+	};
+
+	P9_29_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin", "audio";
+		pinctrl-0 = <&P9_29_default_pin>;
+		pinctrl-1 = <&P9_29_gpio_pin>;
+		pinctrl-2 = <&P9_29_gpio_pu_pin>;
+		pinctrl-3 = <&P9_29_gpio_pd_pin>;
+		pinctrl-4 = <&P9_29_pwm_pin>;
+		pinctrl-5 = <&P9_29_spi_pin>;
+		pinctrl-6 = <&P9_29_pruout_pin>;
+		pinctrl-7 = <&P9_29_pruin_pin>;
+		pinctrl-8 = <&P9_29_audio_pin>;
+	};
+
+	P9_30_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin";
+		pinctrl-0 = <&P9_30_default_pin>;
+		pinctrl-1 = <&P9_30_gpio_pin>;
+		pinctrl-2 = <&P9_30_gpio_pu_pin>;
+		pinctrl-3 = <&P9_30_gpio_pd_pin>;
+		pinctrl-4 = <&P9_30_pwm_pin>;
+		pinctrl-5 = <&P9_30_spi_pin>;
+		pinctrl-6 = <&P9_30_pruout_pin>;
+		pinctrl-7 = <&P9_30_pruin_pin>;
+	};
+
+	P9_31_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "spi", "pruout", "pruin", "audio";
+		pinctrl-0 = <&P9_31_default_pin>;
+		pinctrl-1 = <&P9_31_gpio_pin>;
+		pinctrl-2 = <&P9_31_gpio_pu_pin>;
+		pinctrl-3 = <&P9_31_gpio_pd_pin>;
+		pinctrl-4 = <&P9_31_pwm_pin>;
+		pinctrl-5 = <&P9_31_spi_pin>;
+		pinctrl-6 = <&P9_31_pruout_pin>;
+		pinctrl-7 = <&P9_31_pruin_pin>;
+		pinctrl-8 = <&P9_31_audio_pin>;
+	};
+
+	P9_41_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "timer", "pruin";
+		pinctrl-0 = <&P9_41_default_pin>;
+		pinctrl-1 = <&P9_41_gpio_pin>;
+		pinctrl-2 = <&P9_41_gpio_pu_pin>;
+		pinctrl-3 = <&P9_41_gpio_pd_pin>;
+		pinctrl-4 = <&P9_41_timer_pin>;
+		pinctrl-5 = <&P9_41_pruin_pin>;
+	};
+
+	P9_91_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "qep", "pruout", "pruin";
+		pinctrl-0 = <&P9_91_default_pin>;
+		pinctrl-1 = <&P9_91_gpio_pin>;
+		pinctrl-2 = <&P9_91_gpio_pu_pin>;
+		pinctrl-3 = <&P9_91_gpio_pd_pin>;
+		pinctrl-4 = <&P9_91_qep_pin>;
+		pinctrl-5 = <&P9_91_pruout_pin>;
+		pinctrl-6 = <&P9_91_pruin_pin>;
+	};
+
+	P9_42_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "pwm", "uart", "spics", "spiclk";
+		pinctrl-0 = <&P9_42_default_pin>;
+		pinctrl-1 = <&P9_42_gpio_pin>;
+		pinctrl-2 = <&P9_42_gpio_pu_pin>;
+		pinctrl-3 = <&P9_42_gpio_pd_pin>;
+		pinctrl-4 = <&P9_42_pwm_pin>;
+		pinctrl-5 = <&P9_42_uart_pin>;
+		pinctrl-6 = <&P9_42_spics_pin>;
+		pinctrl-7 = <&P9_42_spiclk_pin>;
+	};
+
+	P9_92_pinmux {
+		compatible = "bone-pinmux-helper";
+		status = "okay";
+		pinctrl-names = "default", "gpio", "gpio_pu", "gpio_pd", "qep", "pruout", "pruin";
+		pinctrl-0 = <&P9_92_default_pin>;
+		pinctrl-1 = <&P9_92_gpio_pin>;
+		pinctrl-2 = <&P9_92_gpio_pu_pin>;
+		pinctrl-3 = <&P9_92_gpio_pd_pin>;
+		pinctrl-4 = <&P9_92_qep_pin>;
+		pinctrl-5 = <&P9_92_pruout_pin>;
+		pinctrl-6 = <&P9_92_pruin_pin>;
+	};
+
+	cape-universal {
+		compatible = "gpio-of-helper";
+		status = "okay";
+		pinctrl-names = "default";
+		pinctrl-0 = <>;
+
+		P8_07 {
+			gpio-name = "P8_07";
+			gpio = <&gpio2 2 0>;
+			input;
+			dir-changeable;
+		};
+		P8_08 {
+			gpio-name = "P8_08";
+			gpio = <&gpio2 3 0>;
+			input;
+			dir-changeable;
+		};
+		P8_09 {
+			gpio-name = "P8_09";
+			gpio = <&gpio2 5 0>;
+			input;
+			dir-changeable;
+		};
+		P8_10 {
+			gpio-name = "P8_10";
+			gpio = <&gpio2 4 0>;
+			input;
+			dir-changeable;
+		};
+		P8_11 {
+			gpio-name = "P8_11";
+			gpio = <&gpio1 13 0>;
+			input;
+			dir-changeable;
+		};
+		P8_12 {
+			gpio-name = "P8_12";
+			gpio = <&gpio1 12 0>;
+			input;
+			dir-changeable;
+		};
+		P8_13 {
+			gpio-name = "P8_13";
+			gpio = <&gpio0 23 0>;
+			input;
+			dir-changeable;
+		};
+		P8_14 {
+			gpio-name = "P8_14";
+			gpio = <&gpio0 26 0>;
+			input;
+			dir-changeable;
+		};
+		P8_15 {
+			gpio-name = "P8_15";
+			gpio = <&gpio1 15 0>;
+			input;
+			dir-changeable;
+		};
+		P8_16 {
+			gpio-name = "P8_16";
+			gpio = <&gpio1 14 0>;
+			input;
+			dir-changeable;
+		};
+		P8_17 {
+			gpio-name = "P8_17";
+			gpio = <&gpio0 27 0>;
+			input;
+			dir-changeable;
+		};
+		P8_18 {
+			gpio-name = "P8_18";
+			gpio = <&gpio2 1 0>;
+			input;
+			dir-changeable;
+		};
+		P8_19 {
+			gpio-name = "P8_19";
+			gpio = <&gpio0 22 0>;
+			input;
+			dir-changeable;
+		};
+
+		P8_26 {
+			gpio-name = "P8_26";
+			gpio = <&gpio1 29 0>;
+			input;
+			dir-changeable;
+		};
+		P8_27 {
+			gpio-name = "P8_27";
+			gpio = <&gpio2 22 0>;
+			input;
+			dir-changeable;
+		};
+		P8_28 {
+			gpio-name = "P8_28";
+			gpio = <&gpio2 24 0>;
+			input;
+			dir-changeable;
+		};
+		P8_29 {
+			gpio-name = "P8_29";
+			gpio = <&gpio2 23 0>;
+			input;
+			dir-changeable;
+		};
+		P8_30 {
+			gpio-name = "P8_30";
+			gpio = <&gpio2 25 0>;
+			input;
+			dir-changeable;
+		};
+		P8_31 {
+			gpio-name = "P8_31";
+			gpio = <&gpio0 10 0>;
+			input;
+			dir-changeable;
+		};
+		P8_32 {
+			gpio-name = "P8_32";
+			gpio = <&gpio0 11 0>;
+			input;
+			dir-changeable;
+		};
+		P8_33 {
+			gpio-name = "P8_33";
+			gpio = <&gpio0 9 0>;
+			input;
+			dir-changeable;
+		};
+		P8_34 {
+			gpio-name = "P8_34";
+			gpio = <&gpio2 17 0>;
+			input;
+			dir-changeable;
+		};
+		P8_35 {
+			gpio-name = "P8_35";
+			gpio = <&gpio0 8 0>;
+			input;
+			dir-changeable;
+		};
+		P8_36 {
+			gpio-name = "P8_36";
+			gpio = <&gpio2 16 0>;
+			input;
+			dir-changeable;
+		};
+		P8_37 {
+			gpio-name = "P8_37";
+			gpio = <&gpio2 14 0>;
+			input;
+			dir-changeable;
+		};
+		P8_38 {
+			gpio-name = "P8_38";
+			gpio = <&gpio2 15 0>;
+			input;
+			dir-changeable;
+		};
+		P8_39 {
+			gpio-name = "P8_39";
+			gpio = <&gpio2 12 0>;
+			input;
+			dir-changeable;
+		};
+		P8_40 {
+			gpio-name = "P8_40";
+			gpio = <&gpio2 13 0>;
+			input;
+			dir-changeable;
+		};
+		P8_41 {
+			gpio-name = "P8_41";
+			gpio = <&gpio2 10 0>;
+			input;
+			dir-changeable;
+		};
+		P8_42 {
+			gpio-name = "P8_42";
+			gpio = <&gpio2 11 0>;
+			input;
+			dir-changeable;
+		};
+		P8_43 {
+			gpio-name = "P8_43";
+			gpio = <&gpio2 8 0>;
+			input;
+			dir-changeable;
+		};
+		P8_44 {
+			gpio-name = "P8_44";
+			gpio = <&gpio2 9 0>;
+			input;
+			dir-changeable;
+		};
+		P8_45 {
+			gpio-name = "P8_45";
+			gpio = <&gpio2 6 0>;
+			input;
+			dir-changeable;
+		};
+		P8_46 {
+			gpio-name = "P8_46";
+			gpio = <&gpio2 7 0>;
+			input;
+			dir-changeable;
+		};
+
+
+		P9_11 {
+			gpio-name = "P9_11";
+			gpio = <&gpio0 30 0>;
+			input;
+			dir-changeable;
+		};
+		P9_12 {
+			gpio-name = "P9_12";
+			gpio = <&gpio1 28 0>;
+			input;
+			dir-changeable;
+		};
+		P9_13 {
+			gpio-name = "P9_13";
+			gpio = <&gpio0 31 0>;
+			input;
+			dir-changeable;
+		};
+		P9_14 {
+			gpio-name = "P9_14";
+			gpio = <&gpio1 18 0>;
+			input;
+			dir-changeable;
+		};
+		P9_15 {
+			gpio-name = "P9_15";
+			gpio = <&gpio1 16 0>;
+			input;
+			dir-changeable;
+		};
+		P9_16 {
+			gpio-name = "P9_16";
+			gpio = <&gpio1 19 0>;
+			input;
+			dir-changeable;
+		};
+		P9_17 {
+			gpio-name = "P9_17";
+			gpio = <&gpio0 5 0>;
+			input;
+			dir-changeable;
+		};
+		P9_18 {
+			gpio-name = "P9_18";
+			gpio = <&gpio0 4 0>;
+			input;
+			dir-changeable;
+		};
+		P9_19 {
+			gpio-name = "P9_19";
+			gpio = <&gpio0 13 0>;
+			input;
+			dir-changeable;
+		};
+		P9_20 {
+			gpio-name = "P9_20";
+			gpio = <&gpio0 12 0>;
+			input;
+			dir-changeable;
+		};
+		P9_21 {
+			gpio-name = "P9_21";
+			gpio = <&gpio0 3 0>;
+			input;
+			dir-changeable;
+		};
+		P9_22 {
+			gpio-name = "P9_22";
+			gpio = <&gpio0 2 0>;
+			input;
+			dir-changeable;
+		};
+		P9_23 {
+			gpio-name = "P9_23";
+			gpio = <&gpio1 17 0>;
+			input;
+			dir-changeable;
+		};
+		P9_24 {
+			gpio-name = "P9_24";
+			gpio = <&gpio0 15 0>;
+			input;
+			dir-changeable;
+		};
+		P9_25 {
+			gpio-name = "P9_25";
+			gpio = <&gpio3 21 0>;
+			input;
+			dir-changeable;
+		};
+		P9_26 {
+			gpio-name = "P9_26";
+			gpio = <&gpio0 14 0>;
+			input;
+			dir-changeable;
+		};
+		P9_27 {
+			gpio-name = "P9_27";
+			gpio = <&gpio3 19 0>;
+			input;
+			dir-changeable;
+		};
+		P9_28 {
+			gpio-name = "P9_28";
+			gpio = <&gpio3 17 0>;
+			input;
+			dir-changeable;
+		};
+		P9_29 {
+			gpio-name = "P9_29";
+			gpio = <&gpio3 15 0>;
+			input;
+			dir-changeable;
+		};
+		P9_30 {
+			gpio-name = "P9_30";
+			gpio = <&gpio3 16 0>;
+			input;
+			dir-changeable;
+		};
+		P9_31 {
+			gpio-name = "P9_31";
+			gpio = <&gpio3 14 0>;
+			input;
+			dir-changeable;
+		};
+		P9_41 {
+			gpio-name = "P9_41";
+			gpio = <&gpio0 20 0>;
+			input;
+			dir-changeable;
+		};
+		P9_91 {
+			gpio-name = "P9_91";
+			gpio = <&gpio3 20 0>;
+			input;
+			dir-changeable;
+		};
+		P9_42 {
+			gpio-name = "P9_42";
+			gpio = <&gpio0 7 0>;
+			input;
+			dir-changeable;
+		};
+		P9_92 {
+			gpio-name = "P9_92";
+			gpio = <&gpio3 18 0>;
+			input;
+			dir-changeable;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
index 0cc150b..b34f3bb 100644
--- a/arch/arm/boot/dts/am335x-bone-common.dtsi
+++ b/arch/arm/boot/dts/am335x-bone-common.dtsi
@@ -25,14 +25,14 @@
 		compatible = "gpio-leds";
 
 		led@2 {
-			label = "beaglebone:green:heartbeat";
+			label = "beaglebone:green:usr0";
 			gpios = <&gpio1 21 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "heartbeat";
 			default-state = "off";
 		};
 
 		led@3 {
-			label = "beaglebone:green:mmc0";
+			label = "beaglebone:green:usr1";
 			gpios = <&gpio1 22 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "mmc0";
 			default-state = "off";
@@ -62,9 +62,6 @@
 };
 
 &am33xx_pinmux {
-	pinctrl-names = "default";
-	pinctrl-0 = <&clkout2_pin>;
-
 	user_leds_s0: user_leds_s0 {
 		pinctrl-single,pins = <
 			AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_a5.gpio1_21 */
@@ -95,15 +92,11 @@
 		>;
 	};
 
-	clkout2_pin: pinmux_clkout2_pin {
-		pinctrl-single,pins = <
-			AM33XX_IOPAD(0x9b4, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr1.clkout2 */
-		>;
-	};
-
 	cpsw_default: cpsw_default {
 		pinctrl-single,pins = <
 			/* Slave 1 */
+			0x108 (PIN_INPUT | MUX_MODE0)		/* mii1_col.mii1_col */
+			0x10c (PIN_INPUT | MUX_MODE0)		/* mii1_crs.mii1_crs */
 			AM33XX_IOPAD(0x910, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxerr.mii1_rxerr */
 			AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txen.mii1_txen */
 			AM33XX_IOPAD(0x918, PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxdv.mii1_rxdv */
@@ -123,6 +116,8 @@
 	cpsw_sleep: cpsw_sleep {
 		pinctrl-single,pins = <
 			/* Slave 1 reset value */
+			0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7)
 			AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
 			AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
 			AM33XX_IOPAD(0x918, PIN_INPUT_PULLDOWN | MUX_MODE7)
@@ -308,6 +303,9 @@
 	 */
 	ti,pmic-shutdown-controller;
 
+	interrupt-parent = <&intc>;
+	interrupts = <7>;	/* NNMI */
+
 	regulators {
 		dcdc1_reg: regulator@0 {
 			regulator-name = "vdds_dpr";
@@ -359,15 +357,11 @@
 	phy-mode = "mii";
 };
 
-&cpsw_emac1 {
-	phy_id = <&davinci_mdio>, <1>;
-	phy-mode = "mii";
-};
-
 &mac {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&cpsw_default>;
 	pinctrl-1 = <&cpsw_sleep>;
+	slaves = <1>;
 	status = "okay";
 };
 
@@ -393,3 +387,32 @@
 &sham {
 	status = "okay";
 };
+
+&rtc {
+	system-power-controller;
+};
+
+/* the cape manager */
+/ {
+	bone_capemgr {
+		compatible = "ti,bone-capemgr";
+		status = "okay";
+
+		nvmem-cells = <&baseboard_data &cape0_data &cape1_data &cape2_data &cape3_data>;
+		nvmem-cell-names = "baseboard", "slot0", "slot1", "slot2", "slot3";
+		#slots = <4>;
+
+		/* map board revisions to compatible definitions */
+		baseboardmaps {
+			baseboard_beaglebone: board@0 {
+				board-name = "A335BONE";
+				compatible-name = "ti,beaglebone";
+			};
+
+			baseboard_beaglebone_black: board@1 {
+				board-name = "A335BNLT";
+				compatible-name = "ti,beaglebone-black";
+			};
+		};
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-bone-emmc-in-reset.dtsi b/arch/arm/boot/dts/am335x-bone-emmc-in-reset.dtsi
new file mode 100644
index 0000000..7d8f673
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-emmc-in-reset.dtsi
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+/* standard */
+
+&gpio1 {
+	emmc_rst {
+		gpio-hog;
+		gpios = <20 0>;
+		output-high;
+		line-name = "EMMC ResetN";
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-bone-jtag.dtsi b/arch/arm/boot/dts/am335x-bone-jtag.dtsi
new file mode 100644
index 0000000..a92db8e
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-jtag.dtsi
@@ -0,0 +1,20 @@
+/*
+ * Device Tree Source for bone jtag
+ *
+ * Copyright (C) 2015 Robert Nelson <robertcnelson@gmail.com>
+ *
+ * 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.
+ */
+
+&am33xx_pinmux {
+	pinctrl-names = "default";
+	pinctrl-0 = <&clkout2_pin>;
+
+	clkout2_pin: pinmux_clkout2_pin {
+		pinctrl-single,pins = <
+			0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* xdma_event_intr1.clkout2 */
+		>;
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-can0.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-can0.dtsi
new file mode 100644
index 0000000..0961216
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-can0.dtsi
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-can0.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P9_19_pinmux {
+ *		mode = "can";
+ *	};
+ *	P9_20_pinmux {
+ *		mode = "can";
+ *	};
+ *};
+ *
+ *&dcan0 {
+ *	pinctrl-0 = <>;
+ *};
+ *
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	dcan0_pins: pinmux_dcan0_pins {
+		pinctrl-single,pins = <
+			/* P9_20: uart1_ctsn.d_can0_tx */
+			BONE_P9_20 (PIN_OUTPUT_PULLUP | MUX_MODE2)
+			/* P9_19: uart1_rtsn.d_can0_rx */
+			BONE_P9_19 (PIN_INPUT_PULLUP | MUX_MODE2)
+		>;
+	};
+};
+
+&dcan0 {
+	pinctrl-0 = <&dcan0_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-can1.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-can1.dtsi
new file mode 100644
index 0000000..9e26413
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-can1.dtsi
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-can1.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P9_24_pinmux {
+ *		mode = "can";
+ *	};
+ *	P9_26_pinmux {
+ *		mode = "can";
+ *	};
+ *};
+ *
+ *&dcan1 {
+ *	pinctrl-0 = <>;
+ *};
+ *
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	dcan1_pins: pinmux_dcan1_pins {
+		pinctrl-single,pins = <
+			/* P9_26: uart1_rxd.d_can1_tx */
+			BONE_P9_26 (PIN_OUTPUT_PULLUP | MUX_MODE2)
+			/* P9_24: uart1_txd.d_can1_rx */
+			BONE_P9_24 (PIN_INPUT_PULLUP | MUX_MODE2)
+		>;
+	};
+};
+
+&dcan1 {
+	pinctrl-0 = <&dcan1_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-emmc.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-emmc.dtsi
new file mode 100644
index 0000000..22cf462
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-emmc.dtsi
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+/* Testing */
+/* lsblk */
+
+#include <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-emmc.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P8_21_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_20_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_25_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_24_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_05_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_06_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_23_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_22_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_03_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_04_pinmux {
+ *		state = "disabled";
+ *	};
+ *};
+ *
+ *&mmc2 {
+ *	pinctrl-0 = <>;
+ *};
+ *
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	emmc_pins: pinmux_emmc_pins {
+		pinctrl-single,pins = <
+			/* P8_21: gpmc_csn1.mmc1_clk */
+			BONE_P8_21 (PIN_INPUT_PULLUP | MUX_MODE2)
+			/* P8_20: gpmc_csn2.mmc1_cmd */
+			BONE_P8_20 (PIN_INPUT_PULLUP | MUX_MODE2)
+			/* P8_25: gpmc_ad0.mmc1_dat0 */
+			BONE_P8_25 (PIN_INPUT_PULLUP | MUX_MODE1)
+			/* P8_24: gpmc_ad1.mmc1_dat1 */
+			BONE_P8_24 (PIN_INPUT_PULLUP | MUX_MODE1)
+			/* P8_05: gpmc_ad2.mmc1_dat2 */
+			BONE_P8_05 (PIN_INPUT_PULLUP | MUX_MODE1)
+			/* P8_06: gpmc_ad3.mmc1_dat3 */
+			BONE_P8_06 (PIN_INPUT_PULLUP | MUX_MODE1)
+			/* P8_23: gpmc_ad4.mmc1_dat4 */
+			BONE_P8_23 (PIN_INPUT_PULLUP | MUX_MODE1)
+			/* P8_22: gpmc_ad5.mmc1_dat5 */
+			BONE_P8_22 (PIN_INPUT_PULLUP | MUX_MODE1)
+			/* P8_03: gpmc_ad6.mmc1_dat6 */
+			BONE_P8_03 (PIN_INPUT_PULLUP | MUX_MODE1)
+			/* P8_04: gpmc_ad7.mmc1_dat7 */
+			BONE_P8_04 (PIN_INPUT_PULLUP | MUX_MODE1)
+		>;
+	};
+};
+
+&mmc2 {
+	pinctrl-0 = <&emmc_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-i2c2.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-i2c2.dtsi
new file mode 100644
index 0000000..abf3b57
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-i2c2.dtsi
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-i2c2.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P9_19_pinmux {
+ *		mode = "i2c";
+ *	};
+ *	P9_20_pinmux {
+ *		mode = "i2c";
+ *	};
+ *};
+ *
+ *&dcan0 {
+ *	pinctrl-0 = <>;
+ *};
+ *
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	i2c2_pins: pinmux_i2c2_pins {
+		pinctrl-single,pins = <
+			/* P9_20: uart1_ctsn.i2c2_sda */
+			BONE_P9_20 (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3)
+			/* P9_19: uart1_rtsn.i2c2_scl */
+			BONE_P9_19 (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3)
+		>;
+	};
+};
+
+&i2c2 {
+	pinctrl-0 = <&i2c2_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-nxp-hdmi.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-nxp-hdmi.dtsi
new file mode 100644
index 0000000..5205fa0
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-nxp-hdmi.dtsi
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 "am335x-peripheral-nxp-hdmi.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P8_27_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_28_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_29_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_30_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_31_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_32_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_33_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_34_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_35_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_36_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_37_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_38_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_39_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_40_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_41_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_42_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_43_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_44_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_45_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_46_pinmux {
+ *		state = "disabled";
+ *	};
+ *};
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	nxp_hdmi_pins: pinmux_nxp_hdmi_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+			AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data0.lcd_data0 */
+			AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data1.lcd_data1 */
+			AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data2.lcd_data2 */
+			AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)		/* lcd_data3.lcd_data3 */
+			AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data4.lcd_data4 */
+			AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data5.lcd_data5 */
+			AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data6.lcd_data6 */
+			AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data7.lcd_data7 */
+			AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data8.lcd_data8 */
+			AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data9.lcd_data9 */
+			AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data10.lcd_data10 */
+			AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data11.lcd_data11 */
+			AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data12.lcd_data12 */
+			AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data13.lcd_data13 */
+			AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data14.lcd_data14 */
+			AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data15.lcd_data15 */
+			AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_vsync.lcd_vsync */
+			AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_hsync.lcd_hsync */
+			AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_pclk.lcd_pclk */
+			AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_ac_bias_en.lcd_ac_bias_en */
+		>;
+	};
+
+	nxp_hdmi_off_pins: nxp_hdmi_off_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+		>;
+	};
+};
+
+&i2c0 {
+	tda19988 {
+		pinctrl-names = "default", "off";
+		pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
+		pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-panel-1024x600-24bit.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-panel-1024x600-24bit.dtsi
new file mode 100644
index 0000000..65e5fbb
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-panel-1024x600-24bit.dtsi
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-panel-1024x600-24bit.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P8_27_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_28_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_29_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_30_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_31_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_32_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_33_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_34_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_35_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_36_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_37_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_38_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_39_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_40_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_41_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_42_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_43_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_44_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_45_pinmux {
+ *		state = "disabled";
+ *	};
+ *	P8_46_pinmux {
+ *		state = "disabled";
+ *	};
+ *};
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	lcd_24bit_pins: pinmux_lcd_24bit_pins {
+		pinctrl-single,pins = <
+
+			/* P8_45: lcd_data0.lcd_data0 */
+			BONE_P8_45 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_46: lcd_data1.lcd_data1 */
+			BONE_P8_46 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_43: lcd_data2.lcd_data2 */
+			BONE_P8_43 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_44: lcd_data3.lcd_data3 */
+			BONE_P8_44 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_41: lcd_data4.lcd_data4 */
+			BONE_P8_41 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_42: lcd_data5.lcd_data5 */
+			BONE_P8_42 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_39: lcd_data6.lcd_data6 */
+			BONE_P8_39 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_40: lcd_data7.lcd_data7 */
+			BONE_P8_40 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_37: lcd_data8.lcd_data8 */
+			BONE_P8_37 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_38: lcd_data9.lcd_data9 */
+			BONE_P8_38 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_36: lcd_data10.lcd_data10 */
+			BONE_P8_36 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_34: lcd_data11.lcd_data11 */
+			BONE_P8_34 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_35: lcd_data12.lcd_data12 */
+			BONE_P8_35 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_33: lcd_data13.lcd_data13 */
+			BONE_P8_33 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_31: lcd_data14.lcd_data14 */
+			BONE_P8_31 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_32: lcd_data15.lcd_data15 */
+			BONE_P8_32 (PIN_OUTPUT | MUX_MODE0)
+
+			/* gpmc_ad15.lcd_data16 */
+			BONE_P8_15 (PIN_OUTPUT | MUX_MODE1)
+			/* gpmc_ad14.lcd_data17 */
+			BONE_P8_16 (PIN_OUTPUT | MUX_MODE1)
+			/* gpmc_ad13.lcd_data18 */
+			BONE_P8_11 (PIN_OUTPUT | MUX_MODE1)
+			/* gpmc_ad12.lcd_data19 */
+			BONE_P8_12 (PIN_OUTPUT | MUX_MODE1)
+			/* gpmc_ad11.lcd_data20 */
+			BONE_P8_17 (PIN_OUTPUT | MUX_MODE1)
+			/* gpmc_ad10.lcd_data21 */
+			BONE_P8_14 (PIN_OUTPUT | MUX_MODE1)
+			/* gpmc_ad9.lcd_data22 */
+			BONE_P8_13 (PIN_OUTPUT | MUX_MODE1)
+			/* gpmc_ad8.lcd_data23 */
+			BONE_P8_19 (PIN_OUTPUT | MUX_MODE1)
+
+			/* P8_27: lcd_vsync.lcd_vsync */
+			BONE_P8_27 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_29: lcd_hsync.lcd_hsync */
+			BONE_P8_29 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_28: lcd_pclk.lcd_pclk*/
+			BONE_P8_28 (PIN_OUTPUT | MUX_MODE0)
+			/* P8_30: lcd_ac_bias_en.lcd_ac_bias_en */
+			BONE_P8_30 (PIN_OUTPUT | MUX_MODE0)
+		>;
+	};
+};
+
+/ {
+	panel {
+		pinctrl-0 = <&lcd_24bit_pins>;
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-spi0.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-spi0.dtsi
new file mode 100644
index 0000000..354e66a
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-spi0.dtsi
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-spi0.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P9_17_pinmux {
+ *		status = "disabled";
+ *	};
+ *	P9_18_pinmux {
+ *		status = "disabled";
+ *	};
+ *	P9_21_pinmux {
+ *		status = "disabled";
+ *	};
+ *	P9_22_pinmux {
+ *		status = "disabled";
+ *	};
+ *};
+ *
+ *&spi0 {
+ *	pinctrl-0 = <>;
+ *};
+ *
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	spi0_pins: pinmux_spi0_pins {
+		pinctrl-single,pins = <
+			0x150 (PIN_INPUT_PULLUP | MUX_MODE0)	/* spi0_sclk.spi0_sclk */
+			0x154 (PIN_INPUT_PULLUP | MUX_MODE0)	/* spi0_d0.spi0_d0 */
+			0x158 (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* spi0_d1.spi0_d1 */
+			0x15c (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* spi0_cs0.spi0_cs0 */
+		>;
+	};
+};
+
+&spi0 {
+	pinctrl-0 = <&spi0_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-spi1.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-spi1.dtsi
new file mode 100644
index 0000000..bff7f8d
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-spi1.dtsi
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-spi1.dtsi"
+
+/* standard */
+
+&am33xx_pinmux {
+	spi1_pins: pinmux_spi1_pins {
+		pinctrl-single,pins = <
+			0x190 0x33	/* mcasp0_aclkx.spi1_sclk, INPUT_PULLUP | MODE3 */
+			0x194 0x33	/* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */
+			0x198 0x13	/* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */
+			0x19c 0x13	/* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */
+			// 0x164 0x12	/* eCAP0_in_PWM0_out.spi1_cs1 OUTPUT_PULLUP | MODE2 */		>;
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-spi1a.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-spi1a.dtsi
new file mode 100644
index 0000000..62874c8
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-spi1a.dtsi
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-spi1.dtsi"
+
+/* standard */
+
+&am33xx_pinmux {
+	spi1a_pins: pinmux_spi1a_pins {
+		pinctrl-single,pins = <
+			0x164 0x34	/* eCAP0_in_PWM0_out.spi1_sclk, INPUT_PULLUP | MODE4 */
+					/* NOTE: P9.42 is connected to two pads */
+			// 0x1A0 0x27	/* set the other pad to gpio input */
+			0x194 0x33	/* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */
+			0x198 0x13	/* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */
+			0x178 0x14	/* uart1_ctsn.spi1_cs0, OUTPUT_PULLUP | MODE4 */		>;
+	};
+};
+
+&spi1 {
+	pinctrl-0 = <&spi1a_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS1.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS1.dtsi
new file mode 100644
index 0000000..ae5b813
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS1.dtsi
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+/* Testing */
+/* sudo /sbin/getty -L ttyS1 115200 vt102 */
+
+#include <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-ttyS1.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P9_24_pinmux {
+ *		mode = "uart";
+ *	};
+ *	P9_26_pinmux {
+ *		mode = "uart";
+ *	};
+ *};
+ *
+ *&uart1 {
+ *	pinctrl-0 = <>;
+ *};
+ *
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	uart1_pins: pinmux_uart1_pins {
+		pinctrl-single,pins = <
+			/* P9_24: uart1_txd.uart1_txd */
+			BONE_P9_24 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+			/* P9_26: uart1_rxd.uart1_rxd */
+			BONE_P9_26 (PIN_INPUT_PULLUP | MUX_MODE0)
+		>;
+	};
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS2.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS2.dtsi
new file mode 100644
index 0000000..5fa593a
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS2.dtsi
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+/* Testing */
+/* sudo /sbin/getty -L ttyS2 115200 vt102 */
+
+#include <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-ttyS2.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P9_21_pinmux {
+ *		mode = "uart";
+ *	};
+ *	P9_22_pinmux {
+ *		mode = "uart";
+ *	};
+ *};
+ *
+ *&uart2 {
+ *	pinctrl-0 = <>;
+ *};
+ *
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	uart2_pins: pinmux_uart2_pins {
+		pinctrl-single,pins = <
+			/* P9_21: spi0_d0.uart2_txd */
+			BONE_P9_21 (PIN_OUTPUT_PULLDOWN | MUX_MODE1)
+			/* P9_22: spi0_sclk.uart2_rxd */
+			BONE_P9_22 (PIN_INPUT_PULLUP | MUX_MODE1)
+		>;
+	};
+};
+
+&uart2 {
+	pinctrl-0 = <&uart2_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS4.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS4.dtsi
new file mode 100644
index 0000000..1d22a95
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS4.dtsi
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+/* Testing */
+/* sudo /sbin/getty -L ttyS4 115200 vt102 */
+
+#include <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-ttyS4.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P9_11_pinmux {
+ *		mode = "uart";
+ *	};
+ *	P9_13_pinmux {
+ *		mode = "uart";
+ *	};
+ *};
+ *
+ *&uart4 {
+ *	pinctrl-0 = <>;
+ *};
+ *
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	uart4_pins: pinmux_uart4_pins {
+		pinctrl-single,pins = <
+			/* P9_11: gpmc_wait0.uart4_rxd_mux2 */
+			BONE_P9_11 (PIN_INPUT_PULLUP | MUX_MODE6)
+			/* P9_13: gpmc_wpn.uart4_txd_mux2  */
+			BONE_P9_13 (PIN_OUTPUT_PULLDOWN | MUX_MODE6)
+		>;
+	};
+};
+
+&uart4 {
+	pinctrl-0 = <&uart4_pins>;
+};
diff --git b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS5.dtsi b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS5.dtsi
new file mode 100644
index 0000000..01d0aec
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bone-pinmux-ttyS5.dtsi
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+/* Testing */
+/* sudo /sbin/getty -L ttyS5 115200 vt102 */
+
+#include <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include "am335x-peripheral-ttyS5.dtsi"
+
+/* cape universal */
+
+/*
+ *&ocp {
+ *	P8_37_pinmux {
+ *		mode = "uart";
+ *	};
+ *	P8_38_pinmux {
+ *		mode = "uart";
+ *	};
+ *};
+ *
+ *&uart5 {
+ *	pinctrl-0 = <>;
+ *};
+ *
+ */
+
+/* standard */
+
+&am33xx_pinmux {
+	uart5_pins: pinmux_uart5_pins {
+		pinctrl-single,pins = <
+			/* P8_38: lcd_data9.uart5_rxd */
+			BONE_P8_38 (PIN_INPUT_PULLUP | MUX_MODE4)
+			/* P8_37: lcd_data8.uart5_txd */
+			BONE_P8_37 (PIN_OUTPUT_PULLDOWN | MUX_MODE4)
+		>;
+	};
+};
+
+&uart5 {
+	pinctrl-0 = <&uart5_pins>;
+};
diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
index 6b84937..b195b9e 100644
--- a/arch/arm/boot/dts/am335x-bone.dts
+++ b/arch/arm/boot/dts/am335x-bone.dts
@@ -9,6 +9,7 @@
 
 #include "am33xx.dtsi"
 #include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
 
 / {
 	model = "TI AM335x BeagleBone";
diff --git b/arch/arm/boot/dts/am335x-boneblack-audio.dts b/arch/arm/boot/dts/am335x-boneblack-audio.dts
new file mode 100644
index 0000000..1c5299c
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-audio.dts
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+
+	clk_mcasp0_fixed: clk_mcasp0_fixed {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <24576000>;
+	};
+
+	clk_mcasp0: clk_mcasp0 {
+		#clock-cells = <0>;
+		compatible = "gpio-gate-clock";
+		clocks = <&clk_mcasp0_fixed>;
+		enable-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>; /* BeagleBone Black Clk enable on GPIO1_27 */
+	};
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
diff --git b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-c.dts b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-c.dts
new file mode 100644
index 0000000..f5ec278
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-c.dts
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common-no-capemgr.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+	vmmc-supply = <&vmmcsd_fixed>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_pins>;
+	bus-width = <8>;
+	status = "okay";
+};
+
+#include "am335x-cape-bbb-exp-c.dtsi"
diff --git b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-r.dts b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-r.dts
new file mode 100644
index 0000000..27b3b72
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-bbb-exp-r.dts
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common-no-capemgr.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+	vmmc-supply = <&vmmcsd_fixed>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_pins>;
+	bus-width = <8>;
+	status = "okay";
+};
+
+#include "am335x-cape-bbb-exp-r.dtsi"
diff --git b/arch/arm/boot/dts/am335x-boneblack-bbbmini.dts b/arch/arm/boot/dts/am335x-boneblack-bbbmini.dts
new file mode 100644
index 0000000..8e41afc
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-bbbmini.dts
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *                    Modified by Mirko Denecke <mirkix@gmail.com>
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+
+#include <dt-bindings/board/am335x-bbw-bbb-base.h>
+#include <dt-bindings/pinctrl/am33xx.h>
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+	vmmc-supply = <&vmmcsd_fixed>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_pins>;
+	bus-width = <8>;
+	status = "okay";
+};
+
+&am33xx_pinmux {
+	dcan1_pins: pinmux_dcan1_pins {
+		pinctrl-single,pins = <
+			/* P9_26: uart1_rxd.d_can1_tx */
+			BONE_P9_26 (PIN_OUTPUT_PULLUP | MUX_MODE2)
+			/* P9_24: uart1_txd.d_can1_rx */
+			BONE_P9_24 (PIN_INPUT_PULLUP | MUX_MODE2)
+		>;
+	};
+
+	pru_pins: pinmux_pru_pins {
+		pinctrl-single,pins = <
+			0x03c 0x35	/* ecap0_in_pwm0_out.pr1_ecap0_ecap_capin, MODE5 | INPUT_PULLUP | PRU, PPM-sum, SBUS, DSM  */
+
+			0x0e8 0x25	/* lcd_pclk.pr1_pru1_pru_r30_10, MODE5 | OUTPUT | PRU, CH_1 */
+			0x0e0 0x25	/* lcd_vsync.pr1_pru1_pru_r30_8, MODE5 | OUTPUT | PRU, CH_2 */
+			0x0ec 0x25	/* lcd_ac_bias_en.pr1_pru1_pru_r30_11, MODE5 | OUTPUT | PRU, CH_3 */
+			0x0e4 0x25	/* lcd_hsync.pr1_pru1_pru_r30_9, MODE5 | OUTPUT | PRU, CH_4 */
+			0x0bc 0x25	/* lcd_data7.pr1_pru1_pru_r30_7, MODE5 | OUTPUT | PRU, CH_5 */
+			0x0b8 0x25	/* lcd_data6.pr1_pru1_pru_r30_6, MODE5 | OUTPUT | PRU, CH_6 */
+			0x0b4 0x25	/* lcd_data5.pr1_pru1_pru_r30_5, MODE5 | OUTPUT | PRU, CH_7 */
+			0x0b0 0x25	/* lcd_data4.pr1_pru1_pru_r30_4, MODE5 | OUTPUT | PRU, CH_8 */
+			0x0ac 0x25	/* lcd_data3.pr1_pru1_pru_r30_3, MODE5 | OUTPUT | PRU, CH_9 */
+			0x0a8 0x25	/* lcd_data2.pr1_pru1_pru_r30_2, MODE5 | OUTPUT | PRU, CH_10 */
+			0x0a4 0x25	/* lcd_data1.pr1_pru1_pru_r30_1, MODE5 | OUTPUT | PRU, CH_11 */
+			0x0a0 0x25	/* lcd_data0.pr1_pru1_pru_r30_0, MODE5 | OUTPUT | PRU, CH_12 */
+
+			BONE_P8_12 (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* HC-SR04 TRIG */
+			BONE_P8_16 (PIN_INPUT_PULLDOWN | MUX_MODE6) /* HC-SR04 ECHO */
+
+			BONE_P9_25 (PIN_INPUT_PULLDOWN | MUX_MODE6) /* MPU9250 INT */
+		>;
+	};
+
+	spi0_pins: pinmux_spi0_pins {
+		pinctrl-single,pins = <
+			/* P9_22: spi0_sclk.spi0_sclk */
+			BONE_P9_22 (PIN_INPUT_PULLUP | MUX_MODE0)
+			/* P9_21: spi0_d0.spi0_d0 */
+			BONE_P9_21 (PIN_INPUT_PULLUP | MUX_MODE0)
+			/* P9_18: spi0_d1.spi0_d1 */
+			BONE_P9_18 (PIN_OUTPUT_PULLUP | MUX_MODE0)
+			/* P9_17: spi0_cs0.spi0_cs0 */
+			BONE_P9_17 (PIN_OUTPUT_PULLUP | MUX_MODE0)
+		>;
+	};
+
+	spi1_pins: pinmux_spi1_pins {
+		pinctrl-single,pins = <
+			/* P9_31: mcasp0_aclkx.spi1_sclk */
+			BONE_P9_31 (PIN_INPUT_PULLUP | MUX_MODE3)
+
+			/* P9_29: mcasp0_fsx.spi1_d0 */
+			BONE_P9_29 (PIN_INPUT_PULLUP | MUX_MODE3)
+
+			/* P9_30: mcasp0_axr0.spi1_d1 */
+			BONE_P9_30 (PIN_OUTPUT_PULLUP | MUX_MODE3)
+
+			/* P9_28: mcasp0_ahclkr.spi1_cs0 */
+			BONE_P9_28 (PIN_OUTPUT_PULLUP | MUX_MODE3)
+
+			/* P9_19: uart1_rtsn.spi1_cs1 */
+/*			BONE_P9_19 (PIN_OUTPUT_PULLUP | MUX_MODE4)*/
+
+			/* P9_42: ecap0_in_pwm0_out.spi1_cs1 */
+			BONE_P9_42A (PIN_OUTPUT_PULLUP | MUX_MODE2)
+		>;
+	};
+
+	uart4_pins: pinmux_uart4_pins {
+		pinctrl-single,pins = <
+			/* P9_11: gpmc_wait0.uart4_rxd_mux2 */
+			BONE_P9_11 (PIN_INPUT_PULLUP | MUX_MODE6)
+			/* P9_13: gpmc_wpn.uart4_txd_mux2  */
+			BONE_P9_13 (PIN_OUTPUT_PULLDOWN | MUX_MODE6)
+		>;
+	};
+
+	uart5_pins: pinmux_uart5_pins {
+		pinctrl-single,pins = <
+			/* P8_38: lcd_data9.uart5_rxd */
+			BONE_P8_38 (PIN_INPUT_PULLUP | MUX_MODE4)
+			/* P8_37: lcd_data8.uart5_txd */
+			BONE_P8_37 (PIN_OUTPUT_PULLDOWN | MUX_MODE4)
+		>;
+	};
+};
+
+&dcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&dcan1_pins>;
+	status = "okay";
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins>;
+	status = "okay";
+
+	spi0_0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-max-frequency = <24000000>;
+		reg = <0>;
+		compatible = "spidev";
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi1_pins>;
+	status = "okay";
+
+	spi1_0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+		spi-max-frequency = <24000000>;
+		compatible = "spidev";
+	};
+
+	spi1_1 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <1>;
+		spi-max-frequency = <24000000>;
+		compatible = "spidev";
+	};
+};
+
+&tscadc {
+	adc {
+		ti,adc-channels = <0 1>;
+	};
+};
+
+&pruss {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pru_pins>;
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins>;
+	status = "okay";
+};
+
+&uart5 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart5_pins>;
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-boneblack-cape-bone-argus.dts b/arch/arm/boot/dts/am335x-boneblack-cape-bone-argus.dts
new file mode 100644
index 0000000..6f16d4c
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-cape-bone-argus.dts
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common-no-capemgr.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+	vmmc-supply = <&vmmcsd_fixed>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_pins>;
+	bus-width = <8>;
+	status = "okay";
+};
+
+&am33xx_pinmux {
+	nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+			AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data0.lcd_data0 */
+			AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data1.lcd_data1 */
+			AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data2.lcd_data2 */
+			AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)		/* lcd_data3.lcd_data3 */
+			AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data4.lcd_data4 */
+			AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data5.lcd_data5 */
+			AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data6.lcd_data6 */
+			AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data7.lcd_data7 */
+			AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data8.lcd_data8 */
+			AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data9.lcd_data9 */
+			AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data10.lcd_data10 */
+			AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data11.lcd_data11 */
+			AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data12.lcd_data12 */
+			AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data13.lcd_data13 */
+			AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data14.lcd_data14 */
+			AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data15.lcd_data15 */
+			AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_vsync.lcd_vsync */
+			AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_hsync.lcd_hsync */
+			AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_pclk.lcd_pclk */
+			AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_ac_bias_en.lcd_ac_bias_en */
+		>;
+	};
+	nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+		>;
+	};
+};
+
+&lcdc {
+	status = "okay";
+	port {
+		lcdc_0: endpoint@0 {
+			remote-endpoint = <&hdmi_0>;
+		};
+	};
+};
+
+&i2c0 {
+	tda19988 {
+		compatible = "nxp,tda998x";
+		reg = <0x70>;
+		pinctrl-names = "default", "off";
+		pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
+		pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
+
+		port {
+			hdmi_0: endpoint@0 {
+				remote-endpoint = <&lcdc_0>;
+			};
+		};
+	};
+};
+
+#include "am335x-bone-argus.dtsi"
diff --git b/arch/arm/boot/dts/am335x-boneblack-emmc-overlay.dts b/arch/arm/boot/dts/am335x-boneblack-emmc-overlay.dts
new file mode 100644
index 0000000..68ae67c
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-emmc-overlay.dts
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+	vmmc-supply = <&vmmcsd_fixed>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_pins>;
+	bus-width = <8>;
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-boneblack-hdmi-overlay.dts b/arch/arm/boot/dts/am335x-boneblack-hdmi-overlay.dts
new file mode 100644
index 0000000..6d419f7
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-hdmi-overlay.dts
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+/* EMMC in reset */
+&gpio1 {
+	emmc_rst {
+		gpio-hog;
+		gpios = <20 0>;
+		output-high;
+		line-name = "EMMC ResetN";
+	};
+};
+
+&am33xx_pinmux {
+	nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+			AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data0.lcd_data0 */
+			AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data1.lcd_data1 */
+			AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data2.lcd_data2 */
+			AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)		/* lcd_data3.lcd_data3 */
+			AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data4.lcd_data4 */
+			AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data5.lcd_data5 */
+			AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data6.lcd_data6 */
+			AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data7.lcd_data7 */
+			AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data8.lcd_data8 */
+			AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data9.lcd_data9 */
+			AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data10.lcd_data10 */
+			AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data11.lcd_data11 */
+			AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data12.lcd_data12 */
+			AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data13.lcd_data13 */
+			AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data14.lcd_data14 */
+			AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data15.lcd_data15 */
+			AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_vsync.lcd_vsync */
+			AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_hsync.lcd_hsync */
+			AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_pclk.lcd_pclk */
+			AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_ac_bias_en.lcd_ac_bias_en */
+		>;
+	};
+	nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+		>;
+	};
+};
+
+&lcdc {
+	status = "okay";
+	port {
+		lcdc_0: endpoint@0 {
+			remote-endpoint = <&hdmi_0>;
+		};
+	};
+};
+
+&i2c0 {
+	tda19988 {
+		compatible = "nxp,tda998x";
+		reg = <0x70>;
+		pinctrl-names = "default", "off";
+		pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
+		pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
+
+		port {
+			hdmi_0: endpoint@0 {
+				remote-endpoint = <&lcdc_0>;
+			};
+		};
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-boneblack-nhdmi-overlay.dts b/arch/arm/boot/dts/am335x-boneblack-nhdmi-overlay.dts
new file mode 100644
index 0000000..6d419f7
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-nhdmi-overlay.dts
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+/* EMMC in reset */
+&gpio1 {
+	emmc_rst {
+		gpio-hog;
+		gpios = <20 0>;
+		output-high;
+		line-name = "EMMC ResetN";
+	};
+};
+
+&am33xx_pinmux {
+	nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+			AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data0.lcd_data0 */
+			AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data1.lcd_data1 */
+			AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data2.lcd_data2 */
+			AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0)		/* lcd_data3.lcd_data3 */
+			AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data4.lcd_data4 */
+			AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data5.lcd_data5 */
+			AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data6.lcd_data6 */
+			AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data7.lcd_data7 */
+			AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data8.lcd_data8 */
+			AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data9.lcd_data9 */
+			AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data10.lcd_data10 */
+			AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data11.lcd_data11 */
+			AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0)		/* lcd_data12.lcd_data12 */
+			AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0)		/* lcd_data13.lcd_data13 */
+			AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0)		/* lcd_data14.lcd_data14 */
+			AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0)		/* lcd_data15.lcd_data15 */
+			AM33XX_IOPAD(0x8e0, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_vsync.lcd_vsync */
+			AM33XX_IOPAD(0x8e4, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_hsync.lcd_hsync */
+			AM33XX_IOPAD(0x8e8, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_pclk.lcd_pclk */
+			AM33XX_IOPAD(0x8ec, PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* lcd_ac_bias_en.lcd_ac_bias_en */
+		>;
+	};
+	nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
+		pinctrl-single,pins = <
+			AM33XX_IOPAD(0x9b0, PIN_OUTPUT_PULLDOWN | MUX_MODE3)	/* xdma_event_intr0 */
+		>;
+	};
+};
+
+&lcdc {
+	status = "okay";
+	port {
+		lcdc_0: endpoint@0 {
+			remote-endpoint = <&hdmi_0>;
+		};
+	};
+};
+
+&i2c0 {
+	tda19988 {
+		compatible = "nxp,tda998x";
+		reg = <0x70>;
+		pinctrl-names = "default", "off";
+		pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
+		pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
+
+		port {
+			hdmi_0: endpoint@0 {
+				remote-endpoint = <&lcdc_0>;
+			};
+		};
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-boneblack-overlay.dts b/arch/arm/boot/dts/am335x-boneblack-overlay.dts
new file mode 100644
index 0000000..d8051b6
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-overlay.dts
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+/* EMMC in reset */
+&gpio1 {
+	emmc_rst {
+		gpio-hog;
+		gpios = <20 0>;
+		output-high;
+		line-name = "EMMC ResetN";
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-boneblack-wl1835mod-cape.dtsi b/arch/arm/boot/dts/am335x-boneblack-wl1835mod-cape.dtsi
new file mode 100644
index 0000000..94caa22
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-wl1835mod-cape.dtsi
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	wlan_en_reg: fixedregulator@2 {
+		compatible = "regulator-fixed";
+		regulator-name = "wlan-en-regulator";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+
+		/* WL_EN */
+		gpio = <&gpio0 26 0>;
+		enable-active-high;
+	};
+
+	kim {
+	        compatible = "kim";
+	        nshutdown_gpio = <44>; /* Bank1, pin12 */
+	        dev_name = "/dev/ttyO4";
+	        flow_cntrl = <1>;
+	        baud_rate = <3000000>;
+	};
+
+	btwilink {
+	        compatible = "btwilink";
+	};
+};
+
+&am33xx_pinmux {
+	bt_pins: pinmux_bt_pins {
+		pinctrl-single,pins = <
+			0x30 (PIN_OUTPUT_PULLUP | MUX_MODE7)	/* gpmc_ad12.gpio1_12 */
+		>;
+	};
+
+	mmc2_pins: pinmux_mmc2_pins {
+		pinctrl-single,pins = <
+			0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+			0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+			0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+			0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+			0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+			0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+		>;
+	};
+
+	mmc2_pins_sleep: pinmux_mmc2_pins_sleep {
+		pinctrl-single,pins = <
+			0x80 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn1.mmc1_clk */
+			0x84 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn2.mmc1_cmd */
+			0x00 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad0.mmc1_dat0 */
+			0x04 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad1.mmc1_dat1 */
+			0x08 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad2.mmc1_dat2 */
+			0x0c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad3.mmc1_dat3 */
+		>;
+	};
+
+	/* wl18xx card enable/irq GPIOs. */
+	wlan_pins: pinmux_wlan_pins {
+		pinctrl-single,pins = <
+			0x28 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_ad10.gpio0_26 WL_EN*/
+			0x2C (PIN_INPUT_PULLUP | MUX_MODE7)	/* gpmc_ad11.gpio0_27 WL_IRQ*/
+			0x7C (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* gpmc_csn0.gpio1_29 BF_EN*/
+		>;
+	};
+
+	/* wl18xx card enable/irq GPIOs. */
+	wlan_pins_sleep: pinmux_wlan_pins_sleep {
+		pinctrl-single,pins = <
+			0x28 (PIN_OUTPUT_PULLUP | MUX_MODE7)	/* gpmc_ad10.gpio0_26 WL_EN*/
+			0x2C (PIN_INPUT_PULLUP | MUX_MODE7)	/* gpmc_ad11.gpio0_27 WL_IRQ*/
+			0x7C (PIN_OUTPUT_PULLUP | MUX_MODE0)	/* gpmc_csn0.gpio1_29 BF_EN*/
+		>;
+	};
+
+	uart4_pins_default: pinmux_uart4_pins_default {
+		pinctrl-single,pins = <
+			0xD0 (PIN_INPUT | MUX_MODE6)		/* lcd_data12.uart4_cts */
+			0xD4 (PIN_OUTPUT_PULLDOWN | MUX_MODE6)	/* lcd_data13.uart4_rts */
+			0x70 (PIN_INPUT_PULLUP | MUX_MODE6)	/* gpmc_wait0.uart4_rxd */
+			0x74 (PIN_OUTPUT_PULLDOWN | MUX_MODE6)	/* gpmc_wpn.uart4_txd */
+		>;
+	};
+
+	uart4_pins_sleep: pinmux_uart4_pins_sleep {
+		pinctrl-single,pins = <
+			0xD0 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* lcd_data12.uart4_cts */
+			0xD4 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* lcd_data13.uart4_rts */
+			0x70 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* gpmc_wait0.uart4_rxd */
+			0x74 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* gpmc_wpn.uart4_txd */
+		>;
+	};
+};
+
+&mmc2 {
+	status = "okay";
+	vmmc-supply = <&wlan_en_reg>;
+	bus-width = <4>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&mmc2_pins &wlan_pins>;
+	pinctrl-1 = <&mmc2_pins_sleep &wlan_pins_sleep>;
+	ti,non-removable;
+	ti,needs-special-hs-handling;
+	cap-power-off-card;
+	keep-power-in-suspend;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+	wlcore: wlcore@0 {
+		compatible = "ti,wl1835";
+		reg = <2>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
+	};
+};
+
+&uart4 {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&uart4_pins_default>;
+	pinctrl-1 = <&uart4_pins_sleep>;
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-boneblack-wl1835mod.dts b/arch/arm/boot/dts/am335x-boneblack-wl1835mod.dts
new file mode 100644
index 0000000..ec953a9
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-boneblack-wl1835mod.dts
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common-no-capemgr.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Black";
+	compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+/* EMMC in reset */
+&gpio1 {
+	emmc_rst {
+		gpio-hog;
+		gpios = <20 0>;
+		output-high;
+		line-name = "EMMC ResetN";
+	};
+};
+
+#include "am335x-boneblack-wl1835mod-cape.dtsi"
diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts
index 55c0e95..11e4a16 100644
--- a/arch/arm/boot/dts/am335x-boneblack.dts
+++ b/arch/arm/boot/dts/am335x-boneblack.dts
@@ -8,7 +8,10 @@
 /dts-v1/;
 
 #include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
 #include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
+/* #include "am335x-bone-jtag.dtsi" */
 
 / {
 	model = "TI AM335x BeagleBone Black";
@@ -90,7 +93,3 @@
 		};
 	};
 };
-
-&rtc {
-	system-power-controller;
-};
diff --git b/arch/arm/boot/dts/am335x-bonegreen-overlay.dts b/arch/arm/boot/dts/am335x-bonegreen-overlay.dts
new file mode 100644
index 0000000..c4bb320
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bonegreen-overlay.dts
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Green";
+	compatible = "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+/* EMMC in reset */
+&gpio1 {
+	emmc_rst {
+		gpio-hog;
+		gpios = <20 0>;
+		output-high;
+		line-name = "EMMC ResetN";
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-bonegreen-wireless.dts b/arch/arm/boot/dts/am335x-bonegreen-wireless.dts
new file mode 100644
index 0000000..44c872d
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bonegreen-wireless.dts
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+#include "am335x-bonegreen-wl1835.dtsi"
+
+/ {
+	model = "TI AM335x BeagleBone Green Wireless";
+	compatible = "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+	vmmc-supply = <&vmmcsd_fixed>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_pins>;
+	bus-width = <8>;
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
+};
+
+&mmc3 {
+	status = "okay";
+};
+
+&mac {
+	status = "disabled";
+};
diff --git b/arch/arm/boot/dts/am335x-bonegreen-wl1835.dtsi b/arch/arm/boot/dts/am335x-bonegreen-wl1835.dtsi
new file mode 100644
index 0000000..f26b22f
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bonegreen-wl1835.dtsi
@@ -0,0 +1,125 @@
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	wlan_en_reg: fixedregulator@2 {
+		compatible = "regulator-fixed";
+		regulator-name = "wlan-en-regulator";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+
+		/* WL_EN */
+		gpio = <&gpio0 26 0>;
+		enable-active-high;
+	};
+
+	tibt {
+		compatible = "tibt";
+		nshutdown_gpio = <60>;
+		dev_name = "/dev/ttyS3";
+		flow_cntrl = <1>;
+		baud_rate = <3000000>;
+	};
+
+	btwilink {
+		compatible = "btwilink";
+	};
+};
+
+&am33xx_pinmux {
+	bt_pins: pinmux_bt_pins {
+		pinctrl-single,pins = <
+			0x78 (PIN_OUTPUT_PULLUP | MUX_MODE7)	/* gpmc_ad12.gpio1_28 BT_EN*/
+		>;
+	};
+
+	mmc3_pins: pinmux_mmc3_pins {
+		pinctrl-single,pins = <
+			0x8c ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio2_1 gpmc_clk.mmc2_clk */
+			0x88 ( PIN_INPUT_PULLUP | MUX_MODE3) /* gpio2_0 gpmc_csn3.mmc2_cmd */
+			0x30 ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio1_12 gpmc_ad12.mmc2_dat0 */
+			0x34 ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio1_13 gpmc_ad13.mmc2_dat1 */
+			0x38 ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio1_14 gpmc_ad14.mmc2_dat2 */
+			0x3c ( PIN_INPUT_PULLUP | MUX_MODE3 ) /* gpio1_15 gpmc_ad15.mmc2_dat3 */
+		>;
+	};
+
+	mmc3_pins_sleep: pinmux_mmc3_pins_sleep {
+		pinctrl-single,pins = <
+			0x8c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio2_1 gpmc_clk.mmc2_clk */
+			0x88 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio2_0 gpmc_csn3.mmc2_cmd */
+			0x30 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio1_12 gpmc_ad12.mmc2_dat0 */
+			0x34 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio1_13 gpmc_ad13.mmc2_dat1 */
+			0x38 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio1_14 gpmc_ad14.mmc2_dat2 */
+			0x3c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpio1_15 gpmc_ad15.mmc2_dat3 */
+		>;
+	};
+
+	/* wl18xx card enable/irq GPIOs. */
+	wlan_pins: pinmux_wlan_pins {
+		pinctrl-single,pins = <
+			0x28 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_ad10.gpio0_26 WL_EN*/
+			0x2C (PIN_INPUT_PULLUP | MUX_MODE7)	    /* gpmc_ad11.gpio0_27 WL_IRQ*/
+			0x7C  (PIN_OUTPUT_PULLUP   | MUX_MODE0) /* gpmc_csn0.gpio1_29 Cape_Buffer_EN*/
+		>;
+	};
+
+	/* wl18xx card enable/irq GPIOs. */
+	wlan_pins_sleep: pinmux_wlan_pins_sleep {
+		pinctrl-single,pins = <
+			0x28 (PIN_OUTPUT_PULLUP | MUX_MODE7)	/* gpmc_ad10.gpio0_26 WL_EN*/
+			0x2C (PIN_INPUT_PULLUP | MUX_MODE7)	    /* gpmc_ad11.gpio0_27 WL_IRQ*/
+			0x7C  (PIN_OUTPUT_PULLUP   | MUX_MODE0) /* gpmc_csn0.gpio1_29 Cape_Buffer_EN*/
+		>;
+	};
+
+	uart3_pins_default: pinmux_uart3_pins_default {
+		pinctrl-single,pins = <
+			0x134 ( PIN_INPUT_PULLUP | MUX_MODE1 ) 		/* (L17) gmii1_rxd3.uart3_rxd */
+			0x138 ( PIN_OUTPUT_PULLDOWN | MUX_MODE1 )	/* (L16) gmii1_rxd2.uart3_txd */
+			0x148 ( PIN_INPUT | MUX_MODE3 ) 			/* (M17) mdio_data.uart3_ctsn */
+			0x14c ( PIN_OUTPUT_PULLDOWN | MUX_MODE3 ) 	/* (M18) mdio_clk.uart3_rtsn */
+		>;
+	};
+
+	uart3_pins_sleep: pinmux_uart3_pins_sleep {
+		pinctrl-single,pins = <
+			0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* (L17) gmii1_rxd3.uart3_rxd */
+			0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* (L16) gmii1_rxd2.uart3_txd */
+			0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* (M17) mdio_data.uart3_ctsn */
+			0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* (M18) mdio_clk.uart3_rtsn */
+		>;
+	};
+};
+
+&mmc3 {
+	dmas = <&edma_xbar 12 0 1
+		&edma_xbar 13 0 2>;
+	dma-names = "tx", "rx";
+	status = "okay";
+	vmmc-supply = <&wlan_en_reg>;
+	bus-width = <4>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&mmc3_pins &wlan_pins>;
+	pinctrl-1 = <&mmc3_pins_sleep &wlan_pins_sleep>;
+	ti,non-removable;
+	ti,needs-special-hs-handling;
+	cap-power-off-card;
+	keep-power-in-suspend;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+	wlcore: wlcore@0 {
+		compatible = "ti,wl1835";
+		reg = <2>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <27 IRQ_TYPE_LEVEL_HIGH>;
+	};
+};
+
+&uart3 {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&uart3_pins_default>;
+	pinctrl-1 = <&uart3_pins_sleep>;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/am335x-bonegreen.dts b/arch/arm/boot/dts/am335x-bonegreen.dts
index dce3c86..ef2e6cd 100644
--- a/arch/arm/boot/dts/am335x-bonegreen.dts
+++ b/arch/arm/boot/dts/am335x-bonegreen.dts
@@ -8,7 +8,9 @@
 /dts-v1/;
 
 #include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
 #include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
 
 / {
 	model = "TI AM335x BeagleBone Green";
@@ -32,22 +34,3 @@
 	bus-width = <8>;
 	status = "okay";
 };
-
-&am33xx_pinmux {
-	uart2_pins: uart2_pins {
-		pinctrl-single,pins = <
-			AM33XX_IOPAD(0x950, PIN_INPUT | MUX_MODE1)	/* spi0_sclk.uart2_rxd */
-			AM33XX_IOPAD(0x954, PIN_OUTPUT | MUX_MODE1)	/* spi0_d0.uart2_txd */
-		>;
-	};
-};
-
-&uart2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart2_pins>;
-	status = "okay";
-};
-
-&rtc {
-	system-power-controller;
-};
diff --git b/arch/arm/boot/dts/am335x-cape-bbb-exp-c.dtsi b/arch/arm/boot/dts/am335x-cape-bbb-exp-c.dtsi
new file mode 100644
index 0000000..01f9cde
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-cape-bbb-exp-c.dtsi
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+
+#include "am335x-peripheral-can0.dtsi"
+#include "am335x-bone-pinmux-can0.dtsi"
+
+#include "am335x-peripheral-ttyS1.dtsi"
+#include "am335x-bone-pinmux-ttyS1.dtsi"
+
+#include "am335x-peripheral-ttyS2.dtsi"
+#include "am335x-bone-pinmux-ttyS2.dtsi"
+
+#include "am335x-peripheral-ttyS4.dtsi"
+#include "am335x-bone-pinmux-ttyS4.dtsi"
+
+&am33xx_pinmux {
+	user_leds_s1: user_leds_s1 {
+		pinctrl-single,pins = <
+			0x98 0x7	/* gpmc_wen.gpio2_4, OUTPUT | MODE7 */
+			0x9c 0x7	/* gpmc_ben0_cle.gpio2_5, OUTPUT | MODE7 */
+		>;
+	};
+
+	bb_lcd_pwm_backlight_pins: pinmux_bb_lcd_pwm_backlight_pins {
+		pinctrl-single,pins = <
+			BONE_P9_14 (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* gpmc_a2.ehrpwm1a */
+		>;
+	};
+
+	keymap3_pins: pinmux_keymap3_pins {
+		pinctrl-single,pins = <
+			0x040 0x2f	/* KEY_UP gpmc_a0.gpio1_16, INPUT | PULLDIS | MODE7 */
+			0x04c 0x2f	/* KEY_DOWN gpmc_a3.gpio1_19, INPUT | PULLDIS | MODE7 */
+			0x078 0x2f	/* KEY_RIGHT gpmc_ben1.gpio1_28, INPUT | PULLDIS | MODE7 */
+			0x164 0x2f	/* KEY_LEFT ecap0_in_pwm0_out.gpio0_7, INPUT | PULLDIS | MODE7 */
+			0x1a4 0x2f	/* KEY_ENTER mcasp0_fxr.gpio3_19, INPUT | PULLDIS | MODE7 */
+		>;
+	};
+
+	edt_ft5306_ts_pins: pinmux_edt_ft5306_ts_pins {
+		pinctrl-single,pins = <
+			/* CAP_TSC gpmc_a1.gpio1_17, INPUT | MODE7 */
+			BONE_P9_23 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	i2c1_pins: pinmux_i2c1_pins {
+		pinctrl-single,pins = <
+			/* spi0_d1.i2c1_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
+			BONE_P9_18 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)
+			/* spi0_cs0.i2c1_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
+			BONE_P9_17 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)
+		>;
+	};
+
+	mcasp0_pins: pinmux_mcasp0_pins {
+		pinctrl-single,pins = <
+			0x190 0x20      /* mcasp0_aclkx.mcasp0_aclkx, INPUT | MODE0 */
+			0x194 0x20      /* mcasp0_fsx.mcasp0_fsx, INPUT | MODE0 */
+			0x198 0x20      /* mcasp0_axr0.mcasp0_axr0, INPUT | MODE0 */
+			0x19c 0x22      /* mcasp0_ahclkr.mcasp0_axr2, INPUT | MODE2 */
+		>;
+	};
+};
+
+&epwmss1 {
+	status = "okay";
+};
+
+
+&ehrpwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&bb_lcd_pwm_backlight_pins>;
+	status = "okay";
+};
+
+&i2c1 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <400000>;
+
+	edt-ft5306@38 {
+		status = "okay";
+		compatible = "edt,edt-ft5306", "edt,edt-ft5x06";
+		pinctrl-names = "default";
+		pinctrl-0 = <&edt_ft5306_ts_pins>;
+
+		reg = <0x38>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <17 0>;
+
+		touchscreen-size-x = <1024>;
+		touchscreen-size-y = <600>;
+	};
+
+	tlv320aic3x: tlv320aic3x@1b {
+		compatible = "ti,tlv320aic3x";
+		reg = <0x1b>;
+		status = "okay";
+	};
+};
+
+&mcasp0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mcasp0_pins>;
+
+	status = "okay";
+
+	op-mode = <0>;          /* MCASP_IIS_MODE */
+	tdm-slots = <2>;
+	num-serializer = <16>;
+	serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
+		1 0 2 0
+		0 0 0 0
+		0 0 0 0
+		0 0 0 0
+	>;
+	tx-num-evt = <1>;
+	rx-num-evt = <1>;
+};
+
+/ {
+	backlight {
+		status = "okay";
+		compatible = "pwm-backlight";
+		pwms = <&ehrpwm1 0 50000 0>;
+		brightness-levels = <0 51 53 56 62 75 101 152 255>;
+		default-brightness-level = <8>;
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&keymap3_pins>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		button@1 {
+			debounce_interval = <50>;
+			linux,code = <105>;
+			label = "left";
+			gpios = <&gpio0 7 0x1>;
+			gpio-key,wakeup;
+			autorepeat;
+		};
+		button@2 {
+			debounce_interval = <50>;
+			linux,code = <106>;
+			label = "right";
+			gpios = <&gpio1 28 0x1>;
+			gpio-key,wakeup;
+			autorepeat;
+		};
+		button@3 {
+			debounce_interval = <50>;
+			linux,code = <103>;
+			label = "up";
+			gpios = <&gpio1 16 0x1>;
+			gpio-key,wakeup;
+			autorepeat;
+		};
+		button@4 {
+			debounce_interval = <50>;
+			linux,code = <108>;
+			label = "down";
+			gpios = <&gpio1 19 0x1>;
+			gpio-key,wakeup;
+			autorepeat;
+		};
+		button@5 {
+			debounce_interval = <50>;
+			linux,code = <28>;
+			label = "enter";
+			gpios = <&gpio3 19 0x1>;
+			gpio-key,wakeup;
+		};
+	};
+
+	gpio-leds-cape-lcd {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+
+		pinctrl-0 = <&user_leds_s1>;
+
+		lcd-led0 {
+			label = "lcd:green:usr0";
+			gpios = <&gpio2 4 0>;
+			linux,default-trigger = "heartbeat";
+			default-state = "off";
+		};
+
+		lcd-led1 {
+			label = "lcd:green:usr1";
+			gpios = <&gpio2 5 0>;
+			linux,default-trigger = "mmc0";
+			default-state = "off";
+		};
+	};
+
+	sound {
+		compatible = "ti,da830-evm-audio";
+		ti,model = "DA830 EVM";
+		ti,audio-codec = <&tlv320aic3x>;
+		ti,mcasp-controller = <&mcasp0>;
+		ti,codec-clock-rate = <12000000>;
+		ti,audio-routing =
+			"Headphone Jack",       "HPLOUT",
+			"Headphone Jack",       "HPROUT",
+			"MIC3L",                "Mic Jack",
+			"MIC3R",                "Mic Jack";
+	};
+};
+
+#include "am335x-peripheral-panel-1024x600-24bit.dtsi"
+#include "am335x-bone-pinmux-panel-1024x600-24bit.dtsi"
diff --git b/arch/arm/boot/dts/am335x-cape-bbb-exp-r.dtsi b/arch/arm/boot/dts/am335x-cape-bbb-exp-r.dtsi
new file mode 100644
index 0000000..539409c
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-cape-bbb-exp-r.dtsi
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+
+#include "am335x-peripheral-can0.dtsi"
+#include "am335x-bone-pinmux-can0.dtsi"
+
+#include "am335x-peripheral-ttyS1.dtsi"
+#include "am335x-bone-pinmux-ttyS1.dtsi"
+
+#include "am335x-peripheral-ttyS2.dtsi"
+#include "am335x-bone-pinmux-ttyS2.dtsi"
+
+#include "am335x-peripheral-ttyS4.dtsi"
+#include "am335x-bone-pinmux-ttyS4.dtsi"
+
+&am33xx_pinmux {
+	user_leds_s1: user_leds_s1 {
+		pinctrl-single,pins = <
+			0x98 0x7	/* gpmc_wen.gpio2_4, OUTPUT | MODE7 */
+			0x9c 0x7	/* gpmc_ben0_cle.gpio2_5, OUTPUT | MODE7 */
+		>;
+	};
+
+	bb_lcd_pwm_backlight_pins: pinmux_bb_lcd_pwm_backlight_pins {
+		pinctrl-single,pins = <
+			BONE_P9_14 (PIN_OUTPUT_PULLDOWN | MUX_MODE6) /* gpmc_a2.ehrpwm1a */
+		>;
+	};
+
+	keymap3_pins: pinmux_keymap3_pins {
+		pinctrl-single,pins = <
+			0x040 0x2f	/* KEY_UP gpmc_a0.gpio1_16, INPUT | PULLDIS | MODE7 */
+			0x04c 0x2f	/* KEY_DOWN gpmc_a3.gpio1_19, INPUT | PULLDIS | MODE7 */
+			0x078 0x2f	/* KEY_RIGHT gpmc_ben1.gpio1_28, INPUT | PULLDIS | MODE7 */
+			0x164 0x2f	/* KEY_LEFT ecap0_in_pwm0_out.gpio0_7, INPUT | PULLDIS | MODE7 */
+			0x1a4 0x2f	/* KEY_ENTER mcasp0_fxr.gpio3_19, INPUT | PULLDIS | MODE7 */
+		>;
+	};
+
+	i2c1_pins: pinmux_i2c1_pins {
+		pinctrl-single,pins = <
+			/* spi0_d1.i2c1_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
+			BONE_P9_18 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)
+			/* spi0_cs0.i2c1_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */
+			BONE_P9_17 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE2)
+		>;
+	};
+
+	mcasp0_pins: pinmux_mcasp0_pins {
+		pinctrl-single,pins = <
+			0x190 0x20      /* mcasp0_aclkx.mcasp0_aclkx, INPUT | MODE0 */
+			0x194 0x20      /* mcasp0_fsx.mcasp0_fsx, INPUT | MODE0 */
+			0x198 0x20      /* mcasp0_axr0.mcasp0_axr0, INPUT | MODE0 */
+			0x19c 0x22      /* mcasp0_ahclkr.mcasp0_axr2, INPUT | MODE2 */
+		>;
+	};
+};
+
+&epwmss1 {
+	status = "okay";
+};
+
+
+&ehrpwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&bb_lcd_pwm_backlight_pins>;
+	status = "okay";
+};
+
+&i2c1 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <400000>;
+
+	tlv320aic3x: tlv320aic3x@1b {
+		compatible = "ti,tlv320aic3x";
+		reg = <0x1b>;
+		status = "okay";
+	};
+};
+
+&mcasp0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mcasp0_pins>;
+
+	status = "okay";
+
+	op-mode = <0>;          /* MCASP_IIS_MODE */
+	tdm-slots = <2>;
+	num-serializer = <16>;
+	serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
+		1 0 2 0
+		0 0 0 0
+		0 0 0 0
+		0 0 0 0
+	>;
+	tx-num-evt = <1>;
+	rx-num-evt = <1>;
+};
+
+&tscadc {
+	status = "okay";
+	tsc {
+		ti,wires = <4>;
+		ti,x-plate-resistance = <200>;
+		ti,coordinate-readouts = <5>;
+		ti,wire-config = <0x00 0x11 0x22 0x33>;
+	};
+
+	adc {
+		ti,adc-channels = <4 5 6 7>;
+	};
+};
+
+/ {
+	backlight {
+		status = "okay";
+		compatible = "pwm-backlight";
+		pwms = <&ehrpwm1 0 50000 0>;
+		brightness-levels = <0 51 53 56 62 75 101 152 255>;
+		default-brightness-level = <8>;
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&keymap3_pins>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		button@1 {
+			debounce_interval = <50>;
+			linux,code = <105>;
+			label = "left";
+			gpios = <&gpio0 7 0x1>;
+			gpio-key,wakeup;
+			autorepeat;
+		};
+		button@2 {
+			debounce_interval = <50>;
+			linux,code = <106>;
+			label = "right";
+			gpios = <&gpio1 28 0x1>;
+			gpio-key,wakeup;
+			autorepeat;
+		};
+		button@3 {
+			debounce_interval = <50>;
+			linux,code = <103>;
+			label = "up";
+			gpios = <&gpio1 16 0x1>;
+			gpio-key,wakeup;
+			autorepeat;
+		};
+		button@4 {
+			debounce_interval = <50>;
+			linux,code = <108>;
+			label = "down";
+			gpios = <&gpio1 19 0x1>;
+			gpio-key,wakeup;
+			autorepeat;
+		};
+		button@5 {
+			debounce_interval = <50>;
+			linux,code = <28>;
+			label = "enter";
+			gpios = <&gpio3 19 0x1>;
+			gpio-key,wakeup;
+		};
+	};
+
+	gpio-leds-cape-lcd {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+
+		pinctrl-0 = <&user_leds_s1>;
+
+		lcd-led0 {
+			label = "lcd:green:usr0";
+			gpios = <&gpio2 4 0>;
+			linux,default-trigger = "heartbeat";
+			default-state = "off";
+		};
+
+		lcd-led1 {
+			label = "lcd:green:usr1";
+			gpios = <&gpio2 5 0>;
+			linux,default-trigger = "mmc0";
+			default-state = "off";
+		};
+	};
+
+	sound {
+		compatible = "ti,da830-evm-audio";
+		ti,model = "DA830 EVM";
+		ti,audio-codec = <&tlv320aic3x>;
+		ti,mcasp-controller = <&mcasp0>;
+		ti,codec-clock-rate = <12000000>;
+		ti,audio-routing =
+			"Headphone Jack",       "HPLOUT",
+			"Headphone Jack",       "HPROUT",
+			"MIC3L",                "Mic Jack",
+			"MIC3R",                "Mic Jack";
+	};
+};
+
+#include "am335x-peripheral-panel-1024x600-24bit.dtsi"
+#include "am335x-bone-pinmux-panel-1024x600-24bit.dtsi"
diff --git b/arch/arm/boot/dts/am335x-cape-rtc-ds1307.dtsi b/arch/arm/boot/dts/am335x-cape-rtc-ds1307.dtsi
new file mode 100644
index 0000000..bce6ac5
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-cape-rtc-ds1307.dtsi
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <dt-bindings/board/am335x-bbw-bbb-base.h>
+
+&am33xx_pinmux {
+	i2c2_pins: pinmux_i2c2_pins {
+		pinctrl-single,pins = <
+			BONE_P9_20 0x73 /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) uart1_ctsn.i2c2_sda */
+			BONE_P9_19 0x73 /* (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE3) uart1_rtsn.i2c2_scl */
+		>;
+	};
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+
+	status = "okay";
+	clock-frequency = <100000>;
+
+	rtc@68 {
+		compatible = "maxim,ds1307";
+		reg = <0x68>;
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-olimex-som.dts b/arch/arm/boot/dts/am335x-olimex-som.dts
new file mode 100644
index 0000000..2b00ad2
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-olimex-som.dts
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am335x-som-common.dtsi"
+
+/ {
+	model = "Olimex AM335x SOM";
+	compatible = "olimex,am335x-olimex-som", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&am33xx_pinmux {
+	lcd_pins_default: lcd_pins_default {
+		pinctrl-single,pins = <
+		0x20 0x01 /* gpmc_ad8.lcd_data16, OUTPUT | MODE1 */
+		0x24 0x01 /* gpmc_ad9.lcd_data17, OUTPUT | MODE1 */
+		0x28 0x01 /* gpmc_ad10.lcd_data18, OUTPUT | MODE1 */
+		0x2c 0x01 /* gpmc_ad11.lcd_data19, OUTPUT | MODE1 */
+		0x30 0x01 /* gpmc_ad12.lcd_data20, OUTPUT | MODE1 */
+		0x34 0x01 /* gpmc_ad13.lcd_data21, OUTPUT | MODE1 */
+		0x38 0x01 /* gpmc_ad14.lcd_data22, OUTPUT | MODE1 */
+		0x3c 0x01 /* gpmc_ad15.lcd_data23, OUTPUT | MODE1 */
+		0xa0 0x00 /* lcd_data0.lcd_data0, OUTPUT | MODE0 */
+		0xa4 0x00 /* lcd_data1.lcd_data1, OUTPUT | MODE0 */
+		0xa8 0x00 /* lcd_data2.lcd_data2, OUTPUT | MODE0 */
+		0xac 0x00 /* lcd_data3.lcd_data3, OUTPUT | MODE0 */
+		0xb0 0x00 /* lcd_data4.lcd_data4, OUTPUT | MODE0 */
+		0xb4 0x00 /* lcd_data5.lcd_data5, OUTPUT | MODE0 */
+		0xb8 0x00 /* lcd_data6.lcd_data6, OUTPUT | MODE0 */
+		0xbc 0x00 /* lcd_data7.lcd_data7, OUTPUT | MODE0 */
+		0xc0 0x00 /* lcd_data8.lcd_data8, OUTPUT | MODE0 */
+		0xc4 0x00 /* lcd_data9.lcd_data9, OUTPUT | MODE0 */
+		0xc8 0x00 /* lcd_data10.lcd_data10, OUTPUT | MODE0 */
+		0xcc 0x00 /* lcd_data11.lcd_data11, OUTPUT | MODE0 */
+		0xd0 0x00 /* lcd_data12.lcd_data12, OUTPUT | MODE0 */
+		0xd4 0x00 /* lcd_data13.lcd_data13, OUTPUT | MODE0 */
+		0xd8 0x00 /* lcd_data14.lcd_data14, OUTPUT | MODE0 */
+		0xdc 0x00 /* lcd_data15.lcd_data15, OUTPUT | MODE0 */
+		0xe0 0x00 /* lcd_vsync.lcd_vsync, OUTPUT | MODE0 */
+		0xe4 0x00 /* lcd_hsync.lcd_hsync, OUTPUT | MODE0 */
+		0xe8 0x00 /* lcd_pclk.lcd_pclk, OUTPUT | MODE0 */
+		0xec 0x00 /* lcd_ac_bias_en.lcd_ac_bias_en, OUTPUT | MODE0 */
+		>;
+	};
+
+	lcd_pins_sleep: lcd_pins_sleep {
+		pinctrl-single,pins = <
+		0x20 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad8.lcd_data16 */
+		0x24 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad9.lcd_data17 */
+		0x28 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad10.lcd_data18 */
+		0x2c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad11.lcd_data19 */
+		0x30 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad12.lcd_data20 */
+		0x34 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad13.lcd_data21 */
+		0x38 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad14.lcd_data22 */
+		0x3c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* gpmc_ad15.lcd_data23 */
+		0xa0 (PULL_DISABLE | MUX_MODE7) /* lcd_data0.lcd_data0 */
+		0xa4 (PULL_DISABLE | MUX_MODE7) /* lcd_data1.lcd_data1 */
+		0xa8 (PULL_DISABLE | MUX_MODE7) /* lcd_data2.lcd_data2 */
+		0xac (PULL_DISABLE | MUX_MODE7) /* lcd_data3.lcd_data3 */
+		0xb0 (PULL_DISABLE | MUX_MODE7) /* lcd_data4.lcd_data4 */
+		0xb4 (PULL_DISABLE | MUX_MODE7) /* lcd_data5.lcd_data5 */
+		0xb8 (PULL_DISABLE | MUX_MODE7) /* lcd_data6.lcd_data6 */
+		0xbc (PULL_DISABLE | MUX_MODE7) /* lcd_data7.lcd_data7 */
+		0xc0 (PULL_DISABLE | MUX_MODE7) /* lcd_data8.lcd_data8 */
+		0xc4 (PULL_DISABLE | MUX_MODE7) /* lcd_data9.lcd_data9 */
+		0xc8 (PULL_DISABLE | MUX_MODE7) /* lcd_data10.lcd_data10 */
+		0xcc (PULL_DISABLE | MUX_MODE7) /* lcd_data11.lcd_data11 */
+		0xd0 (PULL_DISABLE | MUX_MODE7) /* lcd_data12.lcd_data12 */
+		0xd4 (PULL_DISABLE | MUX_MODE7) /* lcd_data13.lcd_data13 */
+		0xd8 (PULL_DISABLE | MUX_MODE7) /* lcd_data14.lcd_data14 */
+		0xdc (PULL_DISABLE | MUX_MODE7) /* lcd_data15.lcd_data15 */
+		/* lcd_vsync.lcd_vsync,OUTPUT | MODE0 */
+		0xe0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		0xe4 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_hsync.lcd_hsync */
+		0xe8 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* lcd_pclk.lcd_pclk */
+		/* lcd_ac_bias_en.lcd_ac_bias_en */
+		0xec (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+};
+
+&lcdc {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&lcd_pins_default>;
+	pinctrl-1 = <&lcd_pins_sleep>;
+	status = "okay";
+	/*        display-timings {
+	 480x272 {
+	 hactive         = <480>;
+	 vactive         = <272>;
+	 hback-porch     = <43>;
+	 hfront-porch    = <8>;
+	 hsync-len       = <4>;
+	 vback-porch     = <12>;
+	 vfront-porch    = <4>;
+	 vsync-len       = <10>;
+	 clock-frequency = <9000000>;
+	 hsync-active    = <0>;
+	 vsync-active    = <0>;
+	 };
+	 };*/
+
+	display-timings {
+		native-mode = <&vga1024x768>;
+		lcd4: 480x272 {
+			clock-frequency = <9000000>;
+			hactive = <480>;
+			vactive = <272>;
+			hfront-porch = <3>;
+			hback-porch = <40>;
+			vback-porch = <8>;
+			vfront-porch = <7>;
+			hsync-len = <2>;
+			vsync-len = <1>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+		};
+		lcd7: 800x480 {
+			clock-frequency = <33300000>;
+			hactive = <800>;
+			vactive = <480>;
+			hfront-porch = <210>;
+			hback-porch = <40>;
+			vback-porch = <23>;
+			vfront-porch = <20>;
+			hsync-len = <6>;
+			vsync-len = <2>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+		};
+		lcd10: 1024x600 {
+			clock-frequency = <51200000>;
+			hactive = <1024>;
+			vactive = <600>;
+			hfront-porch = <160>;
+			hback-porch = <140>;
+			vback-porch = <20>;
+			vfront-porch = <12>;
+			hsync-len = <20>;
+			vsync-len = <3>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+		};
+
+		vga800x600: 800x600 {
+			clock-frequency = <40000000>;
+			hactive = <800>;
+			vactive = <600>;
+			hfront-porch = <40>;
+			hback-porch = <88>;
+			vfront-porch = <1>;
+			vback-porch = <23>;
+			hsync-len = <128>;
+			vsync-len = <4>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+		};
+		vga1024x768: 1024x768 {
+			clock-frequency = <65000000>;
+			hactive = <1024>;
+			hfront-porch = <24>;
+			hback-porch = <160>;
+			hsync-len = <136>;
+			vactive = <768>;
+			vfront-porch = <3>;
+			vback-porch = <29>;
+			vsync-len = <6>;
+			hsync-active = <0>;
+			vsync-active = <0>;
+		};
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-can0.dtsi b/arch/arm/boot/dts/am335x-peripheral-can0.dtsi
new file mode 100644
index 0000000..4335e39
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-can0.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&dcan0 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-can1.dtsi b/arch/arm/boot/dts/am335x-peripheral-can1.dtsi
new file mode 100644
index 0000000..02b5bd1
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-can1.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&dcan1 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-emmc.dtsi b/arch/arm/boot/dts/am335x-peripheral-emmc.dtsi
new file mode 100644
index 0000000..603f34e
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-emmc.dtsi
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&mmc2 {
+	vmmc-supply = <&vmmcsd_fixed>;
+	pinctrl-names = "default";
+
+	bus-width = <8>;
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-i2c2.dtsi b/arch/arm/boot/dts/am335x-peripheral-i2c2.dtsi
new file mode 100644
index 0000000..ed9a0b5
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-i2c2.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&i2c2 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-nxp-hdmi.dtsi b/arch/arm/boot/dts/am335x-peripheral-nxp-hdmi.dtsi
new file mode 100644
index 0000000..1dfd26a
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-nxp-hdmi.dtsi
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&lcdc {
+	status = "okay";
+	port {
+		lcdc_0: endpoint@0 {
+			remote-endpoint = <&hdmi_0>;
+		};
+	};
+};
+
+&i2c0 {
+	tda19988 {
+		compatible = "nxp,tda998x";
+		reg = <0x70>;
+
+		port {
+			hdmi_0: endpoint@0 {
+				remote-endpoint = <&lcdc_0>;
+			};
+		};
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-panel-1024x600-24bit.dtsi b/arch/arm/boot/dts/am335x-peripheral-panel-1024x600-24bit.dtsi
new file mode 100644
index 0000000..74ddc12
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-panel-1024x600-24bit.dtsi
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&lcdc {
+	status = "okay";
+};
+
+/ {
+	panel {
+		status = "okay";
+		compatible = "ti,tilcdc,panel";
+		pinctrl-names = "default";
+
+		panel-info {
+			ac-bias           = <255>;
+			ac-bias-intrpt    = <0>;
+			dma-burst-sz      = <16>;
+			bpp               = <32>;
+			fdd               = <0x80>;
+			sync-edge         = <0>;
+			sync-ctrl         = <0>;
+			raster-order      = <1>;
+			fifo-th           = <0>;
+		};
+		display-timings {
+			native-mode = <&timing0>;
+			timing0: 1024x600 {
+				clock-frequency = <36000000>;
+				hactive = <1024>;
+				vactive = <600>;
+				hfront-porch = <1>;
+				hback-porch = <45>;
+				hsync-len = <30>;
+				vback-porch = <22>;
+				vfront-porch = <12>;
+				vsync-len = <2>;
+				hsync-active = <1>;
+				vsync-active = <1>;
+				de-active = <1>;
+				pixelclk-active = <0>;
+			};
+		};
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-spi0.dtsi b/arch/arm/boot/dts/am335x-peripheral-spi0.dtsi
new file mode 100644
index 0000000..969e352
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-spi0.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&spi0 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-spi1.dtsi b/arch/arm/boot/dts/am335x-peripheral-spi1.dtsi
new file mode 100644
index 0000000..ac5fe97
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-spi1.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&spi1 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-spi1a.dtsi b/arch/arm/boot/dts/am335x-peripheral-spi1a.dtsi
new file mode 100644
index 0000000..ac5fe97
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-spi1a.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&spi1 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-ttyS1.dtsi b/arch/arm/boot/dts/am335x-peripheral-ttyS1.dtsi
new file mode 100644
index 0000000..f59fa4c
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-ttyS1.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&uart1 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-ttyS2.dtsi b/arch/arm/boot/dts/am335x-peripheral-ttyS2.dtsi
new file mode 100644
index 0000000..a25d6cf
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-ttyS2.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&uart2 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-ttyS4.dtsi b/arch/arm/boot/dts/am335x-peripheral-ttyS4.dtsi
new file mode 100644
index 0000000..adc89f0
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-ttyS4.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&uart4 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-peripheral-ttyS5.dtsi b/arch/arm/boot/dts/am335x-peripheral-ttyS5.dtsi
new file mode 100644
index 0000000..8b42fb0
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-peripheral-ttyS5.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+&uart5 {
+	pinctrl-names = "default";
+
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/am335x-sancloud-bbe.dts b/arch/arm/boot/dts/am335x-sancloud-bbe.dts
new file mode 100644
index 0000000..1212a53
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-sancloud-bbe.dts
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am33xx-es2.dtsi"
+#include "am335x-bone-common.dtsi"
+#include "am33xx-overlay-edma-fix.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	model = "SanCloud BeagleBone Enhanced";
+	compatible = "sancloud,am335x-boneenhanced", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+	regulator-min-microvolt = <1800000>;
+	regulator-max-microvolt = <1800000>;
+	regulator-always-on;
+};
+
+&mmc1 {
+	vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+	vmmc-supply = <&vmmcsd_fixed>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_pins>;
+	bus-width = <8>;
+	status = "okay";
+	ti,vcc-aux-disable-is-sleep;
+};
+
+&am33xx_pinmux {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usb_hub_ctrl>;
+
+	nxp_hdmi_bonelt_pins: nxp_hdmi_bonelt_pins {
+		pinctrl-single,pins = <
+			0x1b0 0x03      /* xdma_event_intr0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT */
+			0xa0 0x08       /* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xa4 0x08       /* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xa8 0x08       /* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xac 0x08       /* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xb0 0x08       /* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xb4 0x08       /* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xb8 0x08       /* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xbc 0x08       /* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xc0 0x08       /* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xc4 0x08       /* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xc8 0x08       /* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xcc 0x08       /* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xd0 0x08       /* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xd4 0x08       /* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xd8 0x08       /* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xdc 0x08       /* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+			0xe0 0x00       /* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+			0xe4 0x00       /* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+			0xe8 0x00       /* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+			0xec 0x00       /* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+		>;
+	};
+	nxp_hdmi_bonelt_off_pins: nxp_hdmi_bonelt_off_pins {
+		pinctrl-single,pins = <
+			0x1b0 0x03      /* xdma_event_intr0, OMAP_MUX_MODE3 | AM33XX_PIN_OUTPUT */
+		>;
+	};
+
+	cpsw_default: cpsw_default {
+		pinctrl-single,pins = <
+			/* Slave 1 */
+			0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txen.rgmii1_tctl */
+			0x118 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxdv.rgmii1_rctl */
+			0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd3.rgmii1_td3 */
+			0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd2.rgmii1_td2 */
+			0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd1.rgmii1_td1 */
+			0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd0.rgmii1_td0 */
+			0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txclk.rgmii1_tclk */
+			0x130 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxclk.rgmii1_rclk */
+			0x134 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd3.rgmii1_rd3 */
+			0x138 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd2.rgmii1_rd2 */
+			0x13c (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd1.rgmii1_rd1 */
+			0x140 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd0.rgmii1_rd0 */
+		>;
+	};
+
+	cpsw_sleep: cpsw_sleep {
+		pinctrl-single,pins = <
+			/* Slave 1 reset value */
+			0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	davinci_mdio_default: davinci_mdio_default {
+		pinctrl-single,pins = <
+			/* MDIO */
+			0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
+			0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0)			/* mdio_clk.mdio_clk */
+		>;
+	};
+
+	davinci_mdio_sleep: davinci_mdio_sleep {
+		pinctrl-single,pins = <
+			/* MDIO reset value */
+			0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+		>;
+	};
+
+	usb_hub_ctrl: usb_hub_ctrl {
+		pinctrl-single,pins = <
+			0x144 (PIN_OUTPUT_PULLUP | MUX_MODE7)	/* mcasp0_ahclkr.gpio3_17 */
+		>;
+	};
+
+	mpu6050_pins: pinmux_mpu6050_pins {
+		pinctrl-single,pins = <
+			0x168 (PIN_INPUT | MUX_MODE7)	/* spi0_sclk.gpio0_2 */
+		>;
+	};
+
+	lps3331ap_pins: pinmux_lps3331ap_pins {
+		pinctrl-single,pins = <
+			0x6C (PIN_INPUT | MUX_MODE7)	/* conf_gpmc_a11.gpio1_27 */
+		>;
+	};
+};
+
+&lcdc {
+	status = "okay";
+	port {
+		lcdc_0: endpoint@0 {
+			remote-endpoint = <&hdmi_0>;
+		};
+	};
+};
+
+&mac {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&cpsw_default>;
+	pinctrl-1 = <&cpsw_sleep>;
+};
+
+&davinci_mdio {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&davinci_mdio_default>;
+	pinctrl-1 = <&davinci_mdio_sleep>;
+};
+
+&cpsw_emac0 {
+	phy_id = <&davinci_mdio>, <0>;
+	phy-mode = "rgmii-txid";
+};
+
+&i2c0 {
+	tda19988 {
+		compatible = "nxp,tda998x";
+		reg = <0x70>;
+		pinctrl-names = "default", "off";
+		pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
+		pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>;
+
+		port {
+			hdmi_0: endpoint@0 {
+				remote-endpoint = <&lcdc_0>;
+			};
+		};
+	};
+
+	lps331ap: lps331ap@5C {
+		compatible = "st,lps331ap";
+		st,drdy-int-pin = <1>;
+		reg = <0x5C>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <27 IRQ_TYPE_EDGE_RISING>;
+	};
+
+	mpu6050: mpu6050@68 {
+		compatible = "invensense,mpu6050";
+		reg = <0x68>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <2 IRQ_TYPE_EDGE_RISING>;
+		//orientation = <0xff 0 0 0 1 0 0 0 0xff>;
+	};
+};
diff --git b/arch/arm/boot/dts/am335x-som-common.dtsi b/arch/arm/boot/dts/am335x-som-common.dtsi
new file mode 100644
index 0000000..fb4399b
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-som-common.dtsi
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+/ {
+
+	cpus {
+		cpu@0 {
+			cpu0-supply = <&dcdc2_fixed>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x80000000 0x20000000>; /* 512 MB */
+	};
+
+	ocp {
+		uart0: serial@44e09000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart0_pins>;
+
+			status = "okay";
+		};
+		uart1: serial@48022000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart1_pins>;
+			status = "okay";
+
+		};
+		uart4: serial@481a8000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart4_pins>;
+			status = "okay";
+		};
+
+		epwmss0: epwmss@48300000 {
+			status = "okay";
+
+			ecap0: ecap@48300100 {
+				status = "okay";
+				pinctrl-names = "default", "sleep";
+				pinctrl-0 = <&ecap0_pins_default>;
+				pinctrl-1 = <&ecap0_pins_sleep>;
+			};
+		};
+
+		musb: usb@47400000 {
+			status = "okay";
+
+			control@44e10000 {
+				status = "okay";
+			};
+
+			usb-phy@47401300 {
+				status = "okay";
+			};
+
+			usb-phy@47401b00 {
+				status = "okay";
+			};
+
+			usb@47401000 {
+				status = "okay";
+				dr_mode = "otg";
+			};
+
+			usb@47401800 {
+				status = "okay";
+				dr_mode = "host";
+			};
+
+			dma-controller@07402000  {
+				status = "okay";
+			};
+		};
+
+		i2c0: i2c@44e0b000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&i2c0_pins>;
+			status = "okay";
+			clock-frequency = <100000>;
+
+			tps: tps@24 {
+				reg = <0x24>;
+			};
+		};
+	};
+
+	vmmcsd_fixed: fixedregulator@0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vmmcsd_fixed";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	dcdc2_fixed: fixedregulator@1 {
+		/* VDD_MPU voltage limits 0.95V - 1.325V with +/-4% tolerance */
+		 compatible = "regulator-fixed";
+		regulator-name = "dcdc2_fixed";
+
+		regulator-min-microvolt = <1378000>;
+		regulator-max-microvolt = <1378000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	leds {
+		pinctrl-names = "default";
+		pinctrl-0 = <&user_leds_s0>;
+
+		compatible = "gpio-leds";
+
+		led@1 {
+			label = "led1:green:heartbeat";
+			gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		led@2 {
+			label = "led2:red:heartbeat";
+			gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		led@3 {
+			label = "led3:yello:heartbeat";
+			gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		led@4 {
+			label = "bkl";
+			gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+	};
+
+	backlight {
+		compatible = "pwm-backlight";
+		pwms = <&ecap0 0 500000 1>;
+		brightness-levels = <
+			0  1  2  3  4  5  6  7  8  9
+			10 11 12 13 14 15 16 17 18 19
+			20 21 22 23 24 25 26 27 28 29
+			30 31 32 33 34 35 36 37 38 39
+			40 41 42 43 44 45 46 47 48 49
+			50 51 52 53 54 55 56 57 58 59
+			60 61 62 63 64 65 66 67 68 69
+			70 71 72 73 74 75 76 77 78 79
+			80 81 82 83 84 85 86 87 88 89
+			90 91 92 93 94 95 96 97 98 99
+			100
+		>;
+		default-brightness-level = <50>;
+	};
+};
+
+&am33xx_pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&clkout2_pin>;
+
+		user_leds_s0: user_leds_s0 {
+			pinctrl-single,pins = <
+				0x1b0 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* xdma_event_intr0.gpio0_19 */
+				0x198 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* mcasp0_axr0.gpio3_20 */
+				0x1a8 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* mcasp0_axr1.gpio3_21 */
+				0x1a4 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* mcasp0_fsr.gpio3[19], INPUT_PULLDOWN | MODE7 */
+			>;
+		};
+
+		i2c0_pins: pinmux_i2c0_pins {
+			pinctrl-single,pins = <
+				0x188 (PIN_INPUT_PULLUP | MUX_MODE0)	/* i2c0_sda.i2c0_sda */
+				0x18c (PIN_INPUT_PULLUP | MUX_MODE0)	/* i2c0_scl.i2c0_scl */
+			>;
+		};
+
+		uart0_pins: pinmux_uart0_pins {
+			pinctrl-single,pins = <
+				0x170 (PIN_INPUT_PULLUP | MUX_MODE0)	/* uart0_rxd.uart0_rxd */
+				0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* uart0_txd.uart0_txd */
+			>;
+		};
+
+		uart1_pins: pinmux_uart1_pins {
+			pinctrl-single,pins = <
+				0x168 (PIN_INPUT_PULLUP | MUX_MODE1)
+				0x16c (PIN_OUTPUT_PULLDOWN | MUX_MODE1)
+			>;
+		};
+
+		uart4_pins: pinmux_uart4_pins {
+			pinctrl-single,pins = <
+				0x180 (PIN_INPUT_PULLUP | MUX_MODE0)
+				0x184 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)
+			>;
+		};
+
+
+
+		clkout2_pin: pinmux_clkout2_pin {
+			pinctrl-single,pins = <
+				0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* xdma_event_intr1.clkout2 */
+			>;
+		};
+
+		cpsw_default: cpsw_default {
+			pinctrl-single,pins = <
+				/* Slave 1 */
+				0x110 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxerr.mii1_rxerr */
+				0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txen.mii1_txen */
+				0x118 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxdv.mii1_rxdv */
+				0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd3.mii1_txd3 */
+				0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd2.mii1_txd2 */
+				0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd1.mii1_txd1 */
+				0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)	/* mii1_txd0.mii1_txd0 */
+				0x12c (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_txclk.mii1_txclk */
+				0x130 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxclk.mii1_rxclk */
+				0x134 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd3.mii1_rxd3 */
+				0x138 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd2.mii1_rxd2 */
+				0x13c (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd1.mii1_rxd1 */
+				0x140 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mii1_rxd0.mii1_rxd0 */
+
+				0x040 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a0.gmii2_txen, OUTPUT_PULLDOWN | MODE1 */
+				0x044 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a1.gmii2_rxdv, INPUT_PULLDOWN | MODE1 */
+				0x048 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a2.gmii2_txd3, OUTPUT_PULLDOWN | MODE1 */
+				0x04c (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a3.gmii2_txd2, OUTPUT_PULLDOWN | MODE1 */
+				0x050 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a4.gmii2_txd1, OUTPUT_PULLDOWN | MODE1 */
+				0x054 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* gpmc_a5.gmii2_txd0, OUTPUT_PULLDOWN | MODE1 */
+				0x058 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a6.gmii2_txclk, INPUT_PULLDOWN | MODE1 */
+				0x05c (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a7.gmii2_rxclk, INPUT_PULLDOWN | MODE1 */
+				0x060 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a8.gmii2_rxd3, INPUT_PULLDOWN | MODE1 */
+				0x064 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a9.gmii2_rxd2, INPUT_PULLDOWN | MODE1 */
+				0x068 (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a10.gmii2_rxd1, INPUT_PULLDOWN | MODE1 */
+				0x06c (PIN_INPUT_PULLDOWN | MUX_MODE1 ) /* gpmc_a11.gmii2_rxd0, INPUT_PULLDOWN | MODE1 */
+				0x070 (PIN_INPUT_PULLUP | MUX_MODE1 )   /* gpmc_wait0.gmii2_crs, INPUT_PULLUP | MODE1 */
+				0x074 (PIN_INPUT_PULLUP | MUX_MODE1 )   /* gpmc_wpn.gmii2_rxer, INPUT_PULLUP | MODE1 */
+				0x078 (PIN_INPUT_PULLUP | MUX_MODE1 )   /* gpmc_ben1.gmii2_col, INPUT_PULLUP | MODE1 */
+			>;
+		};
+
+		cpsw_sleep: cpsw_sleep {
+			pinctrl-single,pins = <
+				/* Slave 1 reset value */
+				0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+
+				0x40 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x44 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x48 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x4c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x50 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x54 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x58 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x5c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x60 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x070 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x074 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x078 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			>;
+		};
+
+		davinci_mdio_default: davinci_mdio_default {
+			pinctrl-single,pins = <
+				/* MDIO */
+				0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
+				0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0)			/* mdio_clk.mdio_clk */
+			>;
+		};
+
+		davinci_mdio_sleep: davinci_mdio_sleep {
+			pinctrl-single,pins = <
+				/* MDIO reset value */
+				0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			>;
+		};
+
+		mmc1_pins_default: pinmux_mmc1_pins {
+			pinctrl-single,pins = <
+				0x0F0 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat3.mmc0_dat3 */
+				0x0F4 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat2.mmc0_dat2 */
+				0x0F8 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat1.mmc0_dat1 */
+				0x0FC (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat0.mmc0_dat0 */
+				0x100 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_clk.mmc0_clk */
+				0x104 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_cmd.mmc0_cmd */
+				0x1A0 (PIN_INPUT_PULLUP | MUX_MODE7)	/* mcasp0_aclkr.gpio3_18 */
+				0x160 (PIN_INPUT | MUX_MODE7)		/* spi0_cs1.gpio0_6 */
+			>;
+		};
+
+		mmc1_pins_sleep: pinmux_mmc1_pins_sleep {
+			pinctrl-single,pins = <
+				0x0F0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x0F4 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x0F8 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x0FC (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x100 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x104 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x1A0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+				0x160 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+			>;
+		};
+
+		emmc_pins: pinmux_emmc_pins {
+			pinctrl-single,pins = <
+				0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+				0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+				0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+				0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+				0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+				0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+				0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+				0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+				0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+				0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+			>;
+		};
+
+			ecap0_pins_default: backlight_pins {
+			pinctrl-single,pins = <
+				0x164 0x0       /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out MODE0 */
+			>;
+		};
+
+		ecap0_pins_sleep: ecap0_pins_sleep {
+			pinctrl-single,pins = <
+				0x164  (PULL_DISABLE | MUX_MODE7)       /* eCAP0_in_PWM0_out.eCAP0_in_PWM0_out */
+			>;
+		};
+		dcan0_default: dcan0_default_pins {
+			pinctrl-single,pins = <
+				0x178 0x0a      /* uart1_ctsn.dcan0_tx_mux2, OUTPUT | MODE2 */
+				0x17c 0x2a      /* uart1_rtsn.dcan0_rx_mux2, INPUT | MODE2 */
+			>;
+		};
+	};
+
+&tps {
+	compatible = "ti,tps65217";
+	regulators {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		dcdc1_reg: regulator@0 {
+			reg = <0>;
+			regulator-always-on;
+		};
+
+		dcdc2_reg: regulator@1 {
+			reg = <1>;
+			/* VDD_MPU voltage limits 0.95V - 1.325V with +/-4% tolerance */
+			regulator-name = "vdd_mpu";
+			regulator-min-microvolt = <925000>;
+			regulator-max-microvolt = <1378000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		dcdc3_reg: regulator@2 {
+			reg = <2>;
+			/* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
+			regulator-name = "vdd_core";
+			regulator-min-microvolt = <925000>;
+			regulator-max-microvolt = <1150000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+
+		ldo1_reg: regulator@3 {
+			reg = <3>;
+			regulator-always-on;
+		};
+
+		ldo2_reg: regulator@4 {
+			reg = <4>;
+			regulator-always-on;
+		};
+
+		ldo3_reg: regulator@5 {
+			reg = <5>;
+			regulator-always-on;
+		};
+
+		ldo4_reg: regulator@6 {
+			reg = <6>;
+			regulator-always-on;
+		};
+	};
+};
+
+&cpsw_emac0 {
+	phy_id = <&davinci_mdio>, <0>;
+	phy-mode = "mii";
+};
+
+&cpsw_emac1 {
+	phy_id = <&davinci_mdio>, <1>;
+	phy-mode = "mii";
+};
+
+&mac {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&cpsw_default>;
+	pinctrl-1 = <&cpsw_sleep>;
+	slaves = <2>;
+	dual_emac = <1>;
+	status = "okay";
+};
+
+&davinci_mdio {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&davinci_mdio_default>;
+	pinctrl-1 = <&davinci_mdio_sleep>;
+	status = "okay";
+};
+
+&mmc1 {
+	status = "okay";
+	bus-width = <0x4>;
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&mmc1_pins_default>;
+	pinctrl-1 = <&mmc1_pins_sleep>;
+	cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+	cd-inverted;
+};
+
+&dcan0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&dcan0_default>;
+	status = "okay";
+};
+
+&tscadc {
+	status = "okay";
+	tsc {
+		ti,wires = <4>;
+		ti,x-plate-resistance = <200>;
+		ti,coordinate-readouts = <5>;
+		ti,wire-config = <0x00 0x11 0x22 0x33>;
+	};
+
+	adc {
+		ti,adc-channels = <0 1 2 3>;
+	};
+};
diff --git b/arch/arm/boot/dts/am33xx-es2.dtsi b/arch/arm/boot/dts/am33xx-es2.dtsi
new file mode 100644
index 0000000..6e252d4
--- /dev/null
+++ b/arch/arm/boot/dts/am33xx-es2.dtsi
@@ -0,0 +1,34 @@
+/*
+ * Device Tree Source for AM33XX SoC
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/ {
+	cpus {
+		cpu@0 {
+			/*
+			 * To consider voltage drop between PMIC and SoC,
+			 * tolerance value is reduced to 2% from 4% and
+			 * voltage value is increased as a precaution.
+			 */
+			operating-points = <
+				/* kHz    uV */
+				1000000	1325000
+				800000	1300000
+				600000	1112000
+				300000	969000
+			>;
+			voltage-tolerance = <2>; /* 2 percentage */
+
+			clocks = <&dpll_mpu_ck>;
+			clock-names = "cpu";
+
+			clock-latency = <300000>; /* From omap-cpufreq driver */
+		};
+	};
+};
diff --git b/arch/arm/boot/dts/am33xx-overlay-edma-fix.dtsi b/arch/arm/boot/dts/am33xx-overlay-edma-fix.dtsi
new file mode 100644
index 0000000..88c8d04
--- /dev/null
+++ b/arch/arm/boot/dts/am33xx-overlay-edma-fix.dtsi
@@ -0,0 +1,25 @@
+/*
+ * Device Tree Source for AM33xx Overlay EDMA fixes
+ *
+ * Copyright (C) 2015 Robert Nelson <robertcnelson@gmail.com>
+ *
+ * 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.
+ */
+
+&spi0 {
+	status = "okay";
+};
+
+&spi1 {
+	status = "okay";
+};
+
+&mcasp0 {
+	status = "okay";
+};
+
+&mcasp1 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index bd4c7b3..494eb0e 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -90,7 +90,7 @@
 	 * for the moment, just use a fake OCP bus entry to represent
 	 * the whole bus hierarchy.
 	 */
-	ocp {
+	ocp: ocp {
 		compatible = "simple-bus";
 		#address-cells = <1>;
 		#size-cells = <1>;
@@ -499,6 +499,17 @@
 			ti,timer-pwm;
 		};
 
+		pruss: pruss@4a300000 {
+			compatible = "ti,pruss-v2";
+			ti,hwmods = "pruss";
+			ti,deassert-hard-reset = "pruss", "pruss";
+			reg = <0x4a300000 0x080000>;
+			ti,pintc-offset = <0x20000>;
+			interrupt-parent = <&intc>;
+			status = "disabled";
+			interrupts = <20 21 22 23 24 25 26 27>;
+		};
+
 		rtc: rtc@44e3e000 {
 			compatible = "ti,am3352-rtc", "ti,da830-rtc";
 			reg = <0x44e3e000 0x1000>;
@@ -695,6 +706,15 @@
 				ti,hwmods = "ehrpwm0";
 				status = "disabled";
 			};
+
+			eqep0: eqep@0x48300180 {
+				compatible = "ti,am33xx-eqep";
+				reg = <0x48300180 0x80>;
+				interrupt-parent = <&intc>;
+				interrupts = <79>;
+				ti,hwmods = "eqep0";
+				status = "disabled";
+			};
 		};
 
 		epwmss1: epwmss@48302000 {
@@ -725,6 +745,15 @@
 				ti,hwmods = "ehrpwm1";
 				status = "disabled";
 			};
+
+			eqep1: eqep@0x48302180 {
+				compatible = "ti,am33xx-eqep";
+				reg = <0x48302180 0x80>;
+				interrupt-parent = <&intc>;
+				interrupts = <88>;
+				ti,hwmods = "eqep1";
+				status = "disabled";
+			};
 		};
 
 		epwmss2: epwmss@48304000 {
@@ -755,6 +784,15 @@
 				ti,hwmods = "ehrpwm2";
 				status = "disabled";
 			};
+
+			eqep2: eqep@0x48304180 {
+				compatible = "ti,am33xx-eqep";
+				reg = <0x48304180 0x80>;
+				interrupt-parent = <&intc>;
+				interrupts = <89>;
+				ti,hwmods = "eqep2";
+				status = "disabled";
+			};
 		};
 
 		mac: ethernet@4a100000 {
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index 13ac882..90f2f62 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -303,6 +303,13 @@
 			reg = <0x40d00000 0x100>;
 		};
 
+		dra7_iodelay_core: padconf@4844a000 {
+			compatible = "ti,dra7-iodelay";
+			reg = <0x4844a000 0x0d1c>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
 		sdma: dma-controller@4a056000 {
 			compatible = "ti,omap4430-sdma";
 			reg = <0x4a056000 0x1000>;
diff --git b/arch/arm/boot/dts/exynos3250-artik5-eval.dts b/arch/arm/boot/dts/exynos3250-artik5-eval.dts
new file mode 100644
index 0000000..a371baf
--- /dev/null
+++ b/arch/arm/boot/dts/exynos3250-artik5-eval.dts
@@ -0,0 +1,42 @@
+/*
+ * Samsung's Exynos3250 based ARTIK5 development board device tree source
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Device tree source file for Samsung's ARTIK5 development board
+ * which is based on Samsung Exynos3250 SoC.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+#include "exynos3250-artik5.dtsi"
+
+/ {
+	model = "Samsung ARTIK5 development board";
+	compatible = "samsung,artik5-devel", "samsung,artik5",
+			"samsung,exynos3250", "samsung,exynos3";
+};
+
+&mshc_2 {
+	num-slots = <1>;
+	cap-sd-highspeed;
+	disable-wp;
+	card-detect-delay = <200>;
+	clock-frequency = <100000000>;
+	clock-freq-min-max = <400000 100000000>;
+	samsung,dw-mshc-ciu-div = <1>;
+	samsung,dw-mshc-sdr-timing = <0 1>;
+	samsung,dw-mshc-ddr-timing = <1 2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd2_cmd &sd2_clk &sd2_cd &sd2_bus1 &sd2_bus4>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&serial_2 {
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/exynos3250-artik5.dtsi b/arch/arm/boot/dts/exynos3250-artik5.dtsi
new file mode 100644
index 0000000..9953567
--- /dev/null
+++ b/arch/arm/boot/dts/exynos3250-artik5.dtsi
@@ -0,0 +1,372 @@
+/*
+ * Samsung's Exynos3250 based ARTIK5 module device tree source
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Device tree source file for Samsung's ARTIK5 module which is based on
+ * Samsung Exynos3250 SoC.
+ *
+ * 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 "exynos3250.dtsi"
+#include <dt-bindings/clock/samsung,s2mps11.h>
+
+/ {
+	compatible = "samsung,artik5", "samsung,exynos3250", "samsung,exynos3";
+
+
+	chosen {
+		linux,stdout = &serial_2;
+	};
+
+	memory {
+		reg =  <0x40000000 0x1ff00000>;
+	};
+
+	firmware@0205F000 {
+		compatible = "samsung,secure-firmware";
+		reg = <0x0205F000 0x1000>;
+	};
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			cooling-maps {
+				map0 {
+					/* Corresponds to 500MHz */
+					cooling-device = <&cpu0 5 5>;
+				};
+				map1 {
+					/* Corresponds to 200MHz */
+					cooling-device = <&cpu0 8 8>;
+				};
+			};
+		};
+	};
+};
+
+&adc {
+	vdd-supply = <&ldo7_reg>;
+	assigned-clocks = <&cmu CLK_SCLK_TSADC>;
+	assigned-clock-rates = <6000000>;
+};
+
+&cpu0 {
+	cpu0-supply = <&buck2_reg>;
+};
+
+&i2c_0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	samsung,i2c-sda-delay = <100>;
+	samsung,i2c-slave-addr = <0x10>;
+	samsung,i2c-max-bus-freq = <100000>;
+	status = "okay";
+
+	s2mps14_pmic@66 {
+		compatible = "samsung,s2mps14-pmic";
+		interrupt-parent = <&gpx3>;
+		interrupts = <5 0>;
+		reg = <0x66>;
+		wakeup;
+
+		s2mps14_osc: clocks {
+			compatible = "samsung,s2mps14-clk";
+			#clock-cells = <1>;
+			clock-output-names = "s2mps14_ap", "unused",
+				"s2mps14_bt";
+		};
+
+		regulators {
+			ldo1_reg: LDO1 {
+				/* VDD_ALIVE15x */
+				regulator-name = "VLDO1_1.0V";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+
+			ldo2_reg: LDO2 {
+				/* VDDQM176 ~ VDDQM185 */
+				regulator-name = "VLDO2_1.2V";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+			};
+
+			ldo3_reg: LDO3 {
+				/*
+				 * VDD1_E106 ~ VDD1_E111
+				 * DVDD_RTC_AP, DVDD_MMC2_AP
+				 */
+				regulator-name = "VLDO3_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			ldo4_reg: LDO4 {
+				/*  AVDD_PLL1120 ~ AVDD_PLL11201 */
+				regulator-name = "VLDO4_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			ldo5_reg: LDO5 {
+				/* VDDI_PLL_ISO141 ~ VDDI_PLL_ISO142 */
+				regulator-name = "VLDO5_1.0V";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+
+			ldo6_reg: LDO6 {
+				/* VDD_USB, VDD10_HSIC */
+				regulator-name = "VLDO6_1.0V";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+
+			ldo7_reg: LDO7 {
+				/*
+				 * VDD18P, AVDD18_TS, AVDD18_HSIC, AVDD_PLL2,
+				 * AVDD_ADC, AVDD_ABB_0, M4S_VDD18
+				 */
+				regulator-name = "VLDO7_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			ldo8_reg: LDO8 {
+				/* AVDD33_UOTG */
+				regulator-name = "VLDO8_3.0V";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-always-on;
+			};
+
+			ldo9_reg: LDO9 {
+				/* VDDQ_E86 ~ VDDQ_E105*/
+				regulator-name = "VLDO_1.2V";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+			};
+
+			ldo10_reg: LDO10 {
+				regulator-name = "VLDO10_1.0V";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+			};
+
+			ldo11_reg: LDO11 {
+				/* VDD_MMC */
+				regulator-name = "VLDO11_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			ldo12_reg: LDO12 {
+				/* VDD72 ~ VDD73 */
+				regulator-name = "VLDO12_2.8V";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+				regulator-always-on;
+			};
+
+			ldo13_reg: LDO13 {
+				regulator-name = "VLDO13_2.8V";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+
+			ldo14_reg: LDO14 {
+				regulator-name = "VLDO14_2.7V";
+				regulator-min-microvolt = <2700000>;
+				regulator-max-microvolt = <2700000>;
+			};
+
+			ldo15_reg: LDO15 {
+				regulator-name = "VLDO_3.3V";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			ldo16_reg: LDO16 {
+				regulator-name = "VLDO16_3.3V";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			ldo17_reg: LDO17 {
+				regulator-name = "VLDO17_3.0V";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+
+			ldo18_reg: LDO18 {
+				/* DVDD_MMC2_AP */
+				regulator-name = "VLDO18_2.8V";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+
+			ldo19_reg: LDO19 {
+				regulator-name = "VLDO19_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo20_reg: LDO20 {
+				regulator-name = "VLDO20_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo21_reg: LDO21 {
+				regulator-name = "VLDO21_1.25V";
+				regulator-min-microvolt = <1250000>;
+				regulator-max-microvolt = <1250000>;
+			};
+
+			ldo22_reg: LDO22 {
+				regulator-name = "VLDO22_1.2V";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+			};
+
+			ldo23_reg: LDO23 {
+				/* Xi2c3_SDA/SCL, Xi2c7_SDA/SCL, WLAN_SDIO */
+				regulator-name = "VLDO23_1.8V";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			ldo24_reg: LDO24 {
+				regulator-name = "VLDO24_3.0V";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+
+			ldo25_reg: LDO25 {
+				regulator-name = "VLDO25_3.0V";
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+			};
+
+			buck1_reg: BUCK1 {
+				/* VDD_MIF */
+				regulator-name = "VBUCK1_1.0V";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+
+			buck2_reg: BUCK2 {
+				/* VDD_CPU */
+				regulator-name = "VBUCK2_1.2V";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+			};
+
+			buck3_reg: BUCK3 {
+				/* VDD_G3D */
+				regulator-name = "VBUCK3_1.0V";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+			};
+
+			buck4_reg: BUCK4 {
+				regulator-name = "VBUCK4_1.95V";
+				regulator-min-microvolt = <1950000>;
+				regulator-max-microvolt = <1950000>;
+				regulator-always-on;
+			};
+
+			buck5_reg: BUCK5 {
+				regulator-name = "VBUCK5_1.35V";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&mshc_0 {
+	num-slots = <1>;
+	broken-cd;
+	non-removable;
+	cap-mmc-highspeed;
+	desc-num = <4>;
+	card-detect-delay = <200>;
+	vmmc-supply = <&ldo11_reg>;
+	clock-frequency = <100000000>;
+	clock-freq-min-max = <400000 100000000>;
+	samsung,dw-mshc-ciu-div = <1>;
+	samsung,dw-mshc-sdr-timing = <0 1>;
+	samsung,dw-mshc-ddr-timing = <1 2>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
+	bus-width = <8>;
+	status = "okay";
+};
+
+&ppmu_dmc0 {
+	status = "okay";
+	events {
+		ppmu_dmc0_3: ppmu-event3-dmc0 {
+			event-name = "ppmu-event3-dmc0";
+		};
+	};
+};
+
+&ppmu_dmc1 {
+	status = "okay";
+	events {
+		ppmu_dmc1_3: ppmu-event3-dmc1 {
+			event-name = "ppmu-event3-dmc1";
+		};
+	};
+};
+
+&ppmu_leftbus {
+	status = "okay";
+	events {
+		ppmu_leftbus_3: ppmu-event3-leftbus {
+			event-name = "ppmu-event3-leftbus";
+		};
+	};
+};
+
+&ppmu_rightbus {
+	status = "okay";
+	events {
+		ppmu_rightbus_3: ppmu-event3-rightbus {
+			event-name = "ppmu-event3-rightbus";
+		};
+	};
+};
+
+&tmu {
+	status = "okay";
+};
+
+&rtc {
+	clocks = <&cmu CLK_RTC>, <&s2mps14_osc S2MPS11_CLK_AP>;
+	clock-names = "rtc", "rtc_src";
+	status = "okay";
+};
+
+&xusbxti {
+	clock-frequency = <24000000>;
+};
diff --git a/arch/arm/boot/dts/exynos3250-pinctrl.dtsi b/arch/arm/boot/dts/exynos3250-pinctrl.dtsi
index 5ab81c3..78b995f 100644
--- a/arch/arm/boot/dts/exynos3250-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos3250-pinctrl.dtsi
@@ -120,6 +120,13 @@
 		samsung,pin-drv = <0>;
 	};
 
+	uart2_data: uart2-data {
+		samsung,pins = "gpa1-0", "gpa1-1";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <0>;
+	};
+
 	i2c3_bus: i2c3-bus {
 		samsung,pins = "gpa1-2", "gpa1-3";
 		samsung,pin-function = <3>;
@@ -445,6 +452,41 @@
 		samsung,pin-drv = <3>;
 	};
 
+	sd2_clk: sd2-clk {
+		samsung,pins = "gpk2-0";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd2_cmd: sd2-cmd {
+		samsung,pins = "gpk2-1";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <0>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd2_cd: sd2-cd {
+		samsung,pins = "gpk2-2";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd2_bus1: sd2-bus-width1 {
+		samsung,pins = "gpk2-3";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+
+	sd2_bus4: sd2-bus-width4 {
+		samsung,pins = "gpk2-4", "gpk2-5", "gpk2-6";
+		samsung,pin-function = <2>;
+		samsung,pin-pud = <3>;
+		samsung,pin-drv = <3>;
+	};
+
 	cam_port_b_io: cam-port-b-io {
 		samsung,pins = "gpm0-0", "gpm0-1", "gpm0-2", "gpm0-3",
 				"gpm0-4", "gpm0-5", "gpm0-6", "gpm0-7",
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 137f901..13d00f9 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -31,6 +31,7 @@
 		pinctrl1 = &pinctrl_1;
 		mshc0 = &mshc_0;
 		mshc1 = &mshc_1;
+		mshc2 = &mshc_2;
 		spi0 = &spi_0;
 		spi1 = &spi_1;
 		i2c0 = &i2c_0;
@@ -43,6 +44,7 @@
 		i2c7 = &i2c_7;
 		serial0 = &serial_0;
 		serial1 = &serial_1;
+		serial2 = &serial_2;
 	};
 
 	cpus {
@@ -357,6 +359,18 @@
 			status = "disabled";
 		};
 
+		mshc_2: mshc@12530000 {
+			compatible = "samsung,exynos5250-dw-mshc";
+			reg = <0x12530000 0x1000>;
+			interrupts = <0 144 0>;
+			clocks = <&cmu CLK_SDMMC2>, <&cmu CLK_SCLK_MMC2>;
+			clock-names = "biu", "ciu";
+			fifo-depth = <0x80>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
 		exynos_usbphy: exynos-usbphy@125B0000 {
 			compatible = "samsung,exynos3250-usb2-phy";
 			reg = <0x125B0000 0x100>;
@@ -452,6 +466,17 @@
 			status = "disabled";
 		};
 
+		serial_2: serial@13820000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x13820000 0x100>;
+			interrupts = <0 111 0>;
+			clocks = <&cmu CLK_UART2>, <&cmu CLK_SCLK_UART2>;
+			clock-names = "uart", "clk_uart_baud0";
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart2_data>;
+			status = "disabled";
+		};
+
 		i2c_0: i2c@13860000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
diff --git b/arch/arm/boot/dts/imx6dl-sabresd-wl1835.dts b/arch/arm/boot/dts/imx6dl-sabresd-wl1835.dts
new file mode 100644
index 0000000..37721c1
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-sabresd-wl1835.dts
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "imx6dl.dtsi"
+#include "imx6qdl-sabresd-wl1835.dtsi"
+
+/ {
+	model = "Freescale i.MX6 DualLite SABRE Smart Device Board";
+	compatible = "fsl,imx6dl-sabresd", "fsl,imx6dl";
+};
diff --git b/arch/arm/boot/dts/imx6q-ccimx6sbc.dts b/arch/arm/boot/dts/imx6q-ccimx6sbc.dts
new file mode 100644
index 0000000..d249240
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-ccimx6sbc.dts
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2015 Robert Nelson (robertcnelson@gmail.com)
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file 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.
+ *
+ *     This file 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.
+ *
+ * Or, alternatively
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+/dts-v1/;
+
+#include "imx6q.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Digi ConnectCore-i.MX6 SBC Board";
+	compatible = "digi,connectcore/q", "fsl,imx6q";
+
+	chosen {
+		stdout-path = &uart4;
+	};
+
+	memory {
+		reg = <0x10000000 0x40000000>;
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg_usbh1_reset: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usbh1>;
+			regulator-name = "usbh1_reset";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			gpio = <&gpio3 10 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+		};
+
+		reg_usb_otg_vbus: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usbotg>;
+			regulator-name = "usb_otg_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+		};
+	};
+};
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet>;
+	phy-mode = "rgmii";
+	phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&hdmi {
+	ddc-i2c-bus = <&i2c3>;
+	status = "okay";
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	pmic@58 {
+		compatible = "dlg,da9063";
+		reg = <0x58>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <17 0x8>; /* active-low GPIO0_17 */
+
+		regulators {
+			vdd_3v3_reg: bperi {
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			ldo3_reg: ldo3 {
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			ldo4_reg: ldo4 {
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			ldo6_reg: ldo6 {
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			ldo7_reg: ldo7 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			ldo8_reg: ldo8 {
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	imx6qdl-ccimx6sbc {
+		pinctrl_hog: hoggrp {
+			fsl,pins = <
+				/* da9063*/
+				MX6QDL_PAD_GPIO_17__GPIO7_IO12		0x80000000
+			>;
+		};
+
+		pinctrl_enet: enetgrp {
+			fsl,pins = <
+				MX6QDL_PAD_ENET_MDIO__ENET_MDIO		0x100b0
+				MX6QDL_PAD_ENET_MDC__ENET_MDC		0x100b0
+				MX6QDL_PAD_RGMII_TXC__RGMII_TXC		0x100b0
+				MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x100b0
+				MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x100b0
+				MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x100b0
+				MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x100b0
+				MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x100b0
+				MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK	0x100b0
+				MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b0b0
+				MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x1b0b0
+				MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x1b0b0
+				MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b0b0
+				MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b0b0
+				MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b0b0
+				/* Phy reset */
+				MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25	0x000b0
+			>;
+		};
+
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
+				MX6QDL_PAD_KEY_ROW3__I2C2_SDA		0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c3: i2c3grp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_5__I2C3_SCL		0x4001b8b1
+				MX6QDL_PAD_GPIO_6__I2C3_SDA		0x4001b8b1
+			>;
+		};
+
+		pinctrl_uart4: uart4grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL0__UART4_TX_DATA	0x1b0b1
+				MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA	0x1b0b1
+			>;
+		};
+
+		pinctrl_usbh1: usbh1grp {
+			fsl,pins = <
+				/* need to force low for hub reset */
+				MX6QDL_PAD_EIM_DA10__GPIO3_IO10		0x10b0
+			>;
+		};
+
+		pinctrl_usbotg: usbotggrp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_1__USB_OTG_ID		0x17059
+				MX6QDL_PAD_EIM_D21__USB_OTG_OC		0x1b0b0
+				/* power enable, high active */
+				MX6QDL_PAD_EIM_D22__GPIO3_IO22		0x10b0
+			>;
+		};
+
+		pinctrl_usdhc2: usdhc2grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD2_CMD__SD2_CMD		0x17059
+				MX6QDL_PAD_SD2_CLK__SD2_CLK		0x10059
+				MX6QDL_PAD_SD2_DAT0__SD2_DATA0		0x17059
+				MX6QDL_PAD_SD2_DAT1__SD2_DATA1		0x17059
+				MX6QDL_PAD_SD2_DAT2__SD2_DATA2		0x17059
+				MX6QDL_PAD_SD2_DAT3__SD2_DATA3		0x17059
+			>;
+		};
+
+		pinctrl_usdhc4: usdhc4grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD4_CMD__SD4_CMD		0x17059
+				MX6QDL_PAD_SD4_CLK__SD4_CLK		0x10059
+				MX6QDL_PAD_SD4_DAT0__SD4_DATA0		0x17059
+				MX6QDL_PAD_SD4_DAT1__SD4_DATA1		0x17059
+				MX6QDL_PAD_SD4_DAT2__SD4_DATA2		0x17059
+				MX6QDL_PAD_SD4_DAT3__SD4_DATA3		0x17059
+				MX6QDL_PAD_SD4_DAT4__SD4_DATA4		0x17059
+				MX6QDL_PAD_SD4_DAT5__SD4_DATA5		0x17059
+				MX6QDL_PAD_SD4_DAT6__SD4_DATA6		0x17059
+				MX6QDL_PAD_SD4_DAT7__SD4_DATA7		0x17059
+			>;
+		};
+	};
+};
+
+&sata {
+	status = "okay";
+};
+
+&ssi1 {
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4>;
+	status = "okay";
+};
+
+&usbh1 {
+	vbus-supply = <&reg_usbh1_reset>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbh1>;
+	status = "okay";
+};
+
+&usbotg {
+	vbus-supply = <&reg_usb_otg_vbus>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbotg>;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	bus-width = <4>;
+	broken-cd; /* cd & wp, is not wired up on this board */
+	status = "okay";
+};
+
+&usdhc4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc4>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/imx6q-sabresd-wl1835.dts b/arch/arm/boot/dts/imx6q-sabresd-wl1835.dts
new file mode 100644
index 0000000..d88d9e2
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-sabresd-wl1835.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+
+#include "imx6q.dtsi"
+#include "imx6qdl-sabresd-wl1835.dtsi"
+
+/ {
+	model = "Freescale i.MX6 Quad SABRE Smart Device Board";
+	compatible = "fsl,imx6q-sabresd", "fsl,imx6q";
+};
+
+&sata {
+	status = "okay";
+};
diff --git b/arch/arm/boot/dts/imx6qdl-sabresd-wl1835.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd-wl1835.dtsi
new file mode 100644
index 0000000..862dfbd
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-sabresd-wl1835.dtsi
@@ -0,0 +1,646 @@
+/* Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+	chosen {
+		stdout-path = &uart1;
+	};
+
+	memory {
+		reg = <0x10000000 0x40000000>;
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg_usb_otg_vbus: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "usb_otg_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			gpio = <&gpio3 22 0>;
+			enable-active-high;
+			vin-supply = <&swbst_reg>;
+		};
+
+		reg_usb_h1_vbus: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "usb_h1_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			gpio = <&gpio1 29 0>;
+			enable-active-high;
+			vin-supply = <&swbst_reg>;
+		};
+
+		reg_audio: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "wm8962-supply";
+			gpio = <&gpio4 10 0>;
+			enable-active-high;
+		};
+
+		reg_pcie: regulator@3 {
+			compatible = "regulator-fixed";
+			reg = <3>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_pcie_reg>;
+			regulator-name = "MPCIE_3V3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			gpio = <&gpio3 19 0>;
+			regulator-always-on;
+			enable-active-high;
+		};
+
+		wlan_en_reg: regulator@4 {
+			compatible = "regulator-fixed";
+			regulator-name = "wlan-en-regulator";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			/* WLAN_EN GPIO for this board – Bank4, pin7 */
+			gpio = <&gpio4 7 0>;
+			enable-active-high;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_keys>;
+
+		power {
+			label = "Power Button";
+			gpios = <&gpio3 29 GPIO_ACTIVE_LOW>;
+			gpio-key,wakeup;
+			linux,code = <KEY_POWER>;
+		};
+
+		volume-up {
+			label = "Volume Up";
+			gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
+			gpio-key,wakeup;
+			linux,code = <KEY_VOLUMEUP>;
+		};
+
+		volume-down {
+			label = "Volume Down";
+			gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
+			gpio-key,wakeup;
+			linux,code = <KEY_VOLUMEDOWN>;
+		};
+	};
+
+	sound {
+		compatible = "fsl,imx6q-sabresd-wm8962",
+			   "fsl,imx-audio-wm8962";
+		model = "wm8962-audio";
+		ssi-controller = <&ssi2>;
+		audio-codec = <&codec>;
+		audio-routing =
+			"Headphone Jack", "HPOUTL",
+			"Headphone Jack", "HPOUTR",
+			"Ext Spk", "SPKOUTL",
+			"Ext Spk", "SPKOUTR",
+			"AMIC", "MICBIAS",
+			"IN3R", "AMIC";
+		mux-int-port = <2>;
+		mux-ext-port = <3>;
+	};
+
+	backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm1 0 5000000>;
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <7>;
+		status = "okay";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_leds>;
+
+/* red_led gpio gpio1_2 is used for bt_enable
+		red {
+		        gpios = <&gpio1 2 0>;
+		        default-state = "on";
+		};
+*/
+	};
+
+	kim {
+		compatible = "kim";
+		nshutdown_gpio = <2>;
+		dev_name = "/dev/ttymxc4";
+		flow_cntrl = <1>;
+		baud_rate = <3000000>;
+	};
+
+	btwilink {
+		compatible = "btwilink";
+	};
+};
+
+&audmux {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_audmux>;
+	status = "okay";
+};
+
+/*
+&ecspi1 {
+	fsl,spi-num-chipselects = <1>;
+	cs-gpios = <&gpio4 9 0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	status = "okay";
+
+	flash: m25p80@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "st,m25p32";
+		spi-max-frequency = <20000000>;
+		reg = <0>;
+	};
+};
+*/
+
+&fec {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet>;
+	phy-mode = "rgmii";
+	phy-reset-gpios = <&gpio1 25 0>;
+	status = "okay";
+};
+
+&hdmi {
+	ddc-i2c-bus = <&i2c2>;
+	status = "okay";
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	codec: wm8962@1a {
+		compatible = "wlf,wm8962";
+		reg = <0x1a>;
+		clocks = <&clks IMX6QDL_CLK_CKO>;
+		DCVDD-supply = <&reg_audio>;
+		DBVDD-supply = <&reg_audio>;
+		AVDD-supply = <&reg_audio>;
+		CPVDD-supply = <&reg_audio>;
+		MICVDD-supply = <&reg_audio>;
+		PLLVDD-supply = <&reg_audio>;
+		SPKVDD1-supply = <&reg_audio>;
+		SPKVDD2-supply = <&reg_audio>;
+		gpio-cfg = <
+			0x0000 /* 0:Default */
+			0x0000 /* 1:Default */
+			0x0013 /* 2:FN_DMICCLK */
+			0x0000 /* 3:Default */
+			0x8014 /* 4:FN_DMICCDAT */
+			0x0000 /* 5:Default */
+		>;
+       };
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	pmic: pfuze100@08 {
+		compatible = "fsl,pfuze100";
+		reg = <0x08>;
+
+		regulators {
+			sw1a_reg: sw1ab {
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1875000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <6250>;
+			};
+
+			sw1c_reg: sw1c {
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1875000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <6250>;
+			};
+
+			sw2_reg: sw2 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw3a_reg: sw3a {
+				regulator-min-microvolt = <400000>;
+				regulator-max-microvolt = <1975000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw3b_reg: sw3b {
+				regulator-min-microvolt = <400000>;
+				regulator-max-microvolt = <1975000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw4_reg: sw4 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			swbst_reg: swbst {
+				regulator-min-microvolt = <5000000>;
+				regulator-max-microvolt = <5150000>;
+			};
+
+			snvs_reg: vsnvs {
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			vref_reg: vrefddr {
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			vgen1_reg: vgen1 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1550000>;
+			};
+
+			vgen2_reg: vgen2 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1550000>;
+			};
+
+			vgen3_reg: vgen3 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vgen4_reg: vgen4 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vgen5_reg: vgen5 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vgen6_reg: vgen6 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&i2c3 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+
+	egalax_ts@04 {
+		compatible = "eeti,egalax_ts";
+		reg = <0x04>;
+		interrupt-parent = <&gpio6>;
+		interrupts = <7 2>;
+		wakeup-gpios = <&gpio6 7 0>;
+	};
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	imx6qdl-sabresd {
+		pinctrl_hog: hoggrp {
+			fsl,pins = <
+				MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0
+				MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0
+				MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0
+				MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0
+				MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x130b0
+				MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x1b0b0
+				MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1b0b0
+				MX6QDL_PAD_EIM_D22__GPIO3_IO22  0x1b0b0
+				MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0
+				MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x13059 // reserve two pins wl8 gpio, this is pulled low at reset for WL_EN
+				MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x13059 // this is for WL_IRQ which driver will configure as an input with a pull down
+			>;
+		};
+
+		pinctrl_audmux: audmuxgrp {
+			fsl,pins = <
+				MX6QDL_PAD_CSI0_DAT7__AUD3_RXD		0x130b0
+				MX6QDL_PAD_CSI0_DAT4__AUD3_TXC		0x130b0
+				MX6QDL_PAD_CSI0_DAT5__AUD3_TXD		0x110b0
+				MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS		0x130b0
+			>;
+		};
+
+		pinctrl_ecspi1: ecspi1grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL1__ECSPI1_MISO	0x100b1
+				MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI	0x100b1
+				MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK	0x100b1
+				MX6QDL_PAD_KEY_ROW1__GPIO4_IO09		0x1b0b0
+			>;
+		};
+
+		pinctrl_enet: enetgrp {
+			fsl,pins = <
+				MX6QDL_PAD_ENET_MDIO__ENET_MDIO		0x1b0b0
+				MX6QDL_PAD_ENET_MDC__ENET_MDC		0x1b0b0
+				MX6QDL_PAD_RGMII_TXC__RGMII_TXC		0x1b0b0
+				MX6QDL_PAD_RGMII_TD0__RGMII_TD0		0x1b0b0
+				MX6QDL_PAD_RGMII_TD1__RGMII_TD1		0x1b0b0
+				MX6QDL_PAD_RGMII_TD2__RGMII_TD2		0x1b0b0
+				MX6QDL_PAD_RGMII_TD3__RGMII_TD3		0x1b0b0
+				MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL	0x1b0b0
+				MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK	0x1b0b0
+				MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b0b0
+				MX6QDL_PAD_RGMII_RD0__RGMII_RD0		0x1b0b0
+				MX6QDL_PAD_RGMII_RD1__RGMII_RD1		0x1b0b0
+				MX6QDL_PAD_RGMII_RD2__RGMII_RD2		0x1b0b0
+				MX6QDL_PAD_RGMII_RD3__RGMII_RD3		0x1b0b0
+				MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b0b0
+				MX6QDL_PAD_GPIO_16__ENET_REF_CLK	0x4001b0a8
+			>;
+		};
+
+		pinctrl_gpio_keys: gpio_keysgrp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0
+				MX6QDL_PAD_GPIO_4__GPIO1_IO04  0x1b0b0
+				MX6QDL_PAD_GPIO_5__GPIO1_IO05  0x1b0b0
+			>;
+		};
+
+		pinctrl_i2c1: i2c1grp {
+			fsl,pins = <
+				MX6QDL_PAD_CSI0_DAT8__I2C1_SDA		0x4001b8b1
+				MX6QDL_PAD_CSI0_DAT9__I2C1_SCL		0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
+				MX6QDL_PAD_KEY_ROW3__I2C2_SDA		0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c3: i2c3grp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_3__I2C3_SCL		0x4001b8b1
+				MX6QDL_PAD_GPIO_6__I2C3_SDA		0x4001b8b1
+			>;
+		};
+
+		pinctrl_pcie: pciegrp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_17__GPIO7_IO12	0x1b0b0
+			>;
+		};
+
+		pinctrl_pcie_reg: pciereggrp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_D19__GPIO3_IO19	0x1b0b0
+			>;
+		};
+
+		pinctrl_pwm1: pwm1grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD1_DAT3__PWM1_OUT		0x1b0b1
+			>;
+		};
+
+		pinctrl_uart1: uart1grp {
+			fsl,pins = <
+				MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA	0x1b0b1
+				MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA	0x1b0b1
+			>;
+		};
+
+		pinctrl_uart5: uart5grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1
+				MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1
+				MX6QDL_PAD_KEY_ROW4__UART5_CTS_B   0x1b0b1
+				MX6QDL_PAD_KEY_COL4__UART5_RTS_B   0x1b0b1
+			>;
+		};
+
+		pinctrl_usbotg: usbotggrp {
+			fsl,pins = <
+				MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID	0x17059
+			>;
+		};
+
+		pinctrl_usdhc2: usdhc2grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD2_CMD__SD2_CMD		0x17059
+				MX6QDL_PAD_SD2_CLK__SD2_CLK		0x10059
+				MX6QDL_PAD_SD2_DAT0__SD2_DATA0		0x17059
+				MX6QDL_PAD_SD2_DAT1__SD2_DATA1		0x17059
+				MX6QDL_PAD_SD2_DAT2__SD2_DATA2		0x17059
+				MX6QDL_PAD_SD2_DAT3__SD2_DATA3		0x17059
+				MX6QDL_PAD_NANDF_D4__SD2_DATA4		0x17059
+				MX6QDL_PAD_NANDF_D5__SD2_DATA5		0x17059
+				MX6QDL_PAD_NANDF_D6__SD2_DATA6		0x17059
+				MX6QDL_PAD_NANDF_D7__SD2_DATA7		0x17059
+			>;
+		};
+
+		pinctrl_usdhc3: usdhc3grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD3_CMD__SD3_CMD		0x17059
+				MX6QDL_PAD_SD3_CLK__SD3_CLK		0x10059
+				MX6QDL_PAD_SD3_DAT0__SD3_DATA0		0x17059
+				MX6QDL_PAD_SD3_DAT1__SD3_DATA1		0x17059
+				MX6QDL_PAD_SD3_DAT2__SD3_DATA2		0x17059
+				MX6QDL_PAD_SD3_DAT3__SD3_DATA3		0x17059
+				MX6QDL_PAD_SD3_DAT4__SD3_DATA4		0x17059
+				MX6QDL_PAD_SD3_DAT5__SD3_DATA5		0x17059
+				MX6QDL_PAD_SD3_DAT6__SD3_DATA6		0x17059
+				MX6QDL_PAD_SD3_DAT7__SD3_DATA7		0x17059
+			>;
+		};
+
+		pinctrl_usdhc4: usdhc4grp {
+			fsl,pins = <
+				MX6QDL_PAD_SD4_CMD__SD4_CMD		0x17059
+				MX6QDL_PAD_SD4_CLK__SD4_CLK		0x10059
+				MX6QDL_PAD_SD4_DAT0__SD4_DATA0		0x17059
+				MX6QDL_PAD_SD4_DAT1__SD4_DATA1		0x17059
+				MX6QDL_PAD_SD4_DAT2__SD4_DATA2		0x17059
+				MX6QDL_PAD_SD4_DAT3__SD4_DATA3		0x17059
+				MX6QDL_PAD_SD4_DAT4__SD4_DATA4		0x17059
+				MX6QDL_PAD_SD4_DAT5__SD4_DATA5		0x17059
+				MX6QDL_PAD_SD4_DAT6__SD4_DATA6		0x17059
+				MX6QDL_PAD_SD4_DAT7__SD4_DATA7		0x17059
+			>;
+		};
+	};
+
+	gpio_leds {
+		pinctrl_gpio_leds: gpioledsgrp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0
+			>;
+		};
+	};
+};
+
+&ldb {
+	status = "okay";
+
+	lvds-channel@1 {
+		fsl,data-mapping = "spwg";
+		fsl,data-width = <18>;
+		status = "okay";
+
+		display-timings {
+			native-mode = <&timing0>;
+			timing0: hsd100pxn1 {
+				clock-frequency = <65000000>;
+				hactive = <1024>;
+				vactive = <768>;
+				hback-porch = <220>;
+				hfront-porch = <40>;
+				vback-porch = <21>;
+				vfront-porch = <7>;
+				hsync-len = <60>;
+				vsync-len = <10>;
+			};
+		};
+	};
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie>;
+	reset-gpio = <&gpio7 12 0>;
+	status = "okay";
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm1>;
+	status = "okay";
+};
+
+&snvs_poweroff {
+	status = "okay";
+};
+
+&ssi2 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&uart5 {
+	compatible = "fsl,imx21-uart";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart5>;
+	status = "okay";
+
+	/* enable rts/cts usage on uart5 */
+	fsl,uart-has-rtscts;
+};
+
+&usbh1 {
+	vbus-supply = <&reg_usb_h1_vbus>;
+	status = "okay";
+};
+
+&usbotg {
+	vbus-supply = <&reg_usb_otg_vbus>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbotg>;
+	disable-over-current;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	bus-width = <8>;
+/* 	cd-gpios = <&gpio2 2 0>; */
+	wp-gpios = <&gpio2 3 0>;
+	no-1-8-v;
+	vmmc-supply = <&wlan_en_reg>;
+	non-removable;    /* non-removable is not a variable, the fact it is */
+	                  /* listed is all that is used by driver  */
+	cap-power-off-card;
+	status = "okay";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+	wlcore: wlcore@0 {
+		compatible = "ti,wl1835";
+		reg = <2>;
+		interrupt-parent = <&gpio4>;
+		interrupts = <6 IRQ_TYPE_EDGE_RISING>;
+	};
+};
+
+&usdhc3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	bus-width = <8>;
+	cd-gpios = <&gpio2 0 0>;
+	wp-gpios = <&gpio2 1 0>;
+	status = "okay";
+};
+
+&usdhc4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc4>;
+	bus-width = <8>;
+	non-removable;
+	no-1-8-v;
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
index d3e54e4..ee91732 100644
--- a/arch/arm/boot/dts/imx6qdl-udoo.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-udoo.dtsi
@@ -9,6 +9,8 @@
  *
  */
 
+#include <dt-bindings/gpio/gpio.h>
+
 / {
 	chosen {
 		stdout-path = &uart2;
@@ -18,23 +20,6 @@
 		reg = <0x10000000 0x40000000>;
 	};
 
-	regulators {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		reg_usb_h1_vbus: regulator@0 {
-			compatible = "regulator-fixed";
-			reg = <0>;
-			regulator-name = "usb_h1_vbus";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			enable-active-high;
-			startup-delay-us = <2>; /* USB2415 requires a POR of 1 us minimum */
-			gpio = <&gpio7 12 0>;
-		};
-	};
-
 	sound {
 		compatible = "fsl,imx6q-udoo-ac97",
 			     "fsl,imx-audio-ac97";
@@ -67,8 +52,57 @@
 	status = "okay";
 };
 
+&i2c3 { // CSI camera (CN11) and LVDS 7 inches touch panel (CN13)
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+	ov5640_mipi: ov5640_mipi@3c {
+		compatible = "ovti,ov5640_mipi";
+		reg = <0x3c>;
+		clocks = <&clks IMX6QDL_CLK_CKO>;
+		clock-names = "csi_mclk";
+		pwn-gpios = <&gpio6 4 GPIO_ACTIVE_LOW>;
+		rst-gpios = <&gpio6 5 GPIO_ACTIVE_HIGH>;
+		csi_id = <0>;
+		mclk = <24000000>;
+		mclk_source = <0>;
+	};
+};
+
 &iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
 	imx6q-udoo {
+		pinctrl_hog: hoggrp {
+			fsl,pins = <
+				// Internal GPIOs
+				MX6QDL_PAD_NANDF_D4__GPIO2_IO04			0x80000000  // 5v enable
+				MX6QDL_PAD_NANDF_CS0__GPIO6_IO11		0x80000000  // Vtt enable
+
+				MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26		0x80000000  // Debug UART (J18)
+
+				MX6QDL_PAD_GPIO_17__GPIO7_IO12			0x80000000  // USB hub reset
+				MX6QDL_PAD_NANDF_CS2__CCM_CLKO2			0x130b0     // USB hub clock
+				MX6QDL_PAD_EIM_WAIT__GPIO5_IO00			0xb0b1      // USB OTG select
+
+				MX6QDL_PAD_NANDF_D5__GPIO2_IO05			0x80000000  // SD card power
+				MX6QDL_PAD_SD3_DAT5__GPIO7_IO00			0x80000000  // SD card detect
+
+				MX6QDL_PAD_GPIO_16__GPIO7_IO11			0xb0b1      // SAM3X OTG vbus_en
+				MX6QDL_PAD_SD4_DAT7__GPIO2_IO15			0x80000000  // SAM3X usb host
+				MX6QDL_PAD_GPIO_3__GPIO1_IO03			0x30b1      // Arduino pinout pin 12
+
+				MX6QDL_PAD_GPIO_2__GPIO1_IO02			0x80000000  // LVDS panel on (CN13)
+				MX6QDL_PAD_GPIO_4__GPIO1_IO04			0x80000000  // LVDS backlight on (CN13)
+
+				MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04		0x1f071 	// CSI camera enable (CN11)
+				MX6QDL_PAD_CSI0_DAT19__GPIO6_IO05		0x1f071 	// CSI camera reset (CN11)
+				MX6QDL_PAD_CSI0_MCLK__CCM_CLKO1			0x130b0		// CSI master clock (CN11)
+			>;
+		};
+
 		pinctrl_enet: enetgrp {
 			fsl,pins = <
 				MX6QDL_PAD_RGMII_RXC__RGMII_RXC		0x1b0b0
@@ -97,6 +131,13 @@
 			>;
 		};
 
+		pinctrl_i2c3: i2c3grp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_5__I2C3_SCL		0x4001b8b1
+				MX6QDL_PAD_GPIO_6__I2C3_SDA		0x4001b8b1
+			>;
+		};
+
 		pinctrl_uart2: uart2grp {
 			fsl,pins = <
 				MX6QDL_PAD_EIM_D26__UART2_TX_DATA	0x1b0b1
@@ -104,6 +145,13 @@
 			>;
 		};
 
+		pinctrl_uart4: uart4grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 	0x1b0b1
+				MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 	0x1b0b1
+			>;
+		};
+
 		pinctrl_usbh: usbhgrp {
 			fsl,pins = <
 				MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000
@@ -160,12 +208,26 @@
 	status = "okay";
 };
 
-&usbh1 {
+&uart4 { // iMX6-Arduino internal serial port - ttymxc3
 	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_usbh>;
-	vbus-supply = <&reg_usb_h1_vbus>;
-	clocks = <&clks 201>;
+	pinctrl-0 = <&pinctrl_uart4>;
+	status = "okay";
+};
+
+&usbh1 {
 	status = "okay";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+	hub: usb2415@01 {
+		compatible = "generic-onboard-device";
+		reg = <0x01>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usbh>;
+		clocks = <&clks IMX6QDL_CLK_CKO>;
+		reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
+		reset-duration-us = <2>;
+	};
 };
 
 &usdhc3 {
@@ -189,3 +251,11 @@
 	ac97-gpios = <&gpio4 19 0 &gpio4 18 0 &gpio2 30 0>;
 	status = "okay";
 };
+
+&mipi_csi {
+	status = "okay";
+	ipu_id = <0>;
+	csi_id = <0>;
+	v_channel = <0>;
+	lanes = <2>;
+};
diff --git a/arch/arm/boot/dts/imx6qdl-wandboard-revb1.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard-revb1.dtsi
index ef7fa62..b5d0f58 100644
--- a/arch/arm/boot/dts/imx6qdl-wandboard-revb1.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-wandboard-revb1.dtsi
@@ -11,6 +11,24 @@
 
 #include "imx6qdl-wandboard.dtsi"
 
+/ {
+	rfkill {
+		compatible = "wand,imx6qdl-wandboard-rfkill";
+		pinctrl-names = "default";
+		pinctrl-0 = <>;
+
+		bluetooth-on = <&gpio3 13 0>;
+		bluetooth-wake = <&gpio3 14 0>;
+		bluetooth-host-wake = <&gpio3 15 0>;
+
+		wifi-ref-on = <&gpio2 29 0>;
+		wifi-rst-n = <&gpio5 2 0>;
+		wifi-reg-on = <&gpio1 26 0>;
+		wifi-host-wake = <&gpio1 29 0>;
+		wifi-wake = <&gpio1 30 0>;
+	};
+};
+
 &iomuxc {
 	pinctrl-0 = <&pinctrl_hog>;
 
@@ -37,6 +55,5 @@
 &usdhc2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_usdhc2>;
-	non-removable;
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/imx6qdl-wandboard-revc1.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard-revc1.dtsi
index 8d893a7..b2097ef 100644
--- a/arch/arm/boot/dts/imx6qdl-wandboard-revc1.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-wandboard-revc1.dtsi
@@ -11,6 +11,24 @@
 
 #include "imx6qdl-wandboard.dtsi"
 
+/ {
+	rfkill {
+		compatible = "wand,imx6qdl-wandboard-rfkill";
+		pinctrl-names = "default";
+		pinctrl-0 = <>;
+
+		bluetooth-on = <&gpio5 21 0>;
+		bluetooth-wake = <&gpio5 30 0>;
+		bluetooth-host-wake = <&gpio5 20 0>;
+
+		wifi-ref-on = <&gpio5 31 0>; /* Wifi Power Enable */
+		wifi-rst-n = <&gpio6 0 0>; /* WIFI_ON reset */
+		wifi-reg-on = <&gpio1 26 0>; /* WL_REG_ON */
+		wifi-host-wake = <&gpio1 29 0>; /* WL_HOST_WAKE */
+		wifi-wake = <&gpio1 30 0>; /* WL_WAKE */
+	};
+};
+
 &iomuxc {
 	pinctrl-0 = <&pinctrl_hog>;
 
diff --git b/arch/arm/boot/dts/imx6sl-evk-wl1835.dts b/arch/arm/boot/dts/imx6sl-evk-wl1835.dts
new file mode 100644
index 0000000..e5853f3
--- /dev/null
+++ b/arch/arm/boot/dts/imx6sl-evk-wl1835.dts
@@ -0,0 +1,633 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include "imx6sl.dtsi"
+
+/ {
+	model = "Freescale i.MX6 SoloLite EVK Board";
+	compatible = "fsl,imx6sl-evk", "fsl,imx6sl";
+
+	memory {
+		reg = <0x80000000 0x40000000>;
+	};
+
+	backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm1 0 5000000>;
+		brightness-levels = <0 4 8 16 32 64 128 255>;
+		default-brightness-level = <6>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_led>;
+
+		user {
+			label = "debug";
+			gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg_usb_otg1_vbus: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "usb_otg1_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			gpio = <&gpio4 0 0>;
+			enable-active-high;
+			vin-supply = <&swbst_reg>;
+		};
+
+		reg_usb_otg2_vbus: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "usb_otg2_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			gpio = <&gpio4 2 0>;
+			enable-active-high;
+			vin-supply = <&swbst_reg>;
+		};
+
+		reg_aud3v: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "wm8962-supply-3v15";
+			regulator-min-microvolt = <3150000>;
+			regulator-max-microvolt = <3150000>;
+			regulator-boot-on;
+		};
+
+		reg_aud4v: regulator@3 {
+			compatible = "regulator-fixed";
+			reg = <3>;
+			regulator-name = "wm8962-supply-4v2";
+			regulator-min-microvolt = <4325000>;
+			regulator-max-microvolt = <4325000>;
+			regulator-boot-on;
+		};
+
+		reg_lcd_3v3: regulator@4 {
+			compatible = "regulator-fixed";
+			reg = <4>;
+			regulator-name = "lcd-3v3";
+			gpio = <&gpio4 3 0>;
+			enable-active-high;
+		};
+
+		wlan_en_reg: regulator@5 {
+			compatible = "regulator-fixed";
+			regulator-name = "wlan-en-regulator";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			/* WLAN_EN GPIO for this board – Bank5, pin13 */
+			gpio = <&gpio5 13 0>;
+			enable-active-high;
+		};
+	};
+
+	sound {
+		compatible = "fsl,imx6sl-evk-wm8962", "fsl,imx-audio-wm8962";
+		model = "wm8962-audio";
+		ssi-controller = <&ssi2>;
+		audio-codec = <&codec>;
+		audio-routing =
+			"Headphone Jack", "HPOUTL",
+			"Headphone Jack", "HPOUTR",
+			"Ext Spk", "SPKOUTL",
+			"Ext Spk", "SPKOUTR",
+			"AMIC", "MICBIAS",
+			"IN3R", "AMIC";
+		mux-int-port = <2>;
+		mux-ext-port = <3>;
+	};
+
+	kim {
+	        compatible = "kim";
+	        nshutdown_gpio = <134>;  // GPIO5_6 The wl8 driver expects gpio to be an integer, so gpio5_6 is (5-1)*32+6=134
+	        dev_name = "/dev/ttymxc3";
+	        flow_cntrl = <1>;
+	        baud_rate = <3000000>;
+	};
+
+	btwilink {
+	        compatible = "btwilink";
+	};
+};
+
+&audmux {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_audmux3>;
+	status = "okay";
+};
+
+&ecspi1 {
+	fsl,spi-num-chipselects = <1>;
+	cs-gpios = <&gpio4 11 0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi1>;
+	status = "okay";
+
+	flash: m25p80@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "st,m25p32";
+		spi-max-frequency = <20000000>;
+		reg = <0>;
+	};
+};
+
+&fec {
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pinctrl_fec>;
+	pinctrl-1 = <&pinctrl_fec_sleep>;
+	phy-mode = "rmii";
+	status = "okay";
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	pmic: pfuze100@08 {
+		compatible = "fsl,pfuze100";
+		reg = <0x08>;
+
+		regulators {
+			sw1a_reg: sw1ab {
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1875000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <6250>;
+			};
+
+			sw1c_reg: sw1c {
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1875000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <6250>;
+			};
+
+			sw2_reg: sw2 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw3a_reg: sw3a {
+				regulator-min-microvolt = <400000>;
+				regulator-max-microvolt = <1975000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw3b_reg: sw3b {
+				regulator-min-microvolt = <400000>;
+				regulator-max-microvolt = <1975000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw4_reg: sw4 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			swbst_reg: swbst {
+				regulator-min-microvolt = <5000000>;
+				regulator-max-microvolt = <5150000>;
+			};
+
+			snvs_reg: vsnvs {
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			vref_reg: vrefddr {
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			vgen1_reg: vgen1 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1550000>;
+				regulator-always-on;
+			};
+
+			vgen2_reg: vgen2 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1550000>;
+			};
+
+			vgen3_reg: vgen3 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vgen4_reg: vgen4 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vgen5_reg: vgen5 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vgen6_reg: vgen6 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	codec: wm8962@1a {
+		compatible = "wlf,wm8962";
+		reg = <0x1a>;
+		clocks = <&clks IMX6SL_CLK_EXTERN_AUDIO>;
+		DCVDD-supply = <&vgen3_reg>;
+		DBVDD-supply = <&reg_aud3v>;
+		AVDD-supply = <&vgen3_reg>;
+		CPVDD-supply = <&vgen3_reg>;
+		MICVDD-supply = <&reg_aud3v>;
+		PLLVDD-supply = <&vgen3_reg>;
+		SPKVDD1-supply = <&reg_aud4v>;
+		SPKVDD2-supply = <&reg_aud4v>;
+	};
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	imx6sl-evk {
+		pinctrl_hog: hoggrp {
+			fsl,pins = <
+				MX6SL_PAD_KEY_ROW7__GPIO4_IO07    0x17059
+				MX6SL_PAD_KEY_COL7__GPIO4_IO06    0x17059
+				MX6SL_PAD_SD2_DAT7__GPIO5_IO00    0x17059
+				MX6SL_PAD_SD2_DAT6__GPIO4_IO29    0x17059
+				MX6SL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059
+				MX6SL_PAD_KEY_COL4__GPIO4_IO00	0x80000000
+				MX6SL_PAD_KEY_COL5__GPIO4_IO02	0x80000000
+				MX6SL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130b0
+				MX6SL_PAD_SD1_DAT2__GPIO5_IO13    0x13059   // reserve two pins from sd1 for wl8 gpio, this is pulled low at reset for WL_EN
+				MX6SL_PAD_SD1_DAT1__GPIO5_IO08    0x13059   // this is for wl_irq which driver will configure as an input with a pull down
+			>;
+		};
+
+		pinctrl_audmux3: audmux3grp {
+			fsl,pins = <
+				MX6SL_PAD_AUD_RXD__AUD3_RXD	  0x4130b0
+				MX6SL_PAD_AUD_TXC__AUD3_TXC	  0x4130b0
+				MX6SL_PAD_AUD_TXD__AUD3_TXD	  0x4110b0
+				MX6SL_PAD_AUD_TXFS__AUD3_TXFS	  0x4130b0
+			>;
+		};
+
+		pinctrl_ecspi1: ecspi1grp {
+			fsl,pins = <
+				MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO	0x100b1
+				MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI	0x100b1
+				MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK	0x100b1
+				MX6SL_PAD_ECSPI1_SS0__GPIO4_IO11	0x80000000
+			>;
+		};
+
+		pinctrl_fec: fecgrp {
+			fsl,pins = <
+				MX6SL_PAD_FEC_MDC__FEC_MDC		0x1b0b0
+				MX6SL_PAD_FEC_MDIO__FEC_MDIO		0x1b0b0
+				MX6SL_PAD_FEC_CRS_DV__FEC_RX_DV		0x1b0b0
+				MX6SL_PAD_FEC_RXD0__FEC_RX_DATA0	0x1b0b0
+				MX6SL_PAD_FEC_RXD1__FEC_RX_DATA1	0x1b0b0
+				MX6SL_PAD_FEC_TX_EN__FEC_TX_EN		0x1b0b0
+				MX6SL_PAD_FEC_TXD0__FEC_TX_DATA0	0x1b0b0
+				MX6SL_PAD_FEC_TXD1__FEC_TX_DATA1	0x1b0b0
+				MX6SL_PAD_FEC_REF_CLK__FEC_REF_OUT	0x4001b0a8
+			>;
+		};
+
+		pinctrl_fec_sleep: fecgrp-sleep {
+			fsl,pins = <
+				MX6SL_PAD_FEC_MDC__GPIO4_IO23      0x3080
+				MX6SL_PAD_FEC_CRS_DV__GPIO4_IO25   0x3080
+				MX6SL_PAD_FEC_RXD0__GPIO4_IO17     0x3080
+				MX6SL_PAD_FEC_RXD1__GPIO4_IO18     0x3080
+				MX6SL_PAD_FEC_TX_EN__GPIO4_IO22    0x3080
+				MX6SL_PAD_FEC_TXD0__GPIO4_IO24     0x3080
+				MX6SL_PAD_FEC_TXD1__GPIO4_IO16     0x3080
+				MX6SL_PAD_FEC_REF_CLK__GPIO4_IO26  0x3080
+			>;
+		};
+
+		pinctrl_i2c1: i2c1grp {
+			fsl,pins = <
+				MX6SL_PAD_I2C1_SCL__I2C1_SCL	0x4001b8b1
+				MX6SL_PAD_I2C1_SDA__I2C1_SDA	0x4001b8b1
+			>;
+		};
+
+
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				MX6SL_PAD_I2C2_SCL__I2C2_SCL	0x4001b8b1
+				MX6SL_PAD_I2C2_SDA__I2C2_SDA	0x4001b8b1
+			>;
+		};
+
+		pinctrl_kpp: kppgrp {
+			fsl,pins = <
+				MX6SL_PAD_KEY_ROW0__KEY_ROW0    0x1b010
+				MX6SL_PAD_KEY_ROW1__KEY_ROW1    0x1b010
+				MX6SL_PAD_KEY_ROW2__KEY_ROW2    0x1b0b0
+				MX6SL_PAD_KEY_COL0__KEY_COL0    0x110b0
+				MX6SL_PAD_KEY_COL1__KEY_COL1    0x110b0
+				MX6SL_PAD_KEY_COL2__KEY_COL2    0x110b0
+			>;
+		};
+
+		pinctrl_lcd: lcdgrp {
+			fsl,pins = <
+				MX6SL_PAD_LCD_DAT0__LCD_DATA00 0x1b0b0
+				MX6SL_PAD_LCD_DAT1__LCD_DATA01 0x1b0b0
+				MX6SL_PAD_LCD_DAT2__LCD_DATA02 0x1b0b0
+				MX6SL_PAD_LCD_DAT3__LCD_DATA03 0x1b0b0
+				MX6SL_PAD_LCD_DAT4__LCD_DATA04 0x1b0b0
+				MX6SL_PAD_LCD_DAT5__LCD_DATA05 0x1b0b0
+				MX6SL_PAD_LCD_DAT6__LCD_DATA06 0x1b0b0
+				MX6SL_PAD_LCD_DAT7__LCD_DATA07 0x1b0b0
+				MX6SL_PAD_LCD_DAT8__LCD_DATA08 0x1b0b0
+				MX6SL_PAD_LCD_DAT9__LCD_DATA09 0x1b0b0
+				MX6SL_PAD_LCD_DAT10__LCD_DATA10 0x1b0b0
+				MX6SL_PAD_LCD_DAT11__LCD_DATA11 0x1b0b0
+				MX6SL_PAD_LCD_DAT12__LCD_DATA12 0x1b0b0
+				MX6SL_PAD_LCD_DAT13__LCD_DATA13 0x1b0b0
+				MX6SL_PAD_LCD_DAT14__LCD_DATA14 0x1b0b0
+				MX6SL_PAD_LCD_DAT15__LCD_DATA15 0x1b0b0
+				MX6SL_PAD_LCD_DAT16__LCD_DATA16 0x1b0b0
+				MX6SL_PAD_LCD_DAT17__LCD_DATA17 0x1b0b0
+				MX6SL_PAD_LCD_DAT18__LCD_DATA18 0x1b0b0
+				MX6SL_PAD_LCD_DAT19__LCD_DATA19 0x1b0b0
+				MX6SL_PAD_LCD_DAT20__LCD_DATA20 0x1b0b0
+				MX6SL_PAD_LCD_DAT21__LCD_DATA21 0x1b0b0
+				MX6SL_PAD_LCD_DAT22__LCD_DATA22 0x1b0b0
+				MX6SL_PAD_LCD_DAT23__LCD_DATA23 0x1b0b0
+				MX6SL_PAD_LCD_CLK__LCD_CLK 0x1b0b0
+				MX6SL_PAD_LCD_ENABLE__LCD_ENABLE 0x1b0b0
+				MX6SL_PAD_LCD_HSYNC__LCD_HSYNC 0x1b0b0
+				MX6SL_PAD_LCD_VSYNC__LCD_VSYNC 0x1b0b0
+			>;
+		};
+
+		pinctrl_led: ledgrp {
+			fsl,pins = <
+				MX6SL_PAD_HSIC_STROBE__GPIO3_IO20 0x17059
+			>;
+		};
+
+		pinctrl_pwm1: pwmgrp {
+			fsl,pins = <
+				MX6SL_PAD_PWM1__PWM1_OUT 0x110b0
+			>;
+		};
+
+		pinctrl_uart1: uart1grp {
+			fsl,pins = <
+				MX6SL_PAD_UART1_RXD__UART1_RX_DATA	0x1b0b1
+				MX6SL_PAD_UART1_TXD__UART1_TX_DATA	0x1b0b1
+			>;
+		};
+
+		pinctrl_uart4: uart4grp {
+			fsl,pins = <
+				MX6SL_PAD_SD1_DAT4__UART4_RX_DATA 0x13059 // used for HOST_HCI_RX
+				MX6SL_PAD_SD1_DAT5__UART4_TX_DATA 0x13059 // used for HOST_HCI_TX
+				MX6SL_PAD_SD1_DAT7__UART4_CTS_B 0x13059   // used for HOST_HCI_RTS, note reversed to TI nomenclature
+				MX6SL_PAD_SD1_DAT6__UART4_RTS_B 0x13059   // used for HOST_HCI_CTS
+				MX6SL_PAD_SD1_DAT3__GPIO5_IO06  0x13059   // used for BT_EN
+			>;
+		};
+
+		pinctrl_usbotg1: usbotg1grp {
+			fsl,pins = <
+				MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID	0x17059
+			>;
+		};
+
+		pinctrl_usdhc1: usdhc1grp {
+			fsl,pins = <
+				MX6SL_PAD_SD1_CMD__SD1_CMD		0x17059
+				MX6SL_PAD_SD1_CLK__SD1_CLK		0x10059
+				MX6SL_PAD_SD1_DAT0__SD1_DATA0		0x17059
+				MX6SL_PAD_SD1_DAT1__SD1_DATA1		0x17059
+				MX6SL_PAD_SD1_DAT2__SD1_DATA2		0x17059
+				MX6SL_PAD_SD1_DAT3__SD1_DATA3		0x17059
+				MX6SL_PAD_SD1_DAT4__SD1_DATA4		0x17059
+				MX6SL_PAD_SD1_DAT5__SD1_DATA5		0x17059
+				MX6SL_PAD_SD1_DAT6__SD1_DATA6		0x17059
+				MX6SL_PAD_SD1_DAT7__SD1_DATA7		0x17059
+			>;
+		};
+
+		pinctrl_usdhc2: usdhc2grp {
+			fsl,pins = <
+				MX6SL_PAD_SD2_CMD__SD2_CMD		0x17059
+				MX6SL_PAD_SD2_CLK__SD2_CLK		0x10059
+				MX6SL_PAD_SD2_DAT0__SD2_DATA0		0x17059
+				MX6SL_PAD_SD2_DAT1__SD2_DATA1		0x17059
+				MX6SL_PAD_SD2_DAT2__SD2_DATA2		0x17059
+				MX6SL_PAD_SD2_DAT3__SD2_DATA3		0x17059
+			>;
+		};
+
+		pinctrl_usdhc2_100mhz: usdhc2grp100mhz {
+			fsl,pins = <
+				MX6SL_PAD_SD2_CMD__SD2_CMD		0x170b9
+				MX6SL_PAD_SD2_CLK__SD2_CLK		0x100b9
+				MX6SL_PAD_SD2_DAT0__SD2_DATA0		0x170b9
+				MX6SL_PAD_SD2_DAT1__SD2_DATA1		0x170b9
+				MX6SL_PAD_SD2_DAT2__SD2_DATA2		0x170b9
+				MX6SL_PAD_SD2_DAT3__SD2_DATA3		0x170b9
+			>;
+		};
+
+		pinctrl_usdhc2_200mhz: usdhc2grp200mhz {
+			fsl,pins = <
+				MX6SL_PAD_SD2_CMD__SD2_CMD		0x170f9
+				MX6SL_PAD_SD2_CLK__SD2_CLK		0x100f9
+				MX6SL_PAD_SD2_DAT0__SD2_DATA0		0x170f9
+				MX6SL_PAD_SD2_DAT1__SD2_DATA1		0x170f9
+				MX6SL_PAD_SD2_DAT2__SD2_DATA2		0x170f9
+				MX6SL_PAD_SD2_DAT3__SD2_DATA3		0x170f9
+			>;
+		};
+
+		pinctrl_usdhc3: usdhc3grp {
+			fsl,pins = <
+				MX6SL_PAD_SD3_CMD__SD3_CMD		0x17059
+				MX6SL_PAD_SD3_CLK__SD3_CLK		0x10059
+				MX6SL_PAD_SD3_DAT0__SD3_DATA0		0x17059
+				MX6SL_PAD_SD3_DAT1__SD3_DATA1		0x17059
+				MX6SL_PAD_SD3_DAT2__SD3_DATA2		0x17059
+				MX6SL_PAD_SD3_DAT3__SD3_DATA3		0x17059
+			>;
+		};
+	};
+};
+
+&kpp {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_kpp>;
+	linux,keymap = <
+			MATRIX_KEY(0x0, 0x0, KEY_UP)         /* ROW0, COL0 */
+			MATRIX_KEY(0x0, 0x1, KEY_DOWN)       /* ROW0, COL1 */
+			MATRIX_KEY(0x0, 0x2, KEY_ENTER)      /* ROW0, COL2 */
+			MATRIX_KEY(0x1, 0x0, KEY_HOME)       /* ROW1, COL0 */
+			MATRIX_KEY(0x1, 0x1, KEY_RIGHT)      /* ROW1, COL1 */
+			MATRIX_KEY(0x1, 0x2, KEY_LEFT)       /* ROW1, COL2 */
+			MATRIX_KEY(0x2, 0x0, KEY_VOLUMEDOWN) /* ROW2, COL0 */
+			MATRIX_KEY(0x2, 0x1, KEY_VOLUMEUP)   /* ROW2, COL1 */
+	>;
+	status = "okay";
+};
+
+&lcdif {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_lcd>;
+	lcd-supply = <&reg_lcd_3v3>;
+	display = <&display0>;
+	status = "okay";
+
+	display0: display0 {
+		bits-per-pixel = <32>;
+		bus-width = <24>;
+
+		display-timings {
+			native-mode = <&timing0>;
+			timing0: timing0 {
+				clock-frequency = <33500000>;
+				hactive = <800>;
+				vactive = <480>;
+				hback-porch = <89>;
+				hfront-porch = <164>;
+				vback-porch = <23>;
+				vfront-porch = <10>;
+				hsync-len = <10>;
+				vsync-len = <10>;
+				hsync-active = <0>;
+				vsync-active = <0>;
+				de-active = <1>;
+				pixelclk-active = <0>;
+			};
+		};
+	};
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pwm1>;
+	status = "okay";
+};
+
+&snvs_poweroff {
+	status = "okay";
+};
+
+&ssi2 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&uart4 {
+	compatible = "fsl,imx21-uart";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart4>;
+	status = "okay";
+
+	/* enable rts/cts usage on uart4 */
+	fsl,uart-has-rtscts;
+};
+
+&usbotg1 {
+	vbus-supply = <&reg_usb_otg1_vbus>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usbotg1>;
+	disable-over-current;
+	status = "okay";
+};
+
+&usbotg2 {
+	vbus-supply = <&reg_usb_otg2_vbus>;
+	dr_mode = "host";
+	disable-over-current;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+	cd-gpios = <&gpio5 0 0>;
+	wp-gpios = <&gpio4 29 0>;
+	status = "okay";
+};
+
+&usdhc3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	keep-power-in-suspend;
+	enable-sdio-wakeup;
+	vmmc-supply = <&wlan_en_reg>;
+	non-removable;    // non-removable is not a variable, the fact it is listed is all that is used by driver
+	cap-power-off-card;
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	wlcore: wlcore@0 {
+		compatible = "ti,wl1835";
+		reg = <2>;
+		interrupt-parent = <&gpio5>;
+		interrupts = <8 IRQ_TYPE_EDGE_RISING>;
+	};
+};
diff --git b/arch/arm/boot/dts/imx6ul-14x14-evk-ism43362-b81-evb.dts b/arch/arm/boot/dts/imx6ul-14x14-evk-ism43362-b81-evb.dts
new file mode 100644
index 0000000..5687142
--- /dev/null
+++ b/arch/arm/boot/dts/imx6ul-14x14-evk-ism43362-b81-evb.dts
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "imx6ul.dtsi"
+
+/ {
+	model = "Freescale i.MX6 UltraLite 14x14 EVK Board";
+	compatible = "fsl,imx6ul-14x14-evk", "fsl,imx6ul";
+
+	chosen {
+		stdout-path = &uart1;
+	};
+
+	memory {
+		reg = <0x80000000 0x20000000>;
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg_sd1_vmmc: sd1_regulator {
+			compatible = "regulator-fixed";
+			regulator-name = "VSD_3V3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+			enable-active-high;
+		};
+
+		wlreg_on: fixedregulator@100 {
+			compatible = "regulator-fixed";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-name = "wlreg_on";
+			gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+			startup-delay-us = <100>;
+			enable-active-high;
+		};
+	};
+};
+
+&cpu0 {
+	arm-supply = <&reg_arm>;
+	soc-supply = <&reg_soc>;
+};
+
+&fec1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet1>;
+	phy-mode = "rmii";
+	phy-handle = <&ethphy0>;
+	status = "okay";
+};
+
+&fec2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_enet2>;
+	phy-mode = "rmii";
+	phy-handle = <&ethphy1>;
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@2 {
+			reg = <2>;
+		};
+
+		ethphy1: ethernet-phy@1 {
+			reg = <1>;
+		};
+	};
+};
+
+&qspi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_qspi>;
+	status = "okay";
+
+	flash0: n25q256a@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "micron,n25q256a";
+		spi-max-frequency = <29000000>;
+		reg = <0>;
+	};
+};
+
+&snvs_poweroff {
+	status = "okay";
+};
+
+&tsc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_tsc>;
+	xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+	measure-delay-time = <0xffff>;
+	pre-charge-time = <0xfff>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	fsl,uart-has-rtscts;
+	status = "okay";
+};
+
+&usbotg1 {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+&usbotg2 {
+	dr_mode = "host";
+	disable-over-current;
+	status = "okay";
+};
+
+&reg_sd1_vmmc {
+	regulator-always-on;
+};
+
+&usdhc1 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+	cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
+	no-1-8-v;
+	keep-power-in-suspend;
+	wakeup-source;
+	vmmc-supply = <&reg_sd1_vmmc>;
+	status = "okay";
+};
+
+&usdhc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc2>;
+	no-1-8-v;
+	keep-power-in-suspend;
+	wakeup-source;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+
+	pinctrl_csi1: csi1grp {
+		fsl,pins = <
+			MX6UL_PAD_CSI_MCLK__CSI_MCLK		0x1b088
+			MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK	0x1b088
+			MX6UL_PAD_CSI_VSYNC__CSI_VSYNC		0x1b088
+			MX6UL_PAD_CSI_HSYNC__CSI_HSYNC		0x1b088
+			MX6UL_PAD_CSI_DATA00__CSI_DATA02	0x1b088
+			MX6UL_PAD_CSI_DATA01__CSI_DATA03	0x1b088
+			MX6UL_PAD_CSI_DATA02__CSI_DATA04	0x1b088
+			MX6UL_PAD_CSI_DATA03__CSI_DATA05	0x1b088
+			MX6UL_PAD_CSI_DATA04__CSI_DATA06	0x1b088
+			MX6UL_PAD_CSI_DATA05__CSI_DATA07	0x1b088
+			MX6UL_PAD_CSI_DATA06__CSI_DATA08	0x1b088
+			MX6UL_PAD_CSI_DATA07__CSI_DATA09	0x1b088
+		>;
+	};
+
+	pinctrl_enet1: enet1grp {
+		fsl,pins = <
+			MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN	0x1b0b0
+			MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER	0x1b0b0
+			MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00	0x1b0b0
+			MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01	0x1b0b0
+			MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN	0x1b0b0
+			MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00	0x1b0b0
+			MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01	0x1b0b0
+			MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1	0x4001b031
+		>;
+	};
+
+	pinctrl_enet2: enet2grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO07__ENET2_MDC		0x1b0b0
+			MX6UL_PAD_GPIO1_IO06__ENET2_MDIO	0x1b0b0
+			MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN	0x1b0b0
+			MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER	0x1b0b0
+			MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00	0x1b0b0
+			MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01	0x1b0b0
+			MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN	0x1b0b0
+			MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00	0x1b0b0
+			MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01	0x1b0b0
+			MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2	0x4001b031
+			MX6UL_PAD_SNVS_TAMPER0__GPIO5_IO00	0x17059
+		>;
+	};
+
+	pinctrl_flexcan1: flexcan1grp{
+		fsl,pins = <
+			MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX	0x1b020
+			MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX	0x1b020
+		>;
+	};
+
+	pinctrl_flexcan2: flexcan2grp{
+		fsl,pins = <
+			MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX	0x1b020
+			MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX	0x1b020
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
+			MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
+			MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
+		>;
+	};
+
+	pinctrl_lcdif_dat: lcdifdatgrp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79
+			MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79
+			MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x79
+			MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x79
+			MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x79
+			MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x79
+			MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x79
+			MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x79
+			MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x79
+			MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x79
+			MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x79
+			MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x79
+			MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x79
+			MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x79
+			MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x79
+			MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x79
+			MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x79
+			MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x79
+			MX6UL_PAD_LCD_DATA18__LCDIF_DATA18  0x79
+			MX6UL_PAD_LCD_DATA19__LCDIF_DATA19  0x79
+			MX6UL_PAD_LCD_DATA20__LCDIF_DATA20  0x79
+			MX6UL_PAD_LCD_DATA21__LCDIF_DATA21  0x79
+			MX6UL_PAD_LCD_DATA22__LCDIF_DATA22  0x79
+			MX6UL_PAD_LCD_DATA23__LCDIF_DATA23  0x79
+		>;
+	};
+
+	pinctrl_lcdif_ctrl: lcdifctrlgrp {
+		fsl,pins = <
+			MX6UL_PAD_LCD_CLK__LCDIF_CLK	    0x79
+			MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x79
+			MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x79
+			MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x79
+			/* used for lcd reset */
+			MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09  0x79
+		>;
+	};
+
+	pinctrl_qspi: qspigrp {
+		fsl,pins = <
+			MX6UL_PAD_NAND_WP_B__QSPI_A_SCLK	0x70a1
+			MX6UL_PAD_NAND_READY_B__QSPI_A_DATA00	0x70a1
+			MX6UL_PAD_NAND_CE0_B__QSPI_A_DATA01	0x70a1
+			MX6UL_PAD_NAND_CE1_B__QSPI_A_DATA02	0x70a1
+			MX6UL_PAD_NAND_CLE__QSPI_A_DATA03	0x70a1
+			MX6UL_PAD_NAND_DQS__QSPI_A_SS0_B	0x70a1
+		>;
+	};
+
+	pinctrl_pwm1: pwm1grp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO08__PWM1_OUT   0x110b0
+		>;
+	};
+
+	pinctrl_sim2: sim2grp {
+		fsl,pins = <
+			MX6UL_PAD_CSI_DATA03__SIM2_PORT1_PD		0xb808
+			MX6UL_PAD_CSI_DATA04__SIM2_PORT1_CLK		0x31
+			MX6UL_PAD_CSI_DATA05__SIM2_PORT1_RST_B		0xb808
+			MX6UL_PAD_CSI_DATA06__SIM2_PORT1_SVEN		0xb808
+			MX6UL_PAD_CSI_DATA07__SIM2_PORT1_TRXD		0xb809
+			MX6UL_PAD_CSI_DATA02__GPIO4_IO23		0x3008
+		>;
+	};
+
+	pinctrl_tsc: tscgrp {
+		fsl,pins = <
+			MX6UL_PAD_GPIO1_IO01__GPIO1_IO01		0xb0
+			MX6UL_PAD_GPIO1_IO02__GPIO1_IO02		0xb0
+			MX6UL_PAD_GPIO1_IO03__GPIO1_IO03		0xb0
+			MX6UL_PAD_GPIO1_IO04__GPIO1_IO04		0xb0
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
+			MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX	0x1b0b1
+			MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX	0x1b0b1
+			MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS	0x1b0b1
+			MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS	0x1b0b1
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD     	0x17059
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK     	0x10071
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 	0x17059
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 	0x17059
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 	0x17059
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 	0x17059
+			MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x17059 /* SD1 CD */
+			MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT    0x17059 /* SD1 VSELECT */
+			MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x17059 /* SD1 RESET */
+			MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x3029
+		>;
+	};
+
+	pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170b9
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100b9
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9
+			MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x3029
+		>;
+	};
+
+	pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
+		fsl,pins = <
+			MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170f9
+			MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100f9
+			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
+			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
+			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
+			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
+			MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x3029
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x17059
+			MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x17059
+			MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
+			MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
+			MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
+			MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
+		>;
+	};
+};
diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts
index 01e1e2d..1f02dbd 100644
--- a/arch/arm/boot/dts/omap3-beagle-xm.dts
+++ b/arch/arm/boot/dts/omap3-beagle-xm.dts
@@ -205,6 +205,25 @@
 		>;
 	};
 
+	spi3_pins: pinmux_spi3_pins {
+		pinctrl-single,pins = <
+			0x128 (PIN_INPUT | MUX_MODE1) /* sdmmc2_clk.mcspi3_clk gpio_130 */
+			0x12a (PIN_OUTPUT | MUX_MODE1) /* sdmmc2_cmd.mcspi3_simo gpio_131 */
+			0x12c (PIN_INPUT_PULLUP | MUX_MODE1) /* sdmmc2_dat0.mcspi3_somi gpio_132 */
+			0x130 (PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat2.mcspi3_cs1 gpio_134 */
+			0x132 (PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat3.mcspi3_cs0 gpio_135 */
+		>;
+	};
+
+	spi4_pins: pinmux_spi4_pins {
+		pinctrl-single,pins = <
+			0x15c (PIN_INPUT | MUX_MODE1) /* mcbsp1_clkr.mcspi4_clk gpio_156 */
+			0x160 (PIN_OUTPUT | MUX_MODE1) /* mcbsp1_dx.mcspi4_simo gpio_158 */
+			0x162 (PIN_INPUT_PULLUP | MUX_MODE1) /* mcbsp1_dr.mcspi4_somi gpio_159 */
+			0x166 (PIN_OUTPUT | MUX_MODE1) /* mcbsp1_fsx.mcspi4_cs0 gpio_161 */
+		>;
+	};
+
 	hsusb2_pins: pinmux_hsusb2_pins {
 		pinctrl-single,pins = <
 			OMAP3_CORE1_IOPAD(0x21d4, PIN_INPUT_PULLDOWN | MUX_MODE3)	/* mcspi1_cs3.hsusb2_data2 */
@@ -310,6 +329,36 @@
 	status = "disabled";
 };
 
+&mcspi3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi3_pins>;
+	status = "okay";
+
+	spidev0: spi@0 {
+		compatible = "spidev";
+		reg = <0>;
+		spi-max-frequency = <48000000>;
+	};
+
+	spidev1: spi@1 {
+		compatible = "spidev";
+		reg = <1>;
+		spi-max-frequency = <48000000>;
+	};
+};
+
+&mcspi4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi4_pins>;
+	status = "okay";
+
+	spidev2: spi@0 {
+		compatible = "spidev";
+		reg = <0>;
+		spi-max-frequency = <48000000>;
+	};
+};
+
 &twl_gpio {
 	ti,use-leds;
 	/* pullups: BIT(1) */
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 4602866..09fd812 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -271,9 +271,18 @@
 			codec {
 			};
 		};
+
+		twl_power: power {
+			compatible = "ti,twl4030-power-reset";
+			ti,use_poweroff;
+		};
 	};
 };
 
+&i2c2 {
+	clock-frequency = <400000>;
+};
+
 #include "twl4030.dtsi"
 #include "twl4030_omap3.dtsi"
 
diff --git a/arch/arm/boot/dts/omap4-panda-a4.dts b/arch/arm/boot/dts/omap4-panda-a4.dts
index 78d3631..67ee5b4 100644
--- a/arch/arm/boot/dts/omap4-panda-a4.dts
+++ b/arch/arm/boot/dts/omap4-panda-a4.dts
@@ -10,6 +10,18 @@
 #include "omap443x.dtsi"
 #include "omap4-panda-common.dtsi"
 
+&emif1 {
+	cs1-used;
+	device-handle = <&elpida_ECB240ABACN>;
+	status = "ok";
+};
+
+&emif2 {
+	cs1-used;
+	device-handle = <&elpida_ECB240ABACN>;
+	status = "ok";
+};
+
 /* Pandaboard Rev A4+ have external pullups on SCL & SDA */
 &dss_hdmi_pins {
 	pinctrl-single,pins = <
diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi
index df2e356..cf16679 100644
--- a/arch/arm/boot/dts/omap4-panda-common.dtsi
+++ b/arch/arm/boot/dts/omap4-panda-common.dtsi
@@ -460,16 +460,6 @@
 	};
 };
 
-&emif1 {
-	cs1-used;
-	device-handle = <&elpida_ECB240ABACN>;
-};
-
-&emif2 {
-	cs1-used;
-	device-handle = <&elpida_ECB240ABACN>;
-};
-
 &mcbsp1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mcbsp1_pins>;
diff --git b/arch/arm/boot/dts/omap4-panda-es-b3.dts b/arch/arm/boot/dts/omap4-panda-es-b3.dts
new file mode 100644
index 0000000..2f1dabc
--- /dev/null
+++ b/arch/arm/boot/dts/omap4-panda-es-b3.dts
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "omap4460.dtsi"
+#include "omap4-panda-common.dtsi"
+
+/ {
+	model = "TI OMAP4 PandaBoard-ES";
+	compatible = "ti,omap4-panda-es", "ti,omap4-panda", "ti,omap4460", "ti,omap4430", "ti,omap4";
+};
+
+/* Audio routing is differnet between PandaBoard4430 and PandaBoardES */
+&sound {
+	ti,model = "PandaBoardES";
+
+	/* Audio routing */
+	ti,audio-routing =
+		"Headset Stereophone", "HSOL",
+		"Headset Stereophone", "HSOR",
+		"Ext Spk", "HFL",
+		"Ext Spk", "HFR",
+		"Line Out", "AUXL",
+		"Line Out", "AUXR",
+		"AFML", "Line In",
+		"AFMR", "Line In";
+};
+
+/* PandaboardES has external pullups on SCL & SDA */
+&dss_hdmi_pins {
+	pinctrl-single,pins = <
+		0x5a (PIN_INPUT_PULLUP | MUX_MODE0)	/* hdmi_cec.hdmi_cec */
+		0x5c (PIN_INPUT | MUX_MODE0)		/* hdmi_scl.hdmi_scl */
+		0x5e (PIN_INPUT | MUX_MODE0)		/* hdmi_sda.hdmi_sda */
+		>;
+};
+
+&omap4_pmx_core {
+	led_gpio_pins: gpio_led_pmx {
+		pinctrl-single,pins = <
+			0xb6 (PIN_OUTPUT | MUX_MODE3)	/* gpio_110 */
+		>;
+	};
+};
+
+&led_wkgpio_pins {
+	pinctrl-single,pins = <
+		0x1c (PIN_OUTPUT | MUX_MODE3)	/* gpio_wk8 */
+	>;
+};
+
+&leds {
+	pinctrl-0 = <
+		&led_gpio_pins
+		&led_wkgpio_pins
+	>;
+
+	heartbeat {
+		gpios = <&gpio4 14 GPIO_ACTIVE_HIGH>;
+	};
+	mmc {
+		gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&gpio1 {
+	 ti,no-reset-on-init;
+};
diff --git a/arch/arm/boot/dts/omap4-panda-es.dts b/arch/arm/boot/dts/omap4-panda-es.dts
index 119f8e6..5c54ccf 100644
--- a/arch/arm/boot/dts/omap4-panda-es.dts
+++ b/arch/arm/boot/dts/omap4-panda-es.dts
@@ -15,6 +15,18 @@
 	compatible = "ti,omap4-panda-es", "ti,omap4-panda", "ti,omap4460", "ti,omap4430", "ti,omap4";
 };
 
+&emif1 {
+	cs1-used;
+	device-handle = <&elpida_ECB240ABACN>;
+	status = "ok";
+};
+
+&emif2 {
+	cs1-used;
+	device-handle = <&elpida_ECB240ABACN>;
+	status = "ok";
+};
+
 /* Audio routing is differnet between PandaBoard4430 and PandaBoardES */
 &sound {
 	ti,model = "PandaBoardES";
diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts
index a0e28b2..3ee41ef 100644
--- a/arch/arm/boot/dts/omap4-panda.dts
+++ b/arch/arm/boot/dts/omap4-panda.dts
@@ -14,3 +14,15 @@
 	model = "TI OMAP4 PandaBoard";
 	compatible = "ti,omap4-panda", "ti,omap4430", "ti,omap4";
 };
+
+&emif1 {
+	cs1-used;
+	device-handle = <&elpida_ECB240ABACN>;
+	status = "ok";
+};
+
+&emif2 {
+	cs1-used;
+	device-handle = <&elpida_ECB240ABACN>;
+	status = "ok";
+};
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index aae5132..45df556 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -501,11 +501,13 @@
 &emif1 {
 	cs1-used;
 	device-handle = <&elpida_ECB240ABACN>;
+	status = "ok";
 };
 
 &emif2 {
 	cs1-used;
 	device-handle = <&elpida_ECB240ABACN>;
+	status = "ok";
 };
 
 &keypad {
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 421fe9f..80dacc1 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -691,6 +691,7 @@
 			hw-caps-read-idle-ctrl;
 			hw-caps-ll-interface;
 			hw-caps-temp-alert;
+			status = "disabled";
 		};
 
 		emif2: emif@4d000000 {
@@ -703,6 +704,7 @@
 			hw-caps-read-idle-ctrl;
 			hw-caps-ll-interface;
 			hw-caps-temp-alert;
+			status = "disabled";
 		};
 
 		ocp2scp@4a0ad000 {
diff --git a/arch/arm/mach-imx/devices/Kconfig b/arch/arm/mach-imx/devices/Kconfig
index 3a55298..aa16f7e 100644
--- a/arch/arm/mach-imx/devices/Kconfig
+++ b/arch/arm/mach-imx/devices/Kconfig
@@ -72,3 +72,9 @@ config IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
 
 config IMX_HAVE_PLATFORM_SPI_IMX
 	bool
+
+config WAND_RFKILL
+	tristate "Wandboard RF Kill support"
+	depends on SOC_IMX6Q
+	default m
+	select RFKILL
diff --git a/arch/arm/mach-imx/devices/Makefile b/arch/arm/mach-imx/devices/Makefile
index e5cf587..eee36d9 100644
--- a/arch/arm/mach-imx/devices/Makefile
+++ b/arch/arm/mach-imx/devices/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX) += platform-sdhci-esdhc-imx.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) +=  platform-spi_imx.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_MX2_EMMA) += platform-mx2-emma.o
+obj-$(CONFIG_WAND_RFKILL) += wand-rfkill.o
diff --git b/arch/arm/mach-imx/devices/wand-rfkill.c b/arch/arm/mach-imx/devices/wand-rfkill.c
new file mode 100644
index 0000000..da7ef9f
--- /dev/null
+++ b/arch/arm/mach-imx/devices/wand-rfkill.c
@@ -0,0 +1,290 @@
+/*
+ * arch/arm/mach-imx/devices/wand-rfkill.c
+ *
+ * Copyright (C) 2013 Vladimir Ermakov <vooon341@gmail.com>
+ *
+ * based on net/rfkill/rfkill-gpio.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+
+struct wand_rfkill_data {
+	struct rfkill *rfkill_dev;
+	int shutdown_gpio;
+	const char *shutdown_name;
+};
+
+static int wand_rfkill_set_block(void *data, bool blocked)
+{
+	struct wand_rfkill_data *rfkill = data;
+
+	pr_debug("wandboard-rfkill: set block %d\n", blocked);
+
+	if (blocked) {
+		if (gpio_is_valid(rfkill->shutdown_gpio))
+			gpio_direction_output(rfkill->shutdown_gpio, 0);
+	} else {
+		if (gpio_is_valid(rfkill->shutdown_gpio))
+			gpio_direction_output(rfkill->shutdown_gpio, 1);
+	}
+
+	return 0;
+}
+
+static const struct rfkill_ops wand_rfkill_ops = {
+	.set_block = wand_rfkill_set_block,
+};
+
+static int wand_rfkill_wifi_probe(struct device *dev,
+		struct device_node *np,
+		struct wand_rfkill_data *rfkill)
+{
+	int ret;
+	int wl_ref_on, wl_rst_n, wl_reg_on, wl_wake, wl_host_wake;
+
+	wl_ref_on = of_get_named_gpio(np, "wifi-ref-on", 0);
+	wl_rst_n = of_get_named_gpio(np, "wifi-rst-n", 0);
+	wl_reg_on = of_get_named_gpio(np, "wifi-reg-on", 0);
+	wl_wake = of_get_named_gpio(np, "wifi-wake", 0);
+	wl_host_wake = of_get_named_gpio(np, "wifi-host-wake", 0);
+
+	if (!gpio_is_valid(wl_rst_n) || !gpio_is_valid(wl_ref_on) ||
+			!gpio_is_valid(wl_reg_on) || !gpio_is_valid(wl_wake) ||
+			!gpio_is_valid(wl_host_wake)) {
+
+		dev_err(dev, "incorrect wifi gpios (%d %d %d %d %d)\n",
+				wl_rst_n, wl_ref_on, wl_reg_on, wl_wake, wl_host_wake);
+		return -EINVAL;
+	}
+
+	dev_info(dev, "initialize wifi chip\n");
+
+	gpio_request(wl_rst_n, "wl_rst_n");
+	gpio_direction_output(wl_rst_n, 0);
+	msleep(11);
+	gpio_set_value(wl_rst_n, 1);
+
+	gpio_request(wl_ref_on, "wl_ref_on");
+	gpio_direction_output(wl_ref_on, 1);
+
+	gpio_request(wl_reg_on, "wl_reg_on");
+	gpio_direction_output(wl_reg_on, 1);
+
+	gpio_request(wl_wake, "wl_wake");
+	gpio_direction_output(wl_wake, 1);
+
+	gpio_request(wl_host_wake, "wl_host_wake");
+	gpio_direction_input(wl_host_wake);
+
+	rfkill->shutdown_name = "wifi_shutdown";
+	rfkill->shutdown_gpio = wl_wake;
+
+	rfkill->rfkill_dev = rfkill_alloc("wifi-rfkill", dev, RFKILL_TYPE_WLAN,
+			&wand_rfkill_ops, rfkill);
+	if (!rfkill->rfkill_dev) {
+		ret = -ENOMEM;
+		goto wifi_fail_free_gpio;
+	}
+
+	ret = rfkill_register(rfkill->rfkill_dev);
+	if (ret < 0)
+		goto wifi_fail_unregister;
+
+	dev_info(dev, "wifi-rfkill registered.\n");
+
+	return 0;
+
+wifi_fail_unregister:
+	rfkill_destroy(rfkill->rfkill_dev);
+wifi_fail_free_gpio:
+	if (gpio_is_valid(wl_rst_n))     gpio_free(wl_rst_n);
+	if (gpio_is_valid(wl_ref_on))    gpio_free(wl_ref_on);
+	if (gpio_is_valid(wl_reg_on))    gpio_free(wl_reg_on);
+	if (gpio_is_valid(wl_wake))      gpio_free(wl_wake);
+	if (gpio_is_valid(wl_host_wake)) gpio_free(wl_host_wake);
+
+	return ret;
+}
+
+static int wand_rfkill_bt_probe(struct device *dev,
+		struct device_node *np,
+		struct wand_rfkill_data *rfkill)
+{
+	int ret;
+	int bt_on, bt_wake, bt_host_wake;
+
+	bt_on = of_get_named_gpio(np, "bluetooth-on", 0);
+	bt_wake = of_get_named_gpio(np, "bluetooth-wake", 0);
+	bt_host_wake = of_get_named_gpio(np, "bluetooth-host-wake", 0);
+
+	if (!gpio_is_valid(bt_on) || !gpio_is_valid(bt_wake) ||
+			!gpio_is_valid(bt_host_wake)) {
+
+		dev_err(dev, "incorrect bt gpios (%d %d %d)\n",
+				bt_on, bt_wake, bt_host_wake);
+		return -EINVAL;
+	}
+
+	dev_info(dev, "initialize bluetooth chip\n");
+
+	gpio_request(bt_on, "bt_on");
+	gpio_direction_output(bt_on, 0);
+	msleep(11);
+	gpio_set_value(bt_on, 1);
+
+	gpio_request(bt_wake, "bt_wake");
+	gpio_direction_output(bt_wake, 1);
+
+	gpio_request(bt_host_wake, "bt_host_wake");
+	gpio_direction_input(bt_host_wake);
+
+	rfkill->shutdown_name = "bluetooth_shutdown";
+	rfkill->shutdown_gpio = bt_wake;
+
+	rfkill->rfkill_dev = rfkill_alloc("bluetooth-rfkill", dev, RFKILL_TYPE_BLUETOOTH,
+			&wand_rfkill_ops, rfkill);
+	if (!rfkill->rfkill_dev) {
+		ret = -ENOMEM;
+		goto bt_fail_free_gpio;
+	}
+
+	ret = rfkill_register(rfkill->rfkill_dev);
+	if (ret < 0)
+		goto bt_fail_unregister;
+
+	dev_info(dev, "bluetooth-rfkill registered.\n");
+
+	return 0;
+
+bt_fail_unregister:
+	rfkill_destroy(rfkill->rfkill_dev);
+bt_fail_free_gpio:
+	if (gpio_is_valid(bt_on))        gpio_free(bt_on);
+	if (gpio_is_valid(bt_wake))      gpio_free(bt_wake);
+	if (gpio_is_valid(bt_host_wake)) gpio_free(bt_host_wake);
+
+	return ret;
+}
+
+static int wand_rfkill_probe(struct platform_device *pdev)
+{
+	struct wand_rfkill_data *rfkill;
+	struct pinctrl *pinctrl;
+	int ret;
+
+	dev_info(&pdev->dev, "Wandboard rfkill initialization\n");
+
+	if (!pdev->dev.of_node) {
+		dev_err(&pdev->dev, "no device tree node\n");
+		return -ENODEV;
+	}
+
+	rfkill = kzalloc(sizeof(*rfkill) * 2, GFP_KERNEL);
+	if (!rfkill)
+		return -ENOMEM;
+
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		int ret = PTR_ERR(pinctrl);
+		dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
+		return ret;
+	}
+
+	/* setup WiFi */
+	ret = wand_rfkill_wifi_probe(&pdev->dev, pdev->dev.of_node, &rfkill[0]);
+	if (ret < 0)
+		goto fail_free_rfkill;
+
+	/* setup bluetooth */
+	ret = wand_rfkill_bt_probe(&pdev->dev, pdev->dev.of_node, &rfkill[1]);
+	if (ret < 0)
+		goto fail_unregister_wifi;
+
+	platform_set_drvdata(pdev, rfkill);
+
+	return 0;
+
+fail_unregister_wifi:
+	if (rfkill[1].rfkill_dev) {
+		rfkill_unregister(rfkill[1].rfkill_dev);
+		rfkill_destroy(rfkill[1].rfkill_dev);
+	}
+
+	/* TODO free gpio */
+
+fail_free_rfkill:
+	kfree(rfkill);
+
+	return ret;
+}
+
+static int wand_rfkill_remove(struct platform_device *pdev)
+{
+	struct wand_rfkill_data *rfkill = platform_get_drvdata(pdev);
+
+	dev_info(&pdev->dev, "Module unloading\n");
+
+	if (!rfkill)
+		return 0;
+
+	/* WiFi */
+	if (gpio_is_valid(rfkill[0].shutdown_gpio))
+		gpio_free(rfkill[0].shutdown_gpio);
+
+	rfkill_unregister(rfkill[0].rfkill_dev);
+	rfkill_destroy(rfkill[0].rfkill_dev);
+
+	/* Bt */
+	if (gpio_is_valid(rfkill[1].shutdown_gpio))
+		gpio_free(rfkill[1].shutdown_gpio);
+
+	rfkill_unregister(rfkill[1].rfkill_dev);
+	rfkill_destroy(rfkill[1].rfkill_dev);
+
+	kfree(rfkill);
+
+	return 0;
+}
+
+static struct of_device_id wand_rfkill_match[] = {
+	{ .compatible = "wand,imx6q-wandboard-rfkill", },
+	{ .compatible = "wand,imx6dl-wandboard-rfkill", },
+	{ .compatible = "wand,imx6qdl-wandboard-rfkill", },
+	{}
+};
+
+static struct platform_driver wand_rfkill_driver = {
+	.driver = {
+		.name = "wandboard-rfkill",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(wand_rfkill_match),
+	},
+	.probe = wand_rfkill_probe,
+	.remove = wand_rfkill_remove
+};
+
+module_platform_driver(wand_rfkill_driver);
+
+MODULE_AUTHOR("Vladimir Ermakov <vooon341@gmail.com>");
+MODULE_DESCRIPTION("Wandboard rfkill driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index f7ff3b9..efcce61 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -123,8 +123,8 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
 	struct omap_device *od;
 	struct omap_hwmod *oh;
 	struct device_node *node = pdev->dev.of_node;
-	const char *oh_name;
-	int oh_cnt, i, ret = 0;
+	const char *oh_name, *rst_name;
+	int oh_cnt, dstr_cnt, i, ret = 0;
 	bool device_active = false;
 
 	oh_cnt = of_property_count_strings(node, "ti,hwmods");
@@ -175,6 +175,26 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
 		omap_device_enable(pdev);
 		pm_runtime_set_active(&pdev->dev);
 	}
+	dstr_cnt =
+		of_property_count_strings(node, "ti,deassert-hard-reset");
+	if (dstr_cnt > 0) {
+		for (i = 0; i < dstr_cnt; i += 2) {
+			of_property_read_string_index(
+				node, "ti,deassert-hard-reset", i,
+				&oh_name);
+			of_property_read_string_index(
+				node, "ti,deassert-hard-reset", i+1,
+				&rst_name);
+			oh = omap_hwmod_lookup(oh_name);
+			if (!oh) {
+				dev_warn(&pdev->dev,
+				"Cannot parse deassert property for '%s'\n",
+				oh_name);
+				break;
+			}
+			omap_hwmod_deassert_hardreset(oh, rst_name);
+		}
+	}
 
 odbfd_exit1:
 	kfree(hwmods);
@@ -191,12 +211,21 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct omap_device *od;
-	int err;
+	int i, err;
 
 	switch (event) {
 	case BUS_NOTIFY_DEL_DEVICE:
-		if (pdev->archdata.od)
-			omap_device_delete(pdev->archdata.od);
+		od = to_omap_device(pdev);
+		if (!od)
+			break;
+
+		for (i = 0; i < od->hwmods_cnt; i++) {
+			/* shutdown hwmods */
+			omap_hwmod_shutdown(od->hwmods[i]);
+			/* we don't remove clocks cause there's no API to do so */
+			/* no harm done, since they will not be created next time */
+		}
+		omap_device_delete(od);
 		break;
 	case BUS_NOTIFY_UNBOUND_DRIVER:
 		od = to_omap_device(pdev);
@@ -770,6 +799,8 @@ int omap_device_idle(struct platform_device *pdev)
 	struct omap_device *od;
 
 	od = to_omap_device(pdev);
+	if (!od)
+		return 0;
 
 	if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
 		dev_warn(&pdev->dev,
diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h
index 58fd4ff..190af42 100644
--- a/arch/x86/include/asm/preempt.h
+++ b/arch/x86/include/asm/preempt.h
@@ -89,8 +89,6 @@ static __always_inline bool __preempt_count_dec_and_test(void)
 	if (____preempt_count_dec_and_test())
 		return true;
 #ifdef CONFIG_PREEMPT_LAZY
-	if (current_thread_info()->preempt_lazy_count)
-		return false;
 	return test_thread_flag(TIF_NEED_RESCHED_LAZY);
 #else
 	return false;
@@ -103,19 +101,8 @@ static __always_inline bool __preempt_count_dec_and_test(void)
 static __always_inline bool should_resched(int preempt_offset)
 {
 #ifdef CONFIG_PREEMPT_LAZY
-	u32 tmp;
-
-	tmp = raw_cpu_read_4(__preempt_count);
-	if (tmp == preempt_offset)
-		return true;
-
-	/* preempt count == 0 ? */
-	tmp &= ~PREEMPT_NEED_RESCHED;
-	if (tmp)
-		return false;
-	if (current_thread_info()->preempt_lazy_count)
-		return false;
-	return test_thread_flag(TIF_NEED_RESCHED_LAZY);
+	return unlikely(raw_cpu_read_4(__preempt_count) == preempt_offset ||
+			test_thread_flag(TIF_NEED_RESCHED_LAZY));
 #else
 	return unlikely(raw_cpu_read_4(__preempt_count) == preempt_offset);
 #endif
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c
index fdd41b1..16575ee 100644
--- a/drivers/clk/samsung/clk-exynos3250.c
+++ b/drivers/clk/samsung/clk-exynos3250.c
@@ -302,10 +302,12 @@ static struct samsung_mux_clock mux_clks[] __initdata = {
 
 	/* SRC_FSYS */
 	MUX(CLK_MOUT_TSADC, "mout_tsadc", group_sclk_p, SRC_FSYS, 28, 4),
+	MUX(CLK_MOUT_MMC2, "mout_mmc2", group_sclk_p, SRC_FSYS, 8, 4),
 	MUX(CLK_MOUT_MMC1, "mout_mmc1", group_sclk_p, SRC_FSYS, 4, 4),
 	MUX(CLK_MOUT_MMC0, "mout_mmc0", group_sclk_p, SRC_FSYS, 0, 4),
 
 	/* SRC_PERIL0 */
+	MUX(CLK_MOUT_UART2, "mout_uart2", group_sclk_p, SRC_PERIL0, 8, 4),
 	MUX(CLK_MOUT_UART1, "mout_uart1", group_sclk_p, SRC_PERIL0, 4, 4),
 	MUX(CLK_MOUT_UART0, "mout_uart0", group_sclk_p, SRC_PERIL0, 0, 4),
 
@@ -389,7 +391,13 @@ static struct samsung_div_clock div_clks[] __initdata = {
 		CLK_SET_RATE_PARENT, 0),
 	DIV(CLK_DIV_MMC0, "div_mmc0", "mout_mmc0", DIV_FSYS1, 0, 4),
 
+	/* DIV_FSYS2 */
+	DIV_F(CLK_DIV_MMC2_PRE, "div_mmc2_pre", "div_mmc2", DIV_FSYS2, 8, 8,
+		CLK_SET_RATE_PARENT, 0),
+	DIV(CLK_DIV_MMC2, "div_mmc2", "mout_mmc2", DIV_FSYS2, 0, 4),
+
 	/* DIV_PERIL0 */
+	DIV(CLK_DIV_UART2, "div_uart2", "mout_uart2", DIV_PERIL0, 8, 4),
 	DIV(CLK_DIV_UART1, "div_uart1", "mout_uart1", DIV_PERIL0, 4, 4),
 	DIV(CLK_DIV_UART0, "div_uart0", "mout_uart0", DIV_PERIL0, 0, 4),
 
@@ -538,6 +546,8 @@ static struct samsung_gate_clock gate_clks[] __initdata = {
 		GATE_SCLK_FSYS, 9, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_EBI, "sclk_ebi", "div_ebi",
 		GATE_SCLK_FSYS, 6, CLK_SET_RATE_PARENT, 0),
+	GATE(CLK_SCLK_MMC2, "sclk_mmc2", "div_mmc2_pre",
+		GATE_SCLK_FSYS, 2, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_MMC1, "sclk_mmc1", "div_mmc1_pre",
 		GATE_SCLK_FSYS, 1, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_MMC0, "sclk_mmc0", "div_mmc0_pre",
@@ -552,6 +562,9 @@ static struct samsung_gate_clock gate_clks[] __initdata = {
 		GATE_SCLK_PERIL, 7, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_SPI0, "sclk_spi0", "div_spi0_pre",
 		GATE_SCLK_PERIL, 6, CLK_SET_RATE_PARENT, 0),
+
+	GATE(CLK_SCLK_UART2, "sclk_uart2", "div_uart2",
+		GATE_SCLK_PERIL, 2, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_UART1, "sclk_uart1", "div_uart1",
 		GATE_SCLK_PERIL, 1, CLK_SET_RATE_PARENT, 0),
 	GATE(CLK_SCLK_UART0, "sclk_uart0", "div_uart0",
@@ -630,6 +643,7 @@ static struct samsung_gate_clock gate_clks[] __initdata = {
 	GATE(CLK_USBOTG, "usbotg", "div_aclk_200", GATE_IP_FSYS, 13, 0, 0),
 	GATE(CLK_USBHOST, "usbhost", "div_aclk_200", GATE_IP_FSYS, 12, 0, 0),
 	GATE(CLK_SROMC, "sromc", "div_aclk_200", GATE_IP_FSYS, 11, 0, 0),
+	GATE(CLK_SDMMC2, "sdmmc2", "div_aclk_200", GATE_IP_FSYS, 7, 0, 0),
 	GATE(CLK_SDMMC1, "sdmmc1", "div_aclk_200", GATE_IP_FSYS, 6, 0, 0),
 	GATE(CLK_SDMMC0, "sdmmc0", "div_aclk_200", GATE_IP_FSYS, 5, 0, 0),
 	GATE(CLK_PDMA1, "pdma1", "div_aclk_200", GATE_IP_FSYS, 1, 0, 0),
@@ -649,6 +663,7 @@ static struct samsung_gate_clock gate_clks[] __initdata = {
 	GATE(CLK_I2C2, "i2c2", "div_aclk_100", GATE_IP_PERIL, 8, 0, 0),
 	GATE(CLK_I2C1, "i2c1", "div_aclk_100", GATE_IP_PERIL, 7, 0, 0),
 	GATE(CLK_I2C0, "i2c0", "div_aclk_100", GATE_IP_PERIL, 6, 0, 0),
+	GATE(CLK_UART2, "uart2", "div_aclk_100", GATE_IP_PERIL, 2, 0, 0),
 	GATE(CLK_UART1, "uart1", "div_aclk_100", GATE_IP_PERIL, 1, 0, 0),
 	GATE(CLK_UART0, "uart0", "div_aclk_100", GATE_IP_PERIL, 0, 0, 0),
 };
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 5f3429f..ee4ec46 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -85,6 +85,20 @@ config GPIO_SYSFS
 	  Kernel drivers may also request that a particular GPIO be
 	  exported to userspace; this can be useful when debugging.
 
+config GPIO_OF_HELPER
+	bool "GPIO OF helper device (EXPERIMENTAL)"
+	depends on OF_GPIO
+	help
+	  Say Y here to add an GPIO OF helper driver
+
+	  Allows you specify a GPIO helper based on OF
+	  which allows simple export of GPIO functionality
+	  in user-space.
+
+	  Features include, value set/get, direction control,
+	  interrupt/value change poll support, event counting
+	  and others.
+
 config GPIO_GENERIC
 	tristate
 
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1e0b74f..8633e85 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_GPIOLIB)		+= gpiolib-legacy.o
 obj-$(CONFIG_OF_GPIO)		+= gpiolib-of.o
 obj-$(CONFIG_GPIO_SYSFS)	+= gpiolib-sysfs.o
 obj-$(CONFIG_GPIO_ACPI)		+= gpiolib-acpi.o
+obj-$(CONFIG_GPIO_OF_HELPER)	+= gpio-of-helper.o
 
 # Device drivers. Generally keep list sorted alphabetically
 obj-$(CONFIG_GPIO_GENERIC)	+= gpio-generic.o
diff --git b/drivers/gpio/gpio-of-helper.c b/drivers/gpio/gpio-of-helper.c
new file mode 100644
index 0000000..a9f260b
--- /dev/null
+++ b/drivers/gpio/gpio-of-helper.c
@@ -0,0 +1,429 @@
+/*
+ * GPIO OF based helper
+ *
+ * A simple DT based driver to provide access to GPIO functionality
+ * to user-space via sysfs.
+ *
+ * Copyright (C) 2013 Pantelis Antoniou <panto@antoniou-consulting.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/atomic.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/math64.h>
+#include <linux/atomic.h>
+#include <linux/idr.h>
+
+/* fwd decl. */
+struct gpio_of_helper_info;
+
+enum gpio_type {
+	GPIO_TYPE_INPUT = 0,
+	GPIO_TYPE_OUTPUT = 1,
+};
+
+struct gpio_of_entry {
+	int id;
+	struct gpio_of_helper_info *info;
+	struct device_node *node;
+	enum gpio_type type;
+	int gpio;
+	enum of_gpio_flags gpio_flags;
+	int irq;
+	const char *name;
+	atomic64_t counter;
+	unsigned int count_flags;
+#define COUNT_RISING_EDGE	(1 << 0)
+#define COUNT_FALLING_EDGE	(1 << 1)
+};
+
+struct gpio_of_helper_info {
+	struct platform_device *pdev;
+	struct idr idr;
+};
+
+static const struct of_device_id gpio_of_helper_of_match[] = {
+	{
+		.compatible = "gpio-of-helper",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, gpio_of_helper_of_match);
+
+static ssize_t gpio_of_helper_show_status(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_of_helper_info *info = platform_get_drvdata(pdev);
+	struct gpio_of_entry *entry;
+	char *p, *e;
+	int id, n;
+
+	p = buf;
+	e = p + PAGE_SIZE;
+	n = 0;
+	idr_for_each_entry(&info->idr, entry, id) {
+		switch (entry->type) {
+		case GPIO_TYPE_INPUT:
+			n = snprintf(p, e - p, "%2d %-24s %3d %-3s %llu\n",
+				entry->id, entry->name, entry->gpio, "IN",
+				(unsigned long long)
+					atomic64_read(&entry->counter));
+			break;
+		case GPIO_TYPE_OUTPUT:
+			n = snprintf(p, e - p, "%2d %-24s %3d %-3s\n",
+				entry->id, entry->name, entry->gpio, "OUT");
+			break;
+		}
+		p += n;
+	}
+
+	return p - buf;
+}
+
+static DEVICE_ATTR(status, S_IRUGO,
+		gpio_of_helper_show_status, NULL);
+
+static irqreturn_t gpio_of_helper_handler(int irq, void *ptr)
+{
+	struct gpio_of_entry *entry = ptr;
+
+	/* caution - low speed interfaces only! */
+	atomic64_inc(&entry->counter);
+
+	return IRQ_HANDLED;
+}
+
+static struct gpio_of_entry *
+gpio_of_entry_create(struct gpio_of_helper_info *info,
+		struct device_node *node)
+{
+	struct platform_device *pdev = info->pdev;
+	struct device *dev = &pdev->dev;
+	struct gpio_of_entry *entry;
+	int err, gpio, irq;
+	unsigned int req_flags, count_flags, irq_flags;
+	enum gpio_type type;
+	enum of_gpio_flags gpio_flags;
+	const char *name;
+
+	/* get the type of the node first */
+	if (of_property_read_bool(node, "input"))
+		type = GPIO_TYPE_INPUT;
+	else if (of_property_read_bool(node, "output"))
+		type = GPIO_TYPE_OUTPUT;
+	else {
+		dev_err(dev, "Not valid gpio node type\n");
+		err = -EINVAL;
+		goto err_bad_node;
+	}
+
+	/* get the name */
+	err = of_property_read_string(node, "gpio-name", &name);
+	if (err != 0) {
+		dev_err(dev, "Failed to get name property\n");
+		goto err_bad_node;
+	}
+
+	err = of_get_named_gpio_flags(node, "gpio", 0, &gpio_flags);
+	if (IS_ERR_VALUE(err)) {
+		dev_err(dev, "Failed to get gpio property of '%s'\n", name);
+		goto err_bad_node;
+	}
+	gpio = err;
+
+	req_flags = 0;
+	count_flags = 0;
+
+	/* set the request flags */
+	switch (type) {
+		case GPIO_TYPE_INPUT:
+			req_flags = GPIOF_DIR_IN | GPIOF_EXPORT;
+			if (of_property_read_bool(node, "count-falling-edge"))
+				count_flags |= COUNT_FALLING_EDGE;
+			if (of_property_read_bool(node, "count-rising-edge"))
+				count_flags |= COUNT_RISING_EDGE;
+			break;
+		case GPIO_TYPE_OUTPUT:
+			req_flags = GPIOF_DIR_OUT | GPIOF_EXPORT;
+			if (of_property_read_bool(node, "init-high"))
+				req_flags |= GPIOF_OUT_INIT_HIGH;
+			else if (of_property_read_bool(node, "init-low"))
+				req_flags |= GPIOF_OUT_INIT_LOW;
+			break;
+	}
+	if (of_property_read_bool(node, "dir-changeable"))
+		req_flags |= GPIOF_EXPORT_CHANGEABLE;
+
+	/* request the gpio */
+	err = devm_gpio_request_one(dev, gpio, req_flags, name);
+	if (err != 0) {
+		dev_err(dev, "Failed to request gpio '%s'\n", name);
+		goto err_bad_node;
+	}
+
+	irq = -1;
+	irq_flags = 0;
+
+	/* counter mode requested - need an interrupt */
+	if (count_flags != 0) {
+		irq = gpio_to_irq(gpio);
+		if (IS_ERR_VALUE(irq)) {
+			dev_err(dev, "Failed to request gpio '%s'\n", name);
+			goto err_bad_node;
+		}
+
+		if (count_flags & COUNT_RISING_EDGE)
+			irq_flags |= IRQF_TRIGGER_RISING;
+		if (count_flags & COUNT_FALLING_EDGE)
+			irq_flags |= IRQF_TRIGGER_FALLING;
+	}
+
+//	if (!idr_pre_get(&info->idr, GFP_KERNEL)) {
+//		dev_err(dev, "Failed on idr_pre_get of '%s'\n", name);
+//		err = -ENOMEM;
+//		goto err_no_mem;
+//	}
+
+	idr_preload(GFP_KERNEL);
+
+	entry = devm_kzalloc(dev, sizeof(*entry), GFP_KERNEL);
+	if (entry == NULL) {
+		dev_err(dev, "Failed to allocate gpio entry of '%s'\n", name);
+		err = -ENOMEM;
+		goto err_no_mem;
+	}
+
+	entry->id = -1;
+	entry->info = info;
+	entry->node = of_node_get(node);	/* get node reference */
+	entry->type = type;
+	entry->gpio = gpio;
+	entry->gpio_flags = gpio_flags;
+	entry->irq = irq;
+	entry->name = name;
+
+	/* interrupt enable is last thing done */
+	if (irq >= 0) {
+		atomic64_set(&entry->counter, 0);
+		entry->count_flags = count_flags;
+		err = devm_request_irq(dev, irq, gpio_of_helper_handler,
+				irq_flags, name, entry);
+		if (err != 0) {
+			dev_err(dev, "Failed to request irq of '%s'\n", name);
+			goto err_no_irq;
+		}
+	}
+
+	/* all done; insert */
+//	err = idr_get_new(&info->idr, entry, &entry->id);
+//	if (IS_ERR_VALUE(err)) {
+//		dev_err(dev, "Failed to idr_get_new  of '%s'\n", name);
+//		goto err_fail_idr;
+//	}
+
+	err = idr_alloc(&info->idr, entry, 0, 0, GFP_NOWAIT);
+	if (err >= 0)
+		entry->id = err;
+
+	idr_preload_end();
+
+	if (err < 0) {
+		dev_err(dev, "Failed to idr_get_new  of '%s'\n", name);
+		goto err_fail_idr;
+	}
+
+	dev_info(dev, "Allocated GPIO id=%d\n", entry->id);
+
+	return entry;
+
+err_fail_idr:
+	/* nothing to do */
+err_no_irq:
+	/* release node ref */
+	of_node_put(node);
+	/* nothing else needs to be done, devres handles it */
+err_no_mem:
+err_bad_node:
+	return ERR_PTR(err);
+}
+
+static int gpio_of_entry_destroy(struct gpio_of_entry *entry)
+{
+	struct gpio_of_helper_info *info = entry->info;
+	struct platform_device *pdev = info->pdev;
+	struct device *dev = &pdev->dev;
+
+	dev_info(dev, "Destroying GPIO id=%d\n", entry->id);
+
+	/* remove from the IDR */
+	idr_remove(&info->idr, entry->id);
+
+	/* remove node ref */
+	of_node_put(entry->node);
+
+	/* free gpio */
+	devm_gpio_free(dev, entry->gpio);
+
+	/* gree irq */
+	if (entry->irq >= 0)
+		devm_free_irq(dev, entry->irq, entry);
+
+	/* and free */
+	devm_kfree(dev, entry);
+
+	return 0;
+}
+
+static int gpio_of_helper_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct gpio_of_helper_info *info;
+	struct gpio_of_entry *entry;
+	struct device_node *pnode = pdev->dev.of_node;
+	struct device_node *cnode;
+	struct pinctrl *pinctrl;
+	int err;
+
+	/* we only support OF */
+	if (pnode == NULL) {
+		dev_err(&pdev->dev, "No platform of_node!\n");
+		return -ENODEV;
+	}
+
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		/* special handling for probe defer */
+		if (PTR_ERR(pinctrl) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+
+		dev_warn(&pdev->dev,
+			"pins are not configured from the driver\n");
+	}
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (info == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate info\n");
+		err = -ENOMEM;
+		goto err_no_mem;
+	}
+	platform_set_drvdata(pdev, info);
+	info->pdev = pdev;
+
+	idr_init(&info->idr);
+
+	err = device_create_file(dev, &dev_attr_status);
+	if (err != 0) {
+		dev_err(dev, "Failed to create status sysfs attribute\n");
+		goto err_no_sysfs;
+	}
+
+	for_each_child_of_node(pnode, cnode) {
+
+		entry = gpio_of_entry_create(info, cnode);
+		if (IS_ERR_OR_NULL(entry)) {
+			dev_err(dev, "Failed to create gpio entry\n");
+			err = PTR_ERR(entry);
+			goto err_fail_entry;
+		}
+	}
+
+	dev_info(&pdev->dev, "ready\n");
+
+	return 0;
+err_fail_entry:
+	device_remove_file(&pdev->dev, &dev_attr_status);
+err_no_sysfs:
+err_no_mem:
+	return err;
+}
+
+static int gpio_of_helper_remove(struct platform_device *pdev)
+{
+	struct gpio_of_helper_info *info = platform_get_drvdata(pdev);
+	struct gpio_of_entry *entry;
+	int id;
+
+	dev_info(&pdev->dev, "removing\n");
+
+	device_remove_file(&pdev->dev, &dev_attr_status);
+
+	id = 0;
+	idr_for_each_entry(&info->idr, entry, id) {
+		/* destroy each and every one */
+		gpio_of_entry_destroy(entry);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+//#ifdef CONFIG_PM_RUNTIME
+static int gpio_of_helper_runtime_suspend(struct device *dev)
+{
+	/* place holder */
+	return 0;
+}
+
+static int gpio_of_helper_runtime_resume(struct device *dev)
+{
+	/* place holder */
+	return 0;
+}
+//#endif /* CONFIG_PM_RUNTIME */
+
+static struct dev_pm_ops gpio_of_helper_pm_ops = {
+	SET_RUNTIME_PM_OPS(gpio_of_helper_runtime_suspend,
+			   gpio_of_helper_runtime_resume, NULL)
+};
+#define GPIO_OF_HELPER_PM_OPS (&gpio_of_helper_pm_ops)
+#else
+#define GPIO_OF_HELPER_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+struct platform_driver gpio_of_helper_driver = {
+	.probe		= gpio_of_helper_probe,
+	.remove		= gpio_of_helper_remove,
+	.driver = {
+		.name		= "gpio-of-helper",
+		.owner		= THIS_MODULE,
+		.pm		= GPIO_OF_HELPER_PM_OPS,
+		.of_match_table	= gpio_of_helper_of_match,
+	},
+};
+
+module_platform_driver(gpio_of_helper_driver);
+
+MODULE_AUTHOR("Pantelis Antoniou <panto@antoniou-consulting.com>");
+MODULE_DESCRIPTION("GPIO OF Helper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-of-helper");
diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index 22c7ed6..d19bd80 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -7,6 +7,12 @@ config DRM_I2C_ADV7511
 	help
 	  Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders.
 
+config DRM_I2C_ADIHDMI
+	tristate "ADI HDMI encoder"
+	default m if DRM_TILCDC
+	help
+	  Support for ADI HDMI encoder.
+
 config DRM_I2C_CH7006
 	tristate "Chrontel ch7006 TV encoder"
 	default m if DRM_NOUVEAU
diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
index 2c72eb5..5a509ae 100644
--- a/drivers/gpu/drm/i2c/Makefile
+++ b/drivers/gpu/drm/i2c/Makefile
@@ -10,3 +10,6 @@ obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o
 
 tda998x-y := tda998x_drv.o
 obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o
+
+adihdmi-y := adihdmi_drv.o
+obj-$(CONFIG_DRM_I2C_ADIHDMI) += adihdmi.o
diff --git b/drivers/gpu/drm/i2c/adihdmi.h b/drivers/gpu/drm/i2c/adihdmi.h
new file mode 100644
index 0000000..58d9a2b
--- /dev/null
+++ b/drivers/gpu/drm/i2c/adihdmi.h
@@ -0,0 +1,289 @@
+/*
+ * Analog Devices ADIHDMI HDMI transmitter driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __DRM_I2C_ADIHDMI_H__
+#define __DRM_I2C_ADIHDMI_H__
+
+#include <linux/hdmi.h>
+
+#define ADIHDMI_REG_CHIP_REVISION		0x00
+#define ADIHDMI_REG_N0				0x01
+#define ADIHDMI_REG_N1				0x02
+#define ADIHDMI_REG_N2				0x03
+#define ADIHDMI_REG_SPDIF_FREQ			0x04
+#define ADIHDMI_REG_CTS_AUTOMATIC1		0x05
+#define ADIHDMI_REG_CTS_AUTOMATIC2		0x06
+#define ADIHDMI_REG_CTS_MANUAL0			0x07
+#define ADIHDMI_REG_CTS_MANUAL1			0x08
+#define ADIHDMI_REG_CTS_MANUAL2			0x09
+#define ADIHDMI_REG_AUDIO_SOURCE		0x0a
+#define ADIHDMI_REG_AUDIO_CONFIG		0x0b
+#define ADIHDMI_REG_I2S_CONFIG			0x0c
+#define ADIHDMI_REG_I2S_WIDTH			0x0d
+#define ADIHDMI_REG_AUDIO_SUB_SRC0		0x0e
+#define ADIHDMI_REG_AUDIO_SUB_SRC1		0x0f
+#define ADIHDMI_REG_AUDIO_SUB_SRC2		0x10
+#define ADIHDMI_REG_AUDIO_SUB_SRC3		0x11
+#define ADIHDMI_REG_AUDIO_CFG1			0x12
+#define ADIHDMI_REG_AUDIO_CFG2			0x13
+#define ADIHDMI_REG_AUDIO_CFG3			0x14
+#define ADIHDMI_REG_I2C_FREQ_ID_CFG		0x15
+#define ADIHDMI_REG_VIDEO_INPUT_CFG1		0x16
+#define ADIHDMI_REG_CSC_UPPER(x)		(0x18 + (x) * 2)
+#define ADIHDMI_REG_CSC_LOWER(x)		(0x19 + (x) * 2)
+#define ADIHDMI_REG_SYNC_DECODER(x)		(0x30 + (x))
+#define ADIHDMI_REG_DE_GENERATOR		(0x35 + (x))
+#define ADIHDMI_REG_PIXEL_REPETITION		0x3b
+#define ADIHDMI_REG_VIC_MANUAL			0x3c
+#define ADIHDMI_REG_VIC_SEND			0x3d
+#define ADIHDMI_REG_VIC_DETECTED		0x3e
+#define ADIHDMI_REG_AUX_VIC_DETECTED		0x3f
+#define ADIHDMI_REG_PACKET_ENABLE0		0x40
+#define ADIHDMI_REG_POWER			0x41
+#define ADIHDMI_REG_STATUS			0x42
+#define ADIHDMI_REG_EDID_I2C_ADDR		0x43
+#define ADIHDMI_REG_PACKET_ENABLE1		0x44
+#define ADIHDMI_REG_PACKET_I2C_ADDR		0x45
+#define ADIHDMI_REG_DSD_ENABLE			0x46
+#define ADIHDMI_REG_VIDEO_INPUT_CFG2		0x48
+#define ADIHDMI_REG_INFOFRAME_UPDATE		0x4a
+#define ADIHDMI_REG_GC(x)			(0x4b + (x)) /* 0x4b - 0x51 */
+#define ADIHDMI_REG_AVI_INFOFRAME_VERSION	0x52
+#define ADIHDMI_REG_AVI_INFOFRAME_LENGTH	0x53
+#define ADIHDMI_REG_AVI_INFOFRAME_CHECKSUM	0x54
+#define ADIHDMI_REG_AVI_INFOFRAME(x)		(0x55 + (x)) /* 0x55 - 0x6f */
+#define ADIHDMI_REG_AUDIO_INFOFRAME_VERSION	0x70
+#define ADIHDMI_REG_AUDIO_INFOFRAME_LENGTH	0x71
+#define ADIHDMI_REG_AUDIO_INFOFRAME_CHECKSUM	0x72
+#define ADIHDMI_REG_AUDIO_INFOFRAME(x)		(0x73 + (x)) /* 0x73 - 0x7c */
+#define ADIHDMI_REG_INT_ENABLE(x)		(0x94 + (x))
+#define ADIHDMI_REG_INT(x)			(0x96 + (x))
+#define ADIHDMI_REG_INPUT_CLK_DIV		0x9d
+#define ADIHDMI_REG_PLL_STATUS			0x9e
+#define ADIHDMI_REG_HDMI_POWER			0xa1
+#define ADIHDMI_REG_HDCP_HDMI_CFG		0xaf
+#define ADIHDMI_REG_AN(x)			(0xb0 + (x)) /* 0xb0 - 0xb7 */
+#define ADIHDMI_REG_HDCP_STATUS			0xb8
+#define ADIHDMI_REG_BCAPS			0xbe
+#define ADIHDMI_REG_BKSV(x)			(0xc0 + (x)) /* 0xc0 - 0xc3 */
+#define ADIHDMI_REG_EDID_SEGMENT		0xc4
+#define ADIHDMI_REG_DDC_STATUS			0xc8
+#define ADIHDMI_REG_EDID_READ_CTRL		0xc9
+#define ADIHDMI_REG_BSTATUS(x)			(0xca + (x)) /* 0xca - 0xcb */
+#define ADIHDMI_REG_TIMING_GEN_SEQ		0xd0
+#define ADIHDMI_REG_POWER2			0xd6
+#define ADIHDMI_REG_HSYNC_PLACEMENT_MSB		0xfa
+
+#define ADIHDMI_REG_SYNC_ADJUSTMENT(x)		(0xd7 + (x)) /* 0xd7 - 0xdc */
+#define ADIHDMI_REG_TMDS_CLOCK_INV		0xde
+#define ADIHDMI_REG_ARC_CTRL			0xdf
+#define ADIHDMI_REG_CEC_I2C_ADDR		0xe1
+#define ADIHDMI_REG_CEC_CTRL			0xe2
+#define ADIHDMI_REG_CHIP_ID_HIGH		0xf5
+#define ADIHDMI_REG_CHIP_ID_LOW			0xf6
+
+#define ADIHDMI_CSC_ENABLE			BIT(7)
+#define ADIHDMI_CSC_UPDATE_MODE			BIT(5)
+
+#define ADIHDMI_INT0_HDP			BIT(7)
+#define ADIHDMI_INT0_VSYNC			BIT(5)
+#define ADIHDMI_INT0_AUDIO_FIFO_FULL		BIT(4)
+#define ADIHDMI_INT0_EDID_READY			BIT(2)
+#define ADIHDMI_INT0_HDCP_AUTHENTICATED		BIT(1)
+
+#define ADIHDMI_INT1_DDC_ERROR			BIT(7)
+#define ADIHDMI_INT1_BKSV			BIT(6)
+#define ADIHDMI_INT1_CEC_TX_READY		BIT(5)
+#define ADIHDMI_INT1_CEC_TX_ARBIT_LOST		BIT(4)
+#define ADIHDMI_INT1_CEC_TX_RETRY_TIMEOUT	BIT(3)
+#define ADIHDMI_INT1_CEC_RX_READY3		BIT(2)
+#define ADIHDMI_INT1_CEC_RX_READY2		BIT(1)
+#define ADIHDMI_INT1_CEC_RX_READY1		BIT(0)
+
+#define ADIHDMI_ARC_CTRL_POWER_DOWN		BIT(0)
+
+#define ADIHDMI_CEC_CTRL_POWER_DOWN		BIT(0)
+
+#define ADIHDMI_POWER_POWER_DOWN		BIT(6)
+
+#define ADIHDMI_HDMI_CFG_MODE_MASK		0x2
+#define ADIHDMI_HDMI_CFG_MODE_DVI		0x0
+#define ADIHDMI_HDMI_CFG_MODE_HDMI		0x2
+
+#define ADIHDMI_AUDIO_SELECT_I2C		0x0
+#define ADIHDMI_AUDIO_SELECT_SPDIF		0x1
+#define ADIHDMI_AUDIO_SELECT_DSD		0x2
+#define ADIHDMI_AUDIO_SELECT_HBR		0x3
+#define ADIHDMI_AUDIO_SELECT_DST		0x4
+
+#define ADIHDMI_I2S_SAMPLE_LEN_16		0x2
+#define ADIHDMI_I2S_SAMPLE_LEN_20		0x3
+#define ADIHDMI_I2S_SAMPLE_LEN_18		0x4
+#define ADIHDMI_I2S_SAMPLE_LEN_22		0x5
+#define ADIHDMI_I2S_SAMPLE_LEN_19		0x8
+#define ADIHDMI_I2S_SAMPLE_LEN_23		0x9
+#define ADIHDMI_I2S_SAMPLE_LEN_24		0xb
+#define ADIHDMI_I2S_SAMPLE_LEN_17		0xc
+#define ADIHDMI_I2S_SAMPLE_LEN_21		0xd
+
+#define ADIHDMI_SAMPLE_FREQ_44100		0x0
+#define ADIHDMI_SAMPLE_FREQ_48000		0x2
+#define ADIHDMI_SAMPLE_FREQ_32000		0x3
+#define ADIHDMI_SAMPLE_FREQ_88200		0x8
+#define ADIHDMI_SAMPLE_FREQ_96000		0xa
+#define ADIHDMI_SAMPLE_FREQ_176400		0xc
+#define ADIHDMI_SAMPLE_FREQ_192000		0xe
+
+#define ADIHDMI_STATUS_POWER_DOWN_POLARITY	BIT(7)
+#define ADIHDMI_STATUS_HPD			BIT(6)
+#define ADIHDMI_STATUS_MONITOR_SENSE		BIT(5)
+#define ADIHDMI_STATUS_I2S_32BIT_MODE		BIT(3)
+
+#define ADIHDMI_PACKET_ENABLE_N_CTS		BIT(8+6)
+#define ADIHDMI_PACKET_ENABLE_AUDIO_SAMPLE	BIT(8+5)
+#define ADIHDMI_PACKET_ENABLE_AVI_INFOFRAME	BIT(8+4)
+#define ADIHDMI_PACKET_ENABLE_AUDIO_INFOFRAME	BIT(8+3)
+#define ADIHDMI_PACKET_ENABLE_GC		BIT(7)
+#define ADIHDMI_PACKET_ENABLE_SPD		BIT(6)
+#define ADIHDMI_PACKET_ENABLE_MPEG		BIT(5)
+#define ADIHDMI_PACKET_ENABLE_ACP		BIT(4)
+#define ADIHDMI_PACKET_ENABLE_ISRC		BIT(3)
+#define ADIHDMI_PACKET_ENABLE_GM		BIT(2)
+#define ADIHDMI_PACKET_ENABLE_SPARE2		BIT(1)
+#define ADIHDMI_PACKET_ENABLE_SPARE1		BIT(0)
+
+#define ADIHDMI_REG_POWER2_HDP_SRC_MASK		0xc0
+#define ADIHDMI_REG_POWER2_HDP_SRC_BOTH		0x00
+#define ADIHDMI_REG_POWER2_HDP_SRC_HDP		0x40
+#define ADIHDMI_REG_POWER2_HDP_SRC_CEC		0x80
+#define ADIHDMI_REG_POWER2_HDP_SRC_NONE		0xc0
+#define ADIHDMI_REG_POWER2_TDMS_ENABLE		BIT(4)
+#define ADIHDMI_REG_POWER2_GATE_INPUT_CLK	BIT(0)
+
+#define ADIHDMI_LOW_REFRESH_RATE_NONE		0x0
+#define ADIHDMI_LOW_REFRESH_RATE_24HZ		0x1
+#define ADIHDMI_LOW_REFRESH_RATE_25HZ		0x2
+#define ADIHDMI_LOW_REFRESH_RATE_30HZ		0x3
+
+#define ADIHDMI_AUDIO_CFG3_LEN_MASK		0x0f
+#define ADIHDMI_I2C_FREQ_ID_CFG_RATE_MASK	0xf0
+
+#define ADIHDMI_AUDIO_SOURCE_I2S		0
+#define ADIHDMI_AUDIO_SOURCE_SPDIF		1
+
+#define ADIHDMI_I2S_FORMAT_I2S			0
+#define ADIHDMI_I2S_FORMAT_RIGHT_J		1
+#define ADIHDMI_I2S_FORMAT_LEFT_J		2
+
+#define ADIHDMI_PACKET(p, x)	    ((p) * 0x20 + (x))
+#define ADIHDMI_PACKET_SDP(x)	    ADIHDMI_PACKET(0, x)
+#define ADIHDMI_PACKET_MPEG(x)	    ADIHDMI_PACKET(1, x)
+#define ADIHDMI_PACKET_ACP(x)	    ADIHDMI_PACKET(2, x)
+#define ADIHDMI_PACKET_ISRC1(x)	    ADIHDMI_PACKET(3, x)
+#define ADIHDMI_PACKET_ISRC2(x)	    ADIHDMI_PACKET(4, x)
+#define ADIHDMI_PACKET_GM(x)	    ADIHDMI_PACKET(5, x)
+#define ADIHDMI_PACKET_SPARE(x)	    ADIHDMI_PACKET(6, x)
+
+enum adihdmi_input_clock {
+	ADIHDMI_INPUT_CLOCK_1X,
+	ADIHDMI_INPUT_CLOCK_2X,
+	ADIHDMI_INPUT_CLOCK_DDR,
+};
+
+enum adihdmi_input_justification {
+	ADIHDMI_INPUT_JUSTIFICATION_EVENLY = 0,
+	ADIHDMI_INPUT_JUSTIFICATION_RIGHT = 1,
+	ADIHDMI_INPUT_JUSTIFICATION_LEFT = 2,
+};
+
+enum adihdmi_input_sync_pulse {
+	ADIHDMI_INPUT_SYNC_PULSE_DE = 0,
+	ADIHDMI_INPUT_SYNC_PULSE_HSYNC = 1,
+	ADIHDMI_INPUT_SYNC_PULSE_VSYNC = 2,
+	ADIHDMI_INPUT_SYNC_PULSE_NONE = 3,
+};
+
+/**
+ * enum adihdmi_sync_polarity - Polarity for the input sync signals
+ * @ADIHDMI_SYNC_POLARITY_PASSTHROUGH:  Sync polarity matches that of
+ *				       the currently configured mode.
+ * @ADIHDMI_SYNC_POLARITY_LOW:	    Sync polarity is low
+ * @ADIHDMI_SYNC_POLARITY_HIGH:	    Sync polarity is high
+ *
+ * If the polarity is set to either LOW or HIGH the driver will configure the
+ * ADIHDMI to internally invert the sync signal if required to match the sync
+ * polarity setting for the currently selected output mode.
+ *
+ * If the polarity is set to PASSTHROUGH, the ADIHDMI will route the signal
+ * unchanged. This is used when the upstream graphics core already generates
+ * the sync signals with the correct polarity.
+ */
+enum adihdmi_sync_polarity {
+	ADIHDMI_SYNC_POLARITY_PASSTHROUGH,
+	ADIHDMI_SYNC_POLARITY_LOW,
+	ADIHDMI_SYNC_POLARITY_HIGH,
+};
+
+/**
+ * struct adihdmi_link_config - Describes adihdmi hardware configuration
+ * @input_color_depth:		Number of bits per color component (8, 10 or 12)
+ * @input_colorspace:		The input colorspace (RGB, YUV444, YUV422)
+ * @input_clock:		The input video clock style (1x, 2x, DDR)
+ * @input_style:		The input component arrangement variant
+ * @input_justification:	Video input format bit justification
+ * @clock_delay:		Clock delay for the input clock (in ps)
+ * @embedded_sync:		Video input uses BT.656-style embedded sync
+ * @sync_pulse:			Select the sync pulse
+ * @vsync_polarity:		vsync input signal configuration
+ * @hsync_polarity:		hsync input signal configuration
+ */
+struct adihdmi_link_config {
+	unsigned int input_color_depth;
+	enum hdmi_colorspace input_colorspace;
+	enum adihdmi_input_clock input_clock;
+	unsigned int input_style;
+	enum adihdmi_input_justification input_justification;
+
+	int clock_delay;
+
+	bool embedded_sync;
+	enum adihdmi_input_sync_pulse sync_pulse;
+	enum adihdmi_sync_polarity vsync_polarity;
+	enum adihdmi_sync_polarity hsync_polarity;
+};
+
+/**
+ * enum adihdmi_csc_scaling - Scaling factor for the ADIHDMI CSC
+ * @ADIHDMI_CSC_SCALING_1: CSC results are not scaled
+ * @ADIHDMI_CSC_SCALING_2: CSC results are scaled by a factor of two
+ * @ADIHDMI_CSC_SCALING_4: CSC results are scalled by a factor of four
+ */
+enum adihdmi_csc_scaling {
+	ADIHDMI_CSC_SCALING_1 = 0,
+	ADIHDMI_CSC_SCALING_2 = 1,
+	ADIHDMI_CSC_SCALING_4 = 2,
+};
+
+/**
+ * struct adihdmi_video_config - Describes adihdmi hardware configuration
+ * @csc_enable:			Whether to enable color space conversion
+ * @csc_scaling_factor:		Color space conversion scaling factor
+ * @csc_coefficents:		Color space conversion coefficents
+ * @hdmi_mode:			Whether to use HDMI or DVI output mode
+ * @avi_infoframe:		HDMI infoframe
+ */
+struct adihdmi_video_config {
+	bool csc_enable;
+	enum adihdmi_csc_scaling csc_scaling_factor;
+	const uint16_t *csc_coefficents;
+
+	bool hdmi_mode;
+	struct hdmi_avi_infoframe avi_infoframe;
+};
+
+#endif /* __DRM_I2C_ADIHDMI_H__ */
diff --git b/drivers/gpu/drm/i2c/adihdmi_drv.c b/drivers/gpu/drm/i2c/adihdmi_drv.c
new file mode 100644
index 0000000..6792224
--- /dev/null
+++ b/drivers/gpu/drm/i2c/adihdmi_drv.c
@@ -0,0 +1,1268 @@
+/*
+ * Analog Devices ADIHDMI HDMI transmitter driver
+ *
+ * Copyright 2012 Analog Devices Inc.
+ * Copyright 2015 Konsulko Group
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm_of.h>
+
+#include "adihdmi.h"
+
+#define ADIHDMI_INFOFRAME_PACKETS   (0x7900)
+
+struct adihdmi {
+	struct i2c_client *i2c_main;
+	struct i2c_client *i2c_edid;
+
+	struct regmap *regmap;
+	struct regmap *packet_memory_regmap;
+	enum drm_connector_status status;
+	bool powered;
+
+	unsigned int f_tmds;
+
+	unsigned int current_edid_segment;
+	uint8_t edid_buf[256];
+	bool edid_read;
+
+	wait_queue_head_t wq;
+	struct drm_encoder *encoder;
+
+	bool embedded_sync;
+	enum adihdmi_sync_polarity vsync_polarity;
+	enum adihdmi_sync_polarity hsync_polarity;
+	bool rgb;
+
+	struct edid *edid;
+
+	struct gpio_desc *gpio_pd;
+};
+
+struct adihdmi2 {
+	struct adihdmi base;
+	struct drm_encoder encoder;
+	struct drm_connector connector;
+};
+
+/* ADI recommended values for proper operation. */
+static const struct reg_sequence adihdmi_fixed_registers[] = {
+	{ 0x98, 0x03 },
+	{ 0x9a, 0xe0 },
+	{ 0x9c, 0x30 },
+	{ 0x9d, 0x61 },
+	{ 0xa2, 0xa4 },
+	{ 0xa3, 0xa4 },
+	{ 0xe0, 0xd0 },
+	{ 0xf9, 0x00 },
+	{ 0x55, 0x02 },
+};
+
+/* -----------------------------------------------------------------------------
+ * Register access
+ */
+
+static const uint8_t adihdmi_register_defaults[] = {
+	0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */
+	0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13,
+	0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */
+	0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84,
+	0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */
+	0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */
+	0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
+	0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */
+	0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */
+	0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00,
+	0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */
+	0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */
+	0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04,
+	0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01,
+	0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */
+	0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static bool adihdmi_register_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+		case ADIHDMI_REG_CHIP_REVISION:
+		case ADIHDMI_REG_SPDIF_FREQ:
+		case ADIHDMI_REG_CTS_AUTOMATIC1:
+		case ADIHDMI_REG_CTS_AUTOMATIC2:
+		case ADIHDMI_REG_VIC_DETECTED:
+		case ADIHDMI_REG_VIC_SEND:
+		case ADIHDMI_REG_AUX_VIC_DETECTED:
+		case ADIHDMI_REG_STATUS:
+		case ADIHDMI_REG_GC(1):
+		case ADIHDMI_REG_INT(0):
+		case ADIHDMI_REG_INT(1):
+		case ADIHDMI_REG_PLL_STATUS:
+		case ADIHDMI_REG_AN(0):
+		case ADIHDMI_REG_AN(1):
+		case ADIHDMI_REG_AN(2):
+		case ADIHDMI_REG_AN(3):
+		case ADIHDMI_REG_AN(4):
+		case ADIHDMI_REG_AN(5):
+		case ADIHDMI_REG_AN(6):
+		case ADIHDMI_REG_AN(7):
+		case ADIHDMI_REG_HDCP_STATUS:
+		case ADIHDMI_REG_BCAPS:
+		case ADIHDMI_REG_BKSV(0):
+		case ADIHDMI_REG_BKSV(1):
+		case ADIHDMI_REG_BKSV(2):
+		case ADIHDMI_REG_BKSV(3):
+		case ADIHDMI_REG_BKSV(4):
+		case ADIHDMI_REG_DDC_STATUS:
+		case ADIHDMI_REG_BSTATUS(0):
+		case ADIHDMI_REG_BSTATUS(1):
+		case ADIHDMI_REG_CHIP_ID_HIGH:
+		case ADIHDMI_REG_CHIP_ID_LOW:
+			return true;
+	}
+
+	return false;
+}
+
+static const struct regmap_config adihdmi_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = 0xff,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_defaults_raw = adihdmi_register_defaults,
+	.num_reg_defaults_raw = ARRAY_SIZE(adihdmi_register_defaults),
+
+	.volatile_reg = adihdmi_register_volatile,
+};
+
+/* -----------------------------------------------------------------------------
+ * Hardware configuration
+ */
+
+	static void adihdmi_audio_setup(struct adihdmi * adihdmi)
+{
+	/* Select I2S. */
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_AUDIO_SOURCE, 0x01);
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_I2S_CONFIG, 0x84);
+
+	/* Setup clocks for 48KHz. */
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_N0, 0x00);
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_N1, 0x18);
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_N2, 0x00);
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_I2C_FREQ_ID_CFG, 0xF0, 0x20);
+
+	/* Set audio word length to 24 bits. */
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_AUDIO_CFG3, 0x0F, 0x0B);
+
+	/* Update audio infoframe. */
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_INFOFRAME_UPDATE, 0x20, 0x20);
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_AUDIO_INFOFRAME(0), 0x07, 0x01);
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_AUDIO_INFOFRAME(3), 0x1F, 0x00);
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_INFOFRAME_UPDATE, 0x20, 0x00);
+}
+
+static void adihdmi_set_colormap(struct adihdmi *adihdmi, bool enable,
+		const uint16_t *coeff,
+		unsigned int scaling_factor)
+{
+	unsigned int i;
+
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_CSC_UPPER(1),
+			ADIHDMI_CSC_UPDATE_MODE, ADIHDMI_CSC_UPDATE_MODE);
+
+	if (enable) {
+		for (i = 0; i < 12; ++i) {
+			regmap_update_bits(adihdmi->regmap,
+					ADIHDMI_REG_CSC_UPPER(i),
+					0x1f, coeff[i] >> 8);
+			regmap_write(adihdmi->regmap,
+					ADIHDMI_REG_CSC_LOWER(i),
+					coeff[i] & 0xff);
+		}
+	}
+
+	if (enable)
+		regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_CSC_UPPER(0),
+				0xe0, 0x80 | (scaling_factor << 5));
+	else
+		regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_CSC_UPPER(0),
+				0x80, 0x00);
+
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_CSC_UPPER(1),
+			ADIHDMI_CSC_UPDATE_MODE, 0);
+}
+
+static int adihdmi_packet_enable(struct adihdmi *adihdmi, unsigned int packet)
+{
+	if (packet & 0xff)
+		regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_PACKET_ENABLE0,
+				packet, 0xff);
+
+	if (packet & 0xff00) {
+		packet >>= 8;
+		regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_PACKET_ENABLE1,
+				packet, 0xff);
+	}
+
+	return 0;
+}
+
+static int adihdmi_packet_disable(struct adihdmi *adihdmi, unsigned int packet)
+{
+	if (packet & 0xff)
+		regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_PACKET_ENABLE0,
+				packet, 0x00);
+
+	if (packet & 0xff00) {
+		packet >>= 8;
+		regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_PACKET_ENABLE1,
+				packet, 0x00);
+	}
+
+	return 0;
+}
+
+/* Coefficients for adihdmi color space conversion */
+static const uint16_t adihdmi_csc_ycbcr_to_rgb[] = {
+	0x0734, 0x04ad, 0x0000, 0x1c1b,
+	0x1ddc, 0x04ad, 0x1f24, 0x0135,
+	0x0000, 0x04ad, 0x087c, 0x1b77,
+};
+
+static void adihdmi_set_config_csc(struct adihdmi *adihdmi,
+		struct drm_connector *connector,
+		bool rgb)
+{
+	struct adihdmi_video_config config;
+	bool output_format_422, output_format_ycbcr;
+	unsigned int mode;
+	uint8_t infoframe[17];
+
+	if (adihdmi->edid)
+		config.hdmi_mode = drm_detect_hdmi_monitor(adihdmi->edid);
+	else
+		config.hdmi_mode = false;
+
+	hdmi_avi_infoframe_init(&config.avi_infoframe);
+
+	config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
+
+	if (rgb) {
+		config.csc_enable = false;
+		config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
+	} else {
+		config.csc_scaling_factor = ADIHDMI_CSC_SCALING_4;
+		config.csc_coefficents = adihdmi_csc_ycbcr_to_rgb;
+
+		if ((connector->display_info.color_formats &
+					DRM_COLOR_FORMAT_YCRCB422) &&
+				config.hdmi_mode) {
+			config.csc_enable = false;
+			config.avi_infoframe.colorspace =
+				HDMI_COLORSPACE_YUV422;
+		} else {
+			config.csc_enable = true;
+			config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB;
+		}
+	}
+
+	if (config.hdmi_mode) {
+		mode = ADIHDMI_HDMI_CFG_MODE_HDMI;
+
+		switch (config.avi_infoframe.colorspace) {
+			case HDMI_COLORSPACE_YUV444:
+				output_format_422 = false;
+				output_format_ycbcr = true;
+				break;
+			case HDMI_COLORSPACE_YUV422:
+				output_format_422 = true;
+				output_format_ycbcr = true;
+				break;
+			default:
+				output_format_422 = false;
+				output_format_ycbcr = false;
+				break;
+		}
+	} else {
+		mode = ADIHDMI_HDMI_CFG_MODE_DVI;
+		output_format_422 = false;
+		output_format_ycbcr = false;
+	}
+
+	adihdmi_packet_disable(adihdmi, ADIHDMI_INFOFRAME_PACKETS);
+
+	adihdmi_set_colormap(adihdmi, config.csc_enable,
+			config.csc_coefficents,
+			config.csc_scaling_factor);
+
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_VIDEO_INPUT_CFG1, 0x81,
+			(output_format_422 << 7) | output_format_ycbcr);
+
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_HDCP_HDMI_CFG,
+			ADIHDMI_HDMI_CFG_MODE_MASK, mode);
+
+	hdmi_avi_infoframe_pack(&config.avi_infoframe, infoframe,
+			sizeof(infoframe));
+
+	/* The AVI infoframe id is not configurable */
+	regmap_bulk_write(adihdmi->regmap, ADIHDMI_REG_AVI_INFOFRAME_VERSION,
+			infoframe + 1, sizeof(infoframe) - 1);
+
+	adihdmi_packet_enable(adihdmi, ADIHDMI_INFOFRAME_PACKETS);
+}
+
+static void adihdmi_set_link_config(struct adihdmi *adihdmi,
+		const struct adihdmi_link_config *config)
+{
+	/*
+	 * The input style values documented in the datasheet don't match the
+	 * hardware register field values :-(
+	 */
+	static const unsigned int input_styles[4] = { 0, 2, 1, 3 };
+
+	unsigned int clock_delay;
+	unsigned int color_depth;
+	unsigned int input_id;
+
+	clock_delay = (config->clock_delay + 1200) / 400;
+	color_depth = config->input_color_depth == 8 ? 3
+		: (config->input_color_depth == 10 ? 1 : 2);
+
+	/* TODO Support input ID 6 */
+	if (config->input_colorspace != HDMI_COLORSPACE_YUV422)
+		input_id = config->input_clock == ADIHDMI_INPUT_CLOCK_DDR
+			? 5 : 0;
+	else if (config->input_clock == ADIHDMI_INPUT_CLOCK_DDR)
+		input_id = config->embedded_sync ? 8 : 7;
+	else if (config->input_clock == ADIHDMI_INPUT_CLOCK_2X)
+		input_id = config->embedded_sync ? 4 : 3;
+	else
+		input_id = config->embedded_sync ? 2 : 1;
+
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_I2C_FREQ_ID_CFG, 0xf,
+			input_id);
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_VIDEO_INPUT_CFG1, 0x7e,
+			(color_depth << 4) |
+			(input_styles[config->input_style] << 2));
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_VIDEO_INPUT_CFG2,
+			config->input_justification << 3);
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_TIMING_GEN_SEQ,
+			config->sync_pulse << 2);
+
+	regmap_write(adihdmi->regmap, 0xba, clock_delay << 5);
+
+	adihdmi->embedded_sync = config->embedded_sync;
+	adihdmi->hsync_polarity = config->hsync_polarity;
+	adihdmi->vsync_polarity = config->vsync_polarity;
+	adihdmi->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB;
+}
+
+static void adihdmi_power_on(struct adihdmi *adihdmi)
+{
+	adihdmi->current_edid_segment = -1;
+
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(0),
+			ADIHDMI_INT0_EDID_READY);
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(1),
+			ADIHDMI_INT1_DDC_ERROR);
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER,
+			ADIHDMI_POWER_POWER_DOWN, 0);
+
+	/*
+	 * Per spec it is allowed to pulse the HDP signal to indicate that the
+	 * EDID information has changed. Some monitors do this when they wakeup
+	 * from standby or are enabled. When the HDP goes low the adihdmi is
+	 * reset and the outputs are disabled which might cause the monitor to
+	 * go to standby again. To avoid this we ignore the HDP pin for the
+	 * first few seconds after enabling the output.
+	 */
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER2,
+			ADIHDMI_REG_POWER2_HDP_SRC_MASK,
+			ADIHDMI_REG_POWER2_HDP_SRC_NONE);
+
+	/*
+	 * Most of the registers are reset during power down or when HPD is low.
+	 */
+	regcache_sync(adihdmi->regmap);
+
+	adihdmi->powered = true;
+}
+
+static void adihdmi_power_off(struct adihdmi *adihdmi)
+{
+	/* TODO: setup additional power down modes */
+	regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER,
+			ADIHDMI_POWER_POWER_DOWN,
+			ADIHDMI_POWER_POWER_DOWN);
+	regcache_mark_dirty(adihdmi->regmap);
+
+	adihdmi->powered = false;
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt and hotplug detection
+ */
+
+static bool adihdmi_hpd(struct adihdmi *adihdmi)
+{
+	unsigned int irq0;
+	int ret;
+
+	ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_INT(0), &irq0);
+	if (ret < 0)
+		return false;
+
+	if (irq0 & ADIHDMI_INT0_HDP) {
+		regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(0),
+				ADIHDMI_INT0_HDP);
+		return true;
+	}
+
+	return false;
+}
+
+static int adihdmi_irq_process(struct adihdmi *adihdmi)
+{
+	unsigned int irq0, irq1;
+	int ret;
+
+	ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_INT(0), &irq0);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_INT(1), &irq1);
+	if (ret < 0)
+		return ret;
+
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(0), irq0);
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(1), irq1);
+
+	if (irq0 & ADIHDMI_INT0_HDP)
+		drm_helper_hpd_irq_event(adihdmi->encoder->dev);
+
+	if (irq0 & ADIHDMI_INT0_EDID_READY || irq1 & ADIHDMI_INT1_DDC_ERROR) {
+		adihdmi->edid_read = true;
+
+		if (adihdmi->i2c_main->irq)
+			wake_up_all(&adihdmi->wq);
+	}
+
+	return 0;
+}
+
+static irqreturn_t adihdmi_irq_handler(int irq, void *devid)
+{
+	struct adihdmi *adihdmi = devid;
+	int ret;
+
+	ret = adihdmi_irq_process(adihdmi);
+	return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * EDID retrieval
+ */
+
+static int adihdmi_wait_for_edid(struct adihdmi *adihdmi, int timeout)
+{
+	int ret;
+
+	if (adihdmi->i2c_main->irq) {
+		ret = wait_event_interruptible_timeout(adihdmi->wq,
+				adihdmi->edid_read, msecs_to_jiffies(timeout));
+	} else {
+		for (; timeout > 0; timeout -= 25) {
+			ret = adihdmi_irq_process(adihdmi);
+			if (ret < 0)
+				break;
+
+			if (adihdmi->edid_read)
+				break;
+
+			msleep(25);
+		}
+	}
+
+	return adihdmi->edid_read ? 0 : -EIO;
+}
+
+static int adihdmi_get_edid_block(void *data, u8 *buf, unsigned int block,
+		size_t len)
+{
+	struct adihdmi *adihdmi = data;
+	struct i2c_msg xfer[2];
+	uint8_t offset;
+	unsigned int i;
+	int ret;
+
+	if (len > 128)
+		return -EINVAL;
+
+	if (adihdmi->current_edid_segment != block / 2) {
+		unsigned int status;
+
+		ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_DDC_STATUS,
+				&status);
+		if (ret < 0)
+			return ret;
+
+		if (status != 2) {
+			adihdmi->edid_read = false;
+			regmap_write(adihdmi->regmap, ADIHDMI_REG_EDID_SEGMENT,
+					block);
+			ret = adihdmi_wait_for_edid(adihdmi, 200);
+			if (ret < 0)
+				return ret;
+		}
+
+		/* Break this apart, hopefully more I2C controllers will
+		 * support 64 byte transfers than 256 byte transfers
+		 */
+
+		xfer[0].addr = adihdmi->i2c_edid->addr;
+		xfer[0].flags = 0;
+		xfer[0].len = 1;
+		xfer[0].buf = &offset;
+		xfer[1].addr = adihdmi->i2c_edid->addr;
+		xfer[1].flags = I2C_M_RD;
+		xfer[1].len = 64;
+		xfer[1].buf = adihdmi->edid_buf;
+
+		offset = 0;
+
+		for (i = 0; i < 4; ++i) {
+			ret = i2c_transfer(adihdmi->i2c_edid->adapter, xfer,
+					ARRAY_SIZE(xfer));
+			if (ret < 0)
+				return ret;
+			else if (ret != 2)
+				return -EIO;
+
+			xfer[1].buf += 64;
+			offset += 64;
+		}
+
+		adihdmi->current_edid_segment = block / 2;
+	}
+
+	if (block % 2 == 0)
+		memcpy(buf, adihdmi->edid_buf, len);
+	else
+		memcpy(buf, adihdmi->edid_buf + 128, len);
+
+	return 0;
+}
+
+static int adihdmi_mode_valid(struct drm_display_mode *mode)
+{
+	if (mode->clock > 165000)
+		return MODE_CLOCK_HIGH;
+
+	return MODE_OK;
+}
+
+/* -----------------------------------------------------------------------------
+ * DT and private structure operations
+ */
+
+#define conn_to_adihdmi2(x) \
+	container_of(x, struct adihdmi2, connector);
+
+#define enc_to_adihdmi2(x) \
+	container_of(x, struct adihdmi2, encoder);
+
+#define enc_to_adihdmi(x) \
+	(&(container_of(x, struct adihdmi2, encoder)->base))
+
+static int adihdmi_parse_dt(struct device_node *np,
+		struct adihdmi_link_config *config)
+{
+	memset(config, 0, sizeof(*config));
+
+	config->input_color_depth = 8;
+
+	config->input_colorspace = HDMI_COLORSPACE_RGB;
+	//config->input_colorspace = HDMI_COLORSPACE_YUV422;
+	//config->input_colorspace = HDMI_COLORSPACE_YUV444;
+
+	config->input_clock = ADIHDMI_INPUT_CLOCK_1X;
+	//config->input_clock = ADIHDMI_INPUT_CLOCK_2X;
+	//config->input_clock = ADIHDMI_INPUT_CLOCK_DDR;
+
+	if (config->input_colorspace == HDMI_COLORSPACE_YUV422 ||
+			config->input_clock != ADIHDMI_INPUT_CLOCK_1X) {
+
+		config->input_style = 1;
+		//config->input_justification = ADIHDMI_INPUT_JUSTIFICATION_LEFT;
+		config->input_justification = ADIHDMI_INPUT_JUSTIFICATION_EVENLY;
+		//config->input_justification = ADIHDMI_INPUT_JUSTIFICATION_RIGHT;
+
+	} else {
+		config->input_style = 1;
+		config->input_justification = ADIHDMI_INPUT_JUSTIFICATION_LEFT;
+	}
+
+	config->clock_delay = 0;
+	config->embedded_sync = 0;
+
+	/* Hardcode the sync pulse configurations for now. */
+	config->sync_pulse = ADIHDMI_INPUT_SYNC_PULSE_NONE;
+	config->vsync_polarity = ADIHDMI_SYNC_POLARITY_PASSTHROUGH;
+	config->hsync_polarity = ADIHDMI_SYNC_POLARITY_PASSTHROUGH;
+
+	return 0;
+}
+
+static const int edid_i2c_addr = 0x7e;
+static const int packet_i2c_addr = 0x70;
+static const int cec_i2c_addr = 0x78;
+
+static int adihdmi_create(struct i2c_client *i2c, struct adihdmi *adihdmi)
+{
+	struct adihdmi_link_config link_config;
+	struct device *dev = &i2c->dev;
+	unsigned int val;
+	int ret;
+
+	adihdmi->powered = false;
+	adihdmi->status = connector_status_disconnected;
+
+	ret = adihdmi_parse_dt(NULL, &link_config);
+	if (ret)
+	{
+		pr_err("%s - %d - Bad parse\n", __FUNCTION__, __LINE__);
+		return -EINVAL;
+	}
+
+	/*
+	 * The power down GPIO is optional. If present, toggle it from active to
+	 * inactive to wake up the encoder.
+	 */
+	adihdmi->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
+	if (IS_ERR(adihdmi->gpio_pd))
+	{
+		pr_err("%s - %d - Bad PD GPIO\n", __FUNCTION__, __LINE__);
+		return PTR_ERR(adihdmi->gpio_pd);
+	}
+
+	if (adihdmi->gpio_pd) {
+		mdelay(5);
+		gpiod_set_value_cansleep(adihdmi->gpio_pd, 0);
+	}
+
+	adihdmi->regmap = devm_regmap_init_i2c(i2c, &adihdmi_regmap_config);
+	if (IS_ERR(adihdmi->regmap))
+	{
+		pr_err("%s - %d - Bad reg map init\n", __FUNCTION__, __LINE__);
+		return PTR_ERR(adihdmi->regmap);
+	}
+
+	ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_CHIP_REVISION, &val);
+	if (ret)
+	{
+		pr_err("%s - %d - Bad reg map read\n", __FUNCTION__, __LINE__);
+		return ret;
+	}
+	dev_dbg(dev, "Rev. %d\n", val);
+
+	ret = regmap_register_patch(adihdmi->regmap, adihdmi_fixed_registers,
+			ARRAY_SIZE(adihdmi_fixed_registers));
+	if (ret)
+	{
+		pr_err("%s - %d - Bad reg map patch\n", __FUNCTION__, __LINE__);
+		return ret;
+	}
+
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_EDID_I2C_ADDR, edid_i2c_addr);
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_PACKET_I2C_ADDR,
+			packet_i2c_addr);
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_CEC_I2C_ADDR, cec_i2c_addr);
+	adihdmi_packet_disable(adihdmi, 0xffff);
+
+	adihdmi->i2c_main = i2c;
+	adihdmi->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1);
+	if (!adihdmi->i2c_edid)
+	{
+		pr_err("%s - %d - No mem for EDID\n", __FUNCTION__, __LINE__);
+		return -ENOMEM;
+	}
+
+	if (i2c->irq) {
+		init_waitqueue_head(&adihdmi->wq);
+
+		ret = devm_request_threaded_irq(dev, i2c->irq, NULL,
+				adihdmi_irq_handler,
+				IRQF_ONESHOT, dev_name(dev),
+				adihdmi);
+		if (ret)
+		{
+			pr_err("%s - %d - Bad IRQ thread request\n", __FUNCTION__, __LINE__);
+			goto err_i2c_unregister_device;
+		}
+	}
+
+	/* CEC is unused for now */
+	regmap_write(adihdmi->regmap, ADIHDMI_REG_CEC_CTRL,
+			ADIHDMI_CEC_CTRL_POWER_DOWN);
+
+	adihdmi_power_off(adihdmi);
+
+	adihdmi_set_link_config(adihdmi, &link_config);
+
+	adihdmi_audio_setup(adihdmi);
+
+	return 0;
+
+err_i2c_unregister_device:
+	i2c_unregister_device(adihdmi->i2c_edid);
+
+	return ret;
+}
+
+static void adihdmi_destroy(struct adihdmi *priv)
+{
+	i2c_unregister_device(priv->i2c_edid);
+}
+
+/* -----------------------------------------------------------------------------
+ * Encoder operations
+ */
+
+static int adihdmi_encoder_get_modes(struct adihdmi *adihdmi,
+		struct drm_connector *connector)
+{
+	struct edid *edid;
+	unsigned int count;
+
+	/* Reading the EDID only works if the device is powered */
+	if (!adihdmi->powered) {
+		regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(0),
+				ADIHDMI_INT0_EDID_READY);
+		regmap_write(adihdmi->regmap, ADIHDMI_REG_INT(1),
+				ADIHDMI_INT1_DDC_ERROR);
+		regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER,
+				ADIHDMI_POWER_POWER_DOWN, 0);
+		adihdmi->current_edid_segment = -1;
+	}
+
+	edid = drm_do_get_edid(connector, adihdmi_get_edid_block, adihdmi);
+
+	if (!adihdmi->powered)
+		regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER,
+				ADIHDMI_POWER_POWER_DOWN,
+				ADIHDMI_POWER_POWER_DOWN);
+
+	kfree(adihdmi->edid);
+	adihdmi->edid = edid;
+	if (!edid)
+	{
+		pr_err("%s - %d - No EDID\n", __FUNCTION__, __LINE__);
+		return 0;
+	}
+
+	drm_mode_connector_update_edid_property(connector, edid);
+	count = drm_add_edid_modes(connector, edid);
+
+	adihdmi_set_config_csc(adihdmi, connector, adihdmi->rgb);
+
+	return count;
+}
+
+static void adihdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct adihdmi2 *priv2 = enc_to_adihdmi2(encoder);
+
+	if (mode == DRM_MODE_DPMS_ON)
+		adihdmi_power_on(&priv2->base);
+	else
+		adihdmi_power_off(&priv2->base);
+}
+
+	static enum drm_connector_status
+adihdmi_encoder_detect(struct adihdmi *adihdmi,
+		struct drm_connector *connector)
+{
+	enum drm_connector_status status;
+	unsigned int val;
+	bool hpd;
+	int ret;
+
+	ret = regmap_read(adihdmi->regmap, ADIHDMI_REG_STATUS, &val);
+	if (ret < 0)
+	{
+		pr_err("%s - %d - Disconnected\n", __FUNCTION__, __LINE__);
+		return connector_status_disconnected;
+	}
+
+	if (val & ADIHDMI_STATUS_HPD)
+		status = connector_status_connected;
+	else
+		status = connector_status_disconnected;
+
+	hpd = adihdmi_hpd(adihdmi);
+
+	/* The chip resets itself when the cable is disconnected, so in case
+	 * there is a pending HPD interrupt and the cable is connected there was
+	 * at least one transition from disconnected to connected and the chip
+	 * has to be reinitialized. */
+	if (status == connector_status_connected && hpd && adihdmi->powered) {
+		regcache_mark_dirty(adihdmi->regmap);
+		adihdmi_power_on(adihdmi);
+		adihdmi_encoder_get_modes(adihdmi, connector);
+		if (adihdmi->status == connector_status_connected)
+			status = connector_status_disconnected;
+	} else {
+		/* Renable HDP sensing */
+		regmap_update_bits(adihdmi->regmap, ADIHDMI_REG_POWER2,
+				ADIHDMI_REG_POWER2_HDP_SRC_MASK,
+				ADIHDMI_REG_POWER2_HDP_SRC_BOTH);
+	}
+
+	adihdmi->status = status;
+	return status;
+}
+
+static bool adihdmi_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static int adihdmi_encoder_mode_valid(struct drm_encoder *encoder, struct drm_display_mode *mode)
+{
+	return adihdmi_mode_valid(mode);
+}
+
+static void adihdmi_encoder_mode_set(struct drm_encoder *encoder,
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adj_mode)
+{
+	unsigned int low_refresh_rate;
+	unsigned int hsync_polarity = 0;
+	unsigned int vsync_polarity = 0;
+	struct adihdmi *adihdmi = enc_to_adihdmi(encoder);
+
+	if (adihdmi->embedded_sync) {
+		unsigned int hsync_offset, hsync_len;
+		unsigned int vsync_offset, vsync_len;
+
+		hsync_offset = adj_mode->crtc_hsync_start -
+			adj_mode->crtc_hdisplay;
+		vsync_offset = adj_mode->crtc_vsync_start -
+			adj_mode->crtc_vdisplay;
+		hsync_len = adj_mode->crtc_hsync_end -
+			adj_mode->crtc_hsync_start;
+		vsync_len = adj_mode->crtc_vsync_end -
+			adj_mode->crtc_vsync_start;
+
+		/* The hardware vsync generator has a off-by-one bug */
+		vsync_offset += 1;
+
+		regmap_write(adihdmi->regmap, ADIHDMI_REG_HSYNC_PLACEMENT_MSB,
+				((hsync_offset >> 10) & 0x7) << 5);
+		regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(0),
+				(hsync_offset >> 2) & 0xff);
+		regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(1),
+				((hsync_offset & 0x3) << 6) |
+				((hsync_len >> 4) & 0x3f));
+		regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(2),
+				((hsync_len & 0xf) << 4) |
+				((vsync_offset >> 6) & 0xf));
+		regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(3),
+				((vsync_offset & 0x3f) << 2) |
+				((vsync_len >> 8) & 0x3));
+		regmap_write(adihdmi->regmap, ADIHDMI_REG_SYNC_DECODER(4),
+				vsync_len & 0xff);
+
+		hsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PHSYNC);
+		vsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PVSYNC);
+	} else {
+		enum adihdmi_sync_polarity mode_hsync_polarity;
+		enum adihdmi_sync_polarity mode_vsync_polarity;
+
+		/**
+		 * If the input signal is always low or always high we want to
+		 * invert or let it passthrough depending on the polarity of the
+		 * current mode.
+		 **/
+		if (adj_mode->flags & DRM_MODE_FLAG_NHSYNC)
+			mode_hsync_polarity = ADIHDMI_SYNC_POLARITY_LOW;
+		else
+			mode_hsync_polarity = ADIHDMI_SYNC_POLARITY_HIGH;
+
+		if (adj_mode->flags & DRM_MODE_FLAG_NVSYNC)
+			mode_vsync_polarity = ADIHDMI_SYNC_POLARITY_LOW;
+		else
+			mode_vsync_polarity = ADIHDMI_SYNC_POLARITY_HIGH;
+
+		if (adihdmi->hsync_polarity != mode_hsync_polarity &&
+				adihdmi->hsync_polarity !=
+				ADIHDMI_SYNC_POLARITY_PASSTHROUGH)
+			hsync_polarity = 1;
+
+		if (adihdmi->vsync_polarity != mode_vsync_polarity &&
+				adihdmi->vsync_polarity !=
+				ADIHDMI_SYNC_POLARITY_PASSTHROUGH)
+			vsync_polarity = 1;
+	}
+
+	if (mode->vrefresh <= 24000)
+		low_refresh_rate = ADIHDMI_LOW_REFRESH_RATE_24HZ;
+	else if (mode->vrefresh <= 25000)
+		low_refresh_rate = ADIHDMI_LOW_REFRESH_RATE_25HZ;
+	else if (mode->vrefresh <= 30000)
+		low_refresh_rate = ADIHDMI_LOW_REFRESH_RATE_30HZ;
+	else
+		low_refresh_rate = ADIHDMI_LOW_REFRESH_RATE_NONE;
+
+	regmap_update_bits(adihdmi->regmap, 0xfb,
+			0x6, low_refresh_rate << 1);
+	regmap_update_bits(adihdmi->regmap, 0x17,
+			0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
+
+	/*
+	 * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
+	 * supposed to give better results.
+	 */
+
+			adihdmi->f_tmds = mode->clock;
+}
+
+static void adihdmi_encoder_prepare(struct drm_encoder *encoder)
+{
+	adihdmi_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void adihdmi_encoder_commit(struct drm_encoder *encoder)
+{
+	adihdmi_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static struct drm_encoder_helper_funcs adihdmi_encoder_helper_funcs = {
+	.dpms		= adihdmi_encoder_dpms,
+	.mode_fixup	= adihdmi_encoder_mode_fixup,
+	.prepare	= adihdmi_encoder_prepare,
+	.commit		= adihdmi_encoder_commit,
+	.mode_set	= adihdmi_encoder_mode_set,
+};
+
+static void adihdmi_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct adihdmi2 *priv = enc_to_adihdmi2(encoder);
+
+	adihdmi_destroy(&priv->base);
+	drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs adihdmi_encoder_funcs = {
+	.destroy = adihdmi_encoder_destroy,
+};
+
+/* -----------------------------------------------------------------------------
+ * Slave operations
+ */
+
+static int adihdmi_encoder_slave_create_resources(struct drm_encoder *encoder, struct drm_connector *connector)
+{
+	pr_debug("%s - %d\n", __FUNCTION__, __LINE__);
+	return 0;
+}
+
+static void adihdmi_encoder_slave_destroy(struct drm_encoder *encoder)
+{
+	pr_debug("%s - %d\n", __FUNCTION__, __LINE__);
+}
+
+	static enum drm_connector_status
+adihdmi_encoder_slave_detect(struct drm_encoder *encoder,
+		struct drm_connector *connector)
+{
+	return adihdmi_encoder_detect(enc_to_adihdmi(encoder),
+			connector);
+}
+
+static int adihdmi_encoder_slave_get_modes(struct drm_encoder *encoder,
+		struct drm_connector *connector)
+{
+	return adihdmi_encoder_get_modes(enc_to_adihdmi(encoder),
+			connector);
+}
+
+
+static void adihdmi_encoder_slave_set_config(struct drm_encoder *encoder, void *params)
+{
+	pr_debug("%s - %d\n", __FUNCTION__, __LINE__);
+}
+
+static int adihdmi_encoder_set_property(struct drm_encoder *encoder, struct drm_connector *connector, struct drm_property *property, uint64_t val)
+{
+	pr_debug("%s - %d\n", __FUNCTION__, __LINE__);
+	return 0;
+}
+
+static struct drm_encoder_slave_funcs adihdmi_encoder_slave_funcs = {
+	.create_resources   = adihdmi_encoder_slave_create_resources,
+	.destroy            = adihdmi_encoder_slave_destroy,
+	.detect             = adihdmi_encoder_slave_detect,
+	.dpms               = adihdmi_encoder_dpms,
+	.get_modes          = adihdmi_encoder_slave_get_modes,
+	.mode_fixup         = adihdmi_encoder_mode_fixup,
+	.mode_set           = adihdmi_encoder_mode_set,
+	.mode_valid         = adihdmi_encoder_mode_valid,
+	.set_config         = adihdmi_encoder_slave_set_config,
+	.set_property       = adihdmi_encoder_set_property,
+};
+
+/* -----------------------------------------------------------------------------
+ * Connector operations
+ */
+
+static int adihdmi_connector_get_modes(struct drm_connector *connector)
+{
+	struct adihdmi2 *priv = conn_to_adihdmi2(connector);
+
+	return adihdmi_encoder_get_modes(&priv->base, connector);
+}
+
+static int adihdmi_connector_mode_valid(struct drm_connector *connector,
+		struct drm_display_mode *mode)
+{
+	return adihdmi_mode_valid(mode);
+}
+
+	static struct drm_encoder *
+adihdmi_connector_best_encoder(struct drm_connector *connector)
+{
+	struct adihdmi2 *priv = conn_to_adihdmi2(connector);
+
+	return &priv->encoder;
+}
+
+static struct drm_connector_helper_funcs adihdmi_connector_helper_funcs = {
+	.get_modes          = adihdmi_connector_get_modes,
+	.mode_valid         = adihdmi_connector_mode_valid,
+	.best_encoder	    = adihdmi_connector_best_encoder,
+};
+
+	static enum drm_connector_status
+adihdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct adihdmi2 *priv = conn_to_adihdmi2(connector);
+
+	return adihdmi_encoder_detect(&priv->base, connector);
+}
+
+static void adihdmi_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs adihdmi_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = adihdmi_connector_detect,
+	.destroy = adihdmi_connector_destroy,
+};
+
+/* -----------------------------------------------------------------------------
+ * Component operations
+ */
+
+static int adihdmi_bind(struct device *dev, struct device *master, void *data)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct drm_device *drm = data;
+	struct adihdmi2 *priv;
+	uint32_t crtcs = 0;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+	{
+		pr_err("%s - %d - No memory for ADIHDMI\n", __FUNCTION__, __LINE__);
+		return -ENOMEM;
+	}
+
+	dev_set_drvdata(dev, priv);
+
+	if (dev->of_node)
+		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+	/* If no CRTCs were found, fall back to our old behaviour */
+	if (crtcs == 0) {
+		dev_warn(dev, "Falling back to first CRTC\n");
+		crtcs = 1 << 0;
+	}
+
+	priv->base.encoder = &priv->encoder;
+	priv->connector.interlace_allowed = 1;
+	priv->encoder.possible_crtcs = crtcs;
+
+	ret = adihdmi_create(client, &priv->base);
+	if (ret)
+		return ret;
+
+	drm_encoder_helper_add(&priv->encoder, &adihdmi_encoder_helper_funcs);
+	ret = drm_encoder_init(drm, &priv->encoder, &adihdmi_encoder_funcs,
+			DRM_MODE_ENCODER_TMDS, NULL);
+	if (ret)
+		goto err_encoder;
+
+	drm_connector_helper_add(&priv->connector,
+			&adihdmi_connector_helper_funcs);
+	ret = drm_connector_init(drm, &priv->connector,
+			&adihdmi_connector_funcs,
+			DRM_MODE_CONNECTOR_HDMIA);
+	if (ret)
+		goto err_connector;
+
+	ret = drm_connector_register(&priv->connector);
+	if (ret)
+		goto err_sysfs;
+
+	priv->connector.encoder = &priv->encoder;
+	drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
+
+	return 0;
+
+err_sysfs:
+	drm_connector_cleanup(&priv->connector);
+err_connector:
+	drm_encoder_cleanup(&priv->encoder);
+err_encoder:
+	adihdmi_destroy(&priv->base);
+	return ret;
+
+
+}
+
+static void adihdmi_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct adihdmi2 *priv = dev_get_drvdata(dev);
+
+	drm_connector_cleanup(&priv->connector);
+	drm_encoder_cleanup(&priv->encoder);
+	adihdmi_destroy(&priv->base);
+}
+
+static const struct component_ops adihdmi_ops =
+{
+	.bind = adihdmi_bind,
+	.unbind = adihdmi_unbind,
+};
+
+/* -----------------------------------------------------------------------------
+ * Init operations
+ */
+
+static int adihdmi_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	return component_add(&i2c->dev, &adihdmi_ops);
+}
+
+static int adihdmi_remove(struct i2c_client *i2c)
+{
+	component_del(&i2c->dev, &adihdmi_ops);
+
+	return 0;
+}
+
+static int adihdmi_encoder_init(struct i2c_client *i2c, struct drm_device *dev,
+		struct drm_encoder_slave *encoder_slave)
+{
+
+	struct adihdmi *adihdmi;
+	int ret;
+
+	adihdmi = kzalloc(sizeof(*adihdmi), GFP_KERNEL);
+	if (!adihdmi)
+		return -ENOMEM;
+
+	adihdmi->encoder = &encoder_slave->base;
+
+	ret = adihdmi_create(i2c, adihdmi);
+	if (ret) {
+		kfree(adihdmi);
+		return ret;
+	}
+
+	encoder_slave->slave_priv = adihdmi;
+	encoder_slave->slave_funcs = &adihdmi_encoder_slave_funcs;
+
+	return 0;
+}
+
+static const struct i2c_device_id adihdmi_i2c_ids[] = {
+	{ "adv7511", 0 },
+	{ "adv7511w", 0 },
+	{ "adv7513", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, adihdmi_i2c_ids);
+
+static const struct of_device_id adihdmi_of_ids[] = {
+	{ .compatible = "adi,adv7511", },
+	{ .compatible = "adi,adv7511w", },
+	{ .compatible = "adi,adv7513", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adihdmi_of_ids);
+
+static struct drm_i2c_encoder_driver adihdmi_driver = {
+	.i2c_driver = {
+		.driver = {
+			.name = "adihdmi",
+			.of_match_table = adihdmi_of_ids,
+		},
+		.id_table = adihdmi_i2c_ids,
+		.probe = adihdmi_probe,
+		.remove = adihdmi_remove,
+	},
+
+	.encoder_init = adihdmi_encoder_init,
+};
+
+static int __init adihdmi_init(void)
+{
+	return drm_i2c_encoder_register(THIS_MODULE, &adihdmi_driver);
+}
+module_init(adihdmi_init);
+
+static void __exit adihdmi_exit(void)
+{
+	drm_i2c_encoder_unregister(&adihdmi_driver);
+}
+module_exit(adihdmi_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADIHDMI HDMI transmitter driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 051e5e1..6dce763 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -46,6 +46,7 @@ struct tilcdc_crtc {
 
 	int sync_lost_count;
 	bool frame_intact;
+	struct work_struct recover_work;
 };
 #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base)
 
@@ -113,9 +114,47 @@ static void start(struct drm_crtc *crtc)
 
 static void stop(struct drm_crtc *crtc)
 {
+	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
+	struct tilcdc_drm_private *priv = dev->dev_private;
 
+	tilcdc_crtc->frame_done = false;
 	tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
+
+	/*
+	 * if necessary wait for framedone irq which will still come
+	 * before putting things to sleep..
+	 */
+	if (priv->rev == 2) {
+		int ret = wait_event_timeout(tilcdc_crtc->frame_done_wq,
+					     tilcdc_crtc->frame_done,
+					     msecs_to_jiffies(50));
+		if (ret == 0)
+			dev_err(dev->dev, "%s: timeout waiting for framedone\n",
+				__func__);
+	}
+}
+
+static void tilcdc_crtc_recover_work(struct work_struct *work)
+{
+	struct tilcdc_crtc *tilcdc_crtc =
+		container_of(work, struct tilcdc_crtc, recover_work);
+	struct drm_crtc *crtc = &tilcdc_crtc->base;
+	struct drm_device *dev = crtc->dev;
+
+	dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__);
+
+	drm_modeset_lock_crtc(crtc, NULL);
+
+	if (tilcdc_crtc->dpms == DRM_MODE_DPMS_OFF)
+		goto out;
+
+	tilcdc_crtc->frame_done = false;
+	stop(crtc);
+	tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, LCDC_SYNC_LOST);
+	start(crtc);
+out:
+	drm_modeset_unlock_crtc(crtc);
 }
 
 static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
@@ -212,22 +251,7 @@ void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode)
 		pm_runtime_get_sync(dev->dev);
 		start(crtc);
 	} else {
-		tilcdc_crtc->frame_done = false;
 		stop(crtc);
-
-		/*
-		 * if necessary wait for framedone irq which will still come
-		 * before putting things to sleep..
-		 */
-		if (priv->rev == 2) {
-			int ret = wait_event_timeout(
-					tilcdc_crtc->frame_done_wq,
-					tilcdc_crtc->frame_done,
-					msecs_to_jiffies(50));
-			if (ret == 0)
-				dev_err(dev->dev, "timeout waiting for framedone\n");
-		}
-
 		pm_runtime_put_sync(dev->dev);
 
 		if (tilcdc_crtc->next_fb) {
@@ -718,30 +742,38 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc)
 			tilcdc_crtc->frame_intact = true;
 	}
 
-	if (priv->rev == 2) {
-		if (stat & LCDC_FRAME_DONE) {
-			tilcdc_crtc->frame_done = true;
-			wake_up(&tilcdc_crtc->frame_done_wq);
-		}
-		tilcdc_write(dev, LCDC_END_OF_INT_IND_REG, 0);
+	if (priv->rev == 1)
+		return IRQ_HANDLED;
+	/* The rest is for revision 2 only */
+
+	if (stat & LCDC_FRAME_DONE) {
+		tilcdc_crtc->frame_done = true;
+		wake_up(&tilcdc_crtc->frame_done_wq);
 	}
 
+	if (stat & LCDC_FIFO_UNDERFLOW)
+		dev_err_ratelimited(dev->dev, "%s(0x%08x): FIFO underfow",
+				    __func__, stat);
+
 	if (stat & LCDC_SYNC_LOST) {
 		dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost",
 				    __func__, stat);
 		tilcdc_crtc->frame_intact = false;
 		if (tilcdc_crtc->sync_lost_count++ > SYNC_LOST_COUNT_LIMIT) {
 			dev_err(dev->dev,
-				"%s(0x%08x): Sync lost flood detected, disabling the interrupt",
+				"%s(0x%08x): Sync lost flood detected, recovering",
 				__func__, stat);
+			queue_work(system_wq, &tilcdc_crtc->recover_work);
 			tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
 				     LCDC_SYNC_LOST);
+			tilcdc_crtc->sync_lost_count = 0;
 		}
 	}
 
-	if (stat & LCDC_FIFO_UNDERFLOW)
-		dev_err_ratelimited(dev->dev, "%s(0x%08x): FIFO underfow",
-				    __func__, stat);
+	/* Indicate to LCDC that the interrupt service routine has
+	 * completed, see 13.3.6.1.6 in AM335x TRM.
+	 */
+	tilcdc_write(dev, LCDC_END_OF_INT_IND_REG, 0);
 
 	return IRQ_HANDLED;
 }
@@ -768,6 +800,7 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
 			"unref", unref_worker);
 
 	spin_lock_init(&tilcdc_crtc->irq_lock);
+	INIT_WORK(&tilcdc_crtc->recover_work, tilcdc_crtc_recover_work);
 
 	ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs);
 	if (ret < 0)
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 9d233bb..a8e89df 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -617,7 +617,7 @@ const struct i2c_algorithm i2c_bit_algo = {
 };
 EXPORT_SYMBOL(i2c_bit_algo);
 
-const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = {
+static const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = {
 	.flags = I2C_AQ_NO_CLK_STRETCH,
 };
 
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0967e1a..f167021 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -663,7 +663,7 @@ config I2C_MT65XX
 
 config I2C_MV64XXX
 	tristate "Marvell mv64xxx I2C Controller"
-	depends on MV64X60 || PLAT_ORION || ARCH_SUNXI
+	depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU
 	help
 	  If you say yes to this option, support will be included for the
 	  built-in I2C interface on the Marvell 64xxx line of host bridges.
@@ -965,7 +965,7 @@ config I2C_XILINX
 
 config I2C_XLR
 	tristate "Netlogic XLR and Sigma Designs I2C support"
-	depends on CPU_XLR || ARCH_TANGOX
+	depends on CPU_XLR || ARCH_TANGO
 	help
 	  This driver enables support for the on-chip I2C interface of
 	  the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs.
@@ -985,6 +985,7 @@ config I2C_XLP9XX
 
 config I2C_RCAR
 	tristate "Renesas R-Car I2C Controller"
+	depends on HAS_DMA
 	depends on ARCH_RENESAS || COMPILE_TEST
 	select I2C_SLAVE
 	help
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 921d32b..f233726 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -1013,7 +1013,7 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
 
 error:
 	if (ret != -EPROBE_DEFER)
-		dev_info(dev->dev, "can't use DMA, error %d\n", ret);
+		dev_info(dev->dev, "can't get DMA channel, continue without DMA support\n");
 	if (dma->chan_rx)
 		dma_release_channel(dma->chan_rx);
 	if (dma->chan_tx)
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index b9f0fff..19c8438 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -267,7 +267,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
 	iproc_i2c->msg = msg;
 
 	/* format and load slave address into the TX FIFO */
-	addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0);
+	addr = i2c_8bit_addr_from_msg(msg);
 	writel(addr, iproc_i2c->base + M_TX_OFFSET);
 
 	/*
diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c
index 2c9d9b1..ac9f476 100644
--- a/drivers/i2c/busses/i2c-bcm-kona.c
+++ b/drivers/i2c/busses/i2c-bcm-kona.c
@@ -501,10 +501,7 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
 				return -EREMOTEIO;
 		}
 	} else {
-		addr = msg->addr << 1;
-
-		if (msg->flags & I2C_M_RD)
-			addr |= 1;
+		addr = i2c_8bit_addr_from_msg(msg);
 
 		if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
 			return -EREMOTEIO;
diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c
index 4a45408..6a8cfc1 100644
--- a/drivers/i2c/busses/i2c-brcmstb.c
+++ b/drivers/i2c/busses/i2c-brcmstb.c
@@ -446,9 +446,7 @@ static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev,
 
 		}
 	} else {
-		addr = msg->addr << 1;
-		if (msg->flags & I2C_M_RD)
-			addr |= 1;
+		addr = i2c_8bit_addr_from_msg(msg);
 
 		bsc_writel(dev, addr, chip_address);
 	}
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index b167ab2..ee57c1e 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -197,9 +197,7 @@ static void cpm_i2c_parse_message(struct i2c_adapter *adap,
 	tbdf = cpm->tbase + tx;
 	rbdf = cpm->rbase + rx;
 
-	addr = pmsg->addr << 1;
-	if (pmsg->flags & I2C_M_RD)
-		addr |= 1;
+	addr = i2c_8bit_addr_from_msg(pmsg);
 
 	tb = cpm->txbuf[tx];
 	rb = cpm->rxbuf[rx];
diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c
index 1600edd..f2eb4f7 100644
--- a/drivers/i2c/busses/i2c-dln2.c
+++ b/drivers/i2c/busses/i2c-dln2.c
@@ -19,6 +19,7 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/dln2.h>
+#include <linux/acpi.h>
 
 #define DLN2_I2C_MODULE_ID		0x03
 #define DLN2_I2C_CMD(cmd)		DLN2_CMD(cmd, DLN2_I2C_MODULE_ID)
@@ -210,6 +211,7 @@ static int dln2_i2c_probe(struct platform_device *pdev)
 	dln2->adapter.algo = &dln2_i2c_usb_algorithm;
 	dln2->adapter.quirks = &dln2_i2c_quirks;
 	dln2->adapter.dev.parent = dev;
+	ACPI_COMPANION_SET(&dln2->adapter.dev, ACPI_COMPANION(&pdev->dev));
 	dln2->adapter.dev.of_node = dev->of_node;
 	i2c_set_adapdata(&dln2->adapter, dln2);
 	snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
index f54ece8..c0e3ada 100644
--- a/drivers/i2c/busses/i2c-exynos5.c
+++ b/drivers/i2c/busses/i2c-exynos5.c
@@ -861,14 +861,8 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
 #endif
 
 static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
-#ifdef CONFIG_PM_SLEEP
-	.suspend_noirq = exynos5_i2c_suspend_noirq,
-	.resume_noirq = exynos5_i2c_resume_noirq,
-	.freeze_noirq = exynos5_i2c_suspend_noirq,
-	.thaw_noirq = exynos5_i2c_resume_noirq,
-	.poweroff_noirq = exynos5_i2c_suspend_noirq,
-	.restore_noirq = exynos5_i2c_resume_noirq,
-#endif
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos5_i2c_suspend_noirq,
+				      exynos5_i2c_resume_noirq)
 };
 
 static struct platform_driver exynos5_i2c_driver = {
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index f1b0eaf..4a60ad2 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -94,6 +94,7 @@
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/itco_wdt.h>
+#include <linux/pm_runtime.h>
 
 #if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
 		defined CONFIG_DMI
@@ -730,6 +731,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
 		return -EBUSY;
 	}
 
+	pm_runtime_get_sync(&priv->pci_dev->dev);
+
 	hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
 		&& size != I2C_SMBUS_QUICK
 		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
@@ -828,6 +831,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
 	}
 
 out:
+	pm_runtime_mark_last_busy(&priv->pci_dev->dev);
+	pm_runtime_put_autosuspend(&priv->pci_dev->dev);
 	mutex_unlock(&priv->acpi_lock);
 	return ret;
 }
@@ -1287,6 +1292,12 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
 
 		dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
 		dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n");
+
+		/*
+		 * BIOS is accessing the host controller so prevent it from
+		 * suspending automatically from now on.
+		 */
+		pm_runtime_get_sync(&pdev->dev);
 	}
 
 	if ((function & ACPI_IO_MASK) == ACPI_READ)
@@ -1326,6 +1337,11 @@ static void i801_acpi_remove(struct i801_priv *priv)
 
 	acpi_remove_address_space_handler(adev->handle,
 		ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler);
+
+	mutex_lock(&priv->acpi_lock);
+	if (priv->acpi_reserved)
+		pm_runtime_put(&priv->pci_dev->dev);
+	mutex_unlock(&priv->acpi_lock);
 }
 #else
 static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
@@ -1497,6 +1513,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	pci_set_drvdata(dev, priv);
 
+	pm_runtime_set_autosuspend_delay(&dev->dev, 1000);
+	pm_runtime_use_autosuspend(&dev->dev);
+	pm_runtime_put_autosuspend(&dev->dev);
+	pm_runtime_allow(&dev->dev);
+
 	return 0;
 }
 
@@ -1504,6 +1525,9 @@ static void i801_remove(struct pci_dev *dev)
 {
 	struct i801_priv *priv = pci_get_drvdata(dev);
 
+	pm_runtime_forbid(&dev->dev);
+	pm_runtime_get_noresume(&dev->dev);
+
 	i801_del_mux(priv);
 	i2c_del_adapter(&priv->adapter);
 	i801_acpi_remove(priv);
@@ -1518,34 +1542,32 @@ static void i801_remove(struct pci_dev *dev)
 }
 
 #ifdef CONFIG_PM
-static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
+static int i801_suspend(struct device *dev)
 {
-	struct i801_priv *priv = pci_get_drvdata(dev);
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct i801_priv *priv = pci_get_drvdata(pci_dev);
 
-	pci_save_state(dev);
-	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
-	pci_set_power_state(dev, pci_choose_state(dev, mesg));
+	pci_write_config_byte(pci_dev, SMBHSTCFG, priv->original_hstcfg);
 	return 0;
 }
 
-static int i801_resume(struct pci_dev *dev)
+static int i801_resume(struct device *dev)
 {
-	pci_set_power_state(dev, PCI_D0);
-	pci_restore_state(dev);
 	return 0;
 }
-#else
-#define i801_suspend NULL
-#define i801_resume NULL
 #endif
 
+static UNIVERSAL_DEV_PM_OPS(i801_pm_ops, i801_suspend,
+			    i801_resume, NULL);
+
 static struct pci_driver i801_driver = {
 	.name		= "i801_smbus",
 	.id_table	= i801_ids,
 	.probe		= i801_probe,
 	.remove		= i801_remove,
-	.suspend	= i801_suspend,
-	.resume		= i801_resume,
+	.driver		= {
+		.pm	= &i801_pm_ops,
+	},
 };
 
 static int __init i2c_i801_init(void)
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index b6c0803..cdaa7be 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -269,7 +269,7 @@ static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
 	ndelay(t->hd_sta);
 
 	/* Send address */
-	v = (u8)((p->addr << 1) | ((p->flags & I2C_M_RD) ? 1 : 0));
+	v = i2c_8bit_addr_from_msg(p);
 	for (i = 0, mask = 0x80; i < 8; ++i, mask >>= 1){
 		out_8(&iic->directcntl, sda);
 		ndelay(t->low / 2);
diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
index 379ef9c..ea20425 100644
--- a/drivers/i2c/busses/i2c-img-scb.c
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -751,9 +751,7 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c,
 	switch (i2c->at_cur_cmd) {
 	case CMD_GEN_START:
 		next_cmd = CMD_GEN_DATA;
-		next_data = (i2c->msg.addr << 1);
-		if (i2c->msg.flags & I2C_M_RD)
-			next_data |= 0x1;
+		next_data = i2c_8bit_addr_from_msg(&i2c->msg);
 		break;
 	case CMD_GEN_DATA:
 		if (i2c->line_status & LINESTAT_INPUT_HELD_V)
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 1ca7ef2..1844bc9 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -525,7 +525,7 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
 	imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);
 
 	/* Wait controller to be stable */
-	udelay(50);
+	usleep_range(50, 150);
 
 	/* Start I2C transaction */
 	temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 72d6161..85cbe4b 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -50,10 +50,7 @@ iic_cook_addr(struct i2c_msg *msg)
 {
 	unsigned char addr;
 
-	addr = (msg->addr << 1);
-
-	if (msg->flags & I2C_M_RD)
-		addr |= 1;
+	addr = i2c_8bit_addr_from_msg(msg);
 
 	return addr;
 }
diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c
index 8560a13..586a152 100644
--- a/drivers/i2c/busses/i2c-lpc2k.c
+++ b/drivers/i2c/busses/i2c-lpc2k.c
@@ -133,9 +133,7 @@ static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c)
 	case M_START:
 	case M_REPSTART:
 		/* Start bit was just sent out, send out addr and dir */
-		data = i2c->msg->addr << 1;
-		if (i2c->msg->flags & I2C_M_RD)
-			data |= 1;
+		data = i2c_8bit_addr_from_msg(i2c->msg);
 
 		writel(data, i2c->base + LPC24XX_I2DAT);
 		writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR);
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 453358b..d9373e6 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -413,10 +413,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 	else
 		writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF);
 
-	addr_reg = msgs->addr << 1;
-	if (i2c->op == I2C_MASTER_RD)
-		addr_reg |= 0x1;
-
+	addr_reg = i2c_8bit_addr_from_msg(msgs);
 	writew(addr_reg, i2c->base + OFFSET_SLAVE_ADDR);
 
 	/* Clear interrupt status */
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 43207f5..b4dec08 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -134,9 +134,7 @@ struct mv64xxx_i2c_data {
 	int			rc;
 	u32			freq_m;
 	u32			freq_n;
-#if defined(CONFIG_HAVE_CLK)
 	struct clk              *clk;
-#endif
 	wait_queue_head_t	waitq;
 	spinlock_t		lock;
 	struct i2c_msg		*msg;
@@ -757,7 +755,6 @@ static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
 MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
 
 #ifdef CONFIG_OF
-#ifdef CONFIG_HAVE_CLK
 static int
 mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data,
 		  const int tclk, const int n, const int m)
@@ -791,25 +788,20 @@ mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data,
 		return false;
 	return true;
 }
-#endif /* CONFIG_HAVE_CLK */
 
 static int
 mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
 		  struct device *dev)
 {
-	/* CLK is mandatory when using DT to describe the i2c bus. We
-	 * need to know tclk in order to calculate bus clock
-	 * factors.
-	 */
-#if !defined(CONFIG_HAVE_CLK)
-	/* Have OF but no CLK */
-	return -ENODEV;
-#else
 	const struct of_device_id *device;
 	struct device_node *np = dev->of_node;
 	u32 bus_freq, tclk;
 	int rc = 0;
 
+	/* CLK is mandatory when using DT to describe the i2c bus. We
+	 * need to know tclk in order to calculate bus clock
+	 * factors.
+	 */
 	if (IS_ERR(drv_data->clk)) {
 		rc = -ENODEV;
 		goto out;
@@ -869,7 +861,6 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
 
 out:
 	return rc;
-#endif
 }
 #else /* CONFIG_OF */
 static int
@@ -907,14 +898,13 @@ mv64xxx_i2c_probe(struct platform_device *pd)
 	init_waitqueue_head(&drv_data->waitq);
 	spin_lock_init(&drv_data->lock);
 
-#if defined(CONFIG_HAVE_CLK)
 	/* Not all platforms have a clk */
 	drv_data->clk = devm_clk_get(&pd->dev, NULL);
-	if (!IS_ERR(drv_data->clk)) {
-		clk_prepare(drv_data->clk);
-		clk_enable(drv_data->clk);
-	}
-#endif
+	if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (!IS_ERR(drv_data->clk))
+		clk_prepare_enable(drv_data->clk);
+
 	if (pdata) {
 		drv_data->freq_m = pdata->freq_m;
 		drv_data->freq_n = pdata->freq_n;
@@ -964,13 +954,10 @@ exit_reset:
 	if (!IS_ERR_OR_NULL(drv_data->rstc))
 		reset_control_assert(drv_data->rstc);
 exit_clk:
-#if defined(CONFIG_HAVE_CLK)
 	/* Not all platforms have a clk */
-	if (!IS_ERR(drv_data->clk)) {
-		clk_disable(drv_data->clk);
-		clk_unprepare(drv_data->clk);
-	}
-#endif
+	if (!IS_ERR(drv_data->clk))
+		clk_disable_unprepare(drv_data->clk);
+
 	return rc;
 }
 
@@ -983,13 +970,9 @@ mv64xxx_i2c_remove(struct platform_device *dev)
 	free_irq(drv_data->irq, drv_data);
 	if (!IS_ERR_OR_NULL(drv_data->rstc))
 		reset_control_assert(drv_data->rstc);
-#if defined(CONFIG_HAVE_CLK)
 	/* Not all platforms have a clk */
-	if (!IS_ERR(drv_data->clk)) {
-		clk_disable(drv_data->clk);
-		clk_unprepare(drv_data->clk);
-	}
-#endif
+	if (!IS_ERR(drv_data->clk))
+		clk_disable_unprepare(drv_data->clk);
 
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 70b3c91..42fcc94 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -127,7 +127,7 @@ static struct pci_driver nforce2_driver;
 
 /* For multiplexing support, we need a global reference to the 1st
    SMBus channel */
-#if defined CONFIG_I2C_NFORCE2_S4985 || defined CONFIG_I2C_NFORCE2_S4985_MODULE
+#if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985)
 struct i2c_adapter *nforce2_smbus;
 EXPORT_SYMBOL_GPL(nforce2_smbus);
 
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 11b7b87..dfa7a4b 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -178,10 +178,7 @@ static void ocores_process(struct ocores_i2c *i2c)
 		if (i2c->nmsgs) {	/* end? */
 			/* send start? */
 			if (!(msg->flags & I2C_M_NOSTART)) {
-				u8 addr = (msg->addr << 1);
-
-				if (msg->flags & I2C_M_RD)
-					addr |= 1;
+				u8 addr = i2c_8bit_addr_from_msg(msg);
 
 				i2c->state = STATE_START;
 
diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c
index 46fb6c4..30ae351 100644
--- a/drivers/i2c/busses/i2c-octeon.c
+++ b/drivers/i2c/busses/i2c-octeon.c
@@ -11,6 +11,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/atomic.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -29,13 +30,23 @@
 /* Register offsets */
 #define SW_TWSI			0x00
 #define TWSI_INT		0x10
+#define SW_TWSI_EXT		0x18
 
 /* Controller command patterns */
 #define SW_TWSI_V		BIT_ULL(63)	/* Valid bit */
+#define SW_TWSI_EIA		BIT_ULL(61)	/* Extended internal address */
 #define SW_TWSI_R		BIT_ULL(56)	/* Result or read bit */
+#define SW_TWSI_SOVR		BIT_ULL(55)	/* Size override */
+#define SW_TWSI_SIZE_SHIFT	52
+#define SW_TWSI_ADDR_SHIFT	40
+#define SW_TWSI_IA_SHIFT	32		/* Internal address */
 
 /* Controller opcode word (bits 60:57) */
 #define SW_TWSI_OP_SHIFT	57
+#define SW_TWSI_OP_7		(0ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_7_IA		(1ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10		(2ULL << SW_TWSI_OP_SHIFT)
+#define SW_TWSI_OP_10_IA	(3ULL << SW_TWSI_OP_SHIFT)
 #define SW_TWSI_OP_TWSI_CLK	(4ULL << SW_TWSI_OP_SHIFT)
 #define SW_TWSI_OP_EOP		(6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */
 
@@ -48,46 +59,93 @@
 #define SW_TWSI_EOP_TWSI_RST	(SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT)
 
 /* Controller command and status bits */
-#define TWSI_CTL_CE		0x80
+#define TWSI_CTL_CE		0x80	/* High level controller enable */
 #define TWSI_CTL_ENAB		0x40	/* Bus enable */
 #define TWSI_CTL_STA		0x20	/* Master-mode start, HW clears when done */
 #define TWSI_CTL_STP		0x10	/* Master-mode stop, HW clears when done */
 #define TWSI_CTL_IFLG		0x08	/* HW event, SW writes 0 to ACK */
 #define TWSI_CTL_AAK		0x04	/* Assert ACK */
 
-/* Some status values */
+/* Status values */
+#define STAT_ERROR		0x00
 #define STAT_START		0x08
-#define STAT_RSTART		0x10
+#define STAT_REP_START		0x10
 #define STAT_TXADDR_ACK		0x18
+#define STAT_TXADDR_NAK		0x20
 #define STAT_TXDATA_ACK		0x28
+#define STAT_TXDATA_NAK		0x30
+#define STAT_LOST_ARB_38	0x38
 #define STAT_RXADDR_ACK		0x40
+#define STAT_RXADDR_NAK		0x48
 #define STAT_RXDATA_ACK		0x50
+#define STAT_RXDATA_NAK		0x58
+#define STAT_SLAVE_60		0x60
+#define STAT_LOST_ARB_68	0x68
+#define STAT_SLAVE_70		0x70
+#define STAT_LOST_ARB_78	0x78
+#define STAT_SLAVE_80		0x80
+#define STAT_SLAVE_88		0x88
+#define STAT_GENDATA_ACK	0x90
+#define STAT_GENDATA_NAK	0x98
+#define STAT_SLAVE_A0		0xA0
+#define STAT_SLAVE_A8		0xA8
+#define STAT_LOST_ARB_B0	0xB0
+#define STAT_SLAVE_LOST		0xB8
+#define STAT_SLAVE_NAK		0xC0
+#define STAT_SLAVE_ACK		0xC8
+#define STAT_AD2W_ACK		0xD0
+#define STAT_AD2W_NAK		0xD8
 #define STAT_IDLE		0xF8
 
 /* TWSI_INT values */
+#define TWSI_INT_ST_INT		BIT_ULL(0)
+#define TWSI_INT_TS_INT		BIT_ULL(1)
+#define TWSI_INT_CORE_INT	BIT_ULL(2)
+#define TWSI_INT_ST_EN		BIT_ULL(4)
+#define TWSI_INT_TS_EN		BIT_ULL(5)
 #define TWSI_INT_CORE_EN	BIT_ULL(6)
 #define TWSI_INT_SDA_OVR	BIT_ULL(8)
 #define TWSI_INT_SCL_OVR	BIT_ULL(9)
+#define TWSI_INT_SDA		BIT_ULL(10)
+#define TWSI_INT_SCL		BIT_ULL(11)
+
+#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */
 
 struct octeon_i2c {
 	wait_queue_head_t queue;
 	struct i2c_adapter adap;
 	int irq;
+	int hlc_irq;		/* For cn7890 only */
 	u32 twsi_freq;
 	int sys_freq;
 	void __iomem *twsi_base;
 	struct device *dev;
+	bool hlc_enabled;
+	bool broken_irq_mode;
+	bool broken_irq_check;
+	void (*int_enable)(struct octeon_i2c *);
+	void (*int_disable)(struct octeon_i2c *);
+	void (*hlc_int_enable)(struct octeon_i2c *);
+	void (*hlc_int_disable)(struct octeon_i2c *);
+	atomic_t int_enable_cnt;
+	atomic_t hlc_int_enable_cnt;
 };
 
+static void octeon_i2c_writeq_flush(u64 val, void __iomem *addr)
+{
+	__raw_writeq(val, addr);
+	__raw_readq(addr);	/* wait for write to land */
+}
+
 /**
- * octeon_i2c_write_sw - write an I2C core register
+ * octeon_i2c_reg_write - write an I2C core register
  * @i2c: The struct octeon_i2c
  * @eop_reg: Register selector
  * @data: Value to be written
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
+static void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
 {
 	u64 tmp;
 
@@ -97,8 +155,13 @@ static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
 	} while ((tmp & SW_TWSI_V) != 0);
 }
 
+#define octeon_i2c_ctl_write(i2c, val)					\
+	octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val)
+#define octeon_i2c_data_write(i2c, val)					\
+	octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val)
+
 /**
- * octeon_i2c_read_sw - read lower bits of an I2C core register
+ * octeon_i2c_reg_read - read lower bits of an I2C core register
  * @i2c: The struct octeon_i2c
  * @eop_reg: Register selector
  *
@@ -106,7 +169,7 @@ static void octeon_i2c_write_sw(struct octeon_i2c *i2c, u64 eop_reg, u8 data)
  *
  * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
  */
-static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
+static u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg)
 {
 	u64 tmp;
 
@@ -118,6 +181,24 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
 	return tmp & 0xFF;
 }
 
+#define octeon_i2c_ctl_read(i2c)					\
+	octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL)
+#define octeon_i2c_data_read(i2c)					\
+	octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA)
+#define octeon_i2c_stat_read(i2c)					\
+	octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT)
+
+/**
+ * octeon_i2c_read_int - read the TWSI_INT register
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns the value of the register.
+ */
+static u64 octeon_i2c_read_int(struct octeon_i2c *i2c)
+{
+	return __raw_readq(i2c->twsi_base + TWSI_INT);
+}
+
 /**
  * octeon_i2c_write_int - write the TWSI_INT register
  * @i2c: The struct octeon_i2c
@@ -125,8 +206,7 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
  */
 static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
 {
-	__raw_writeq(data, i2c->twsi_base + TWSI_INT);
-	__raw_readq(i2c->twsi_base + TWSI_INT);
+	octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT);
 }
 
 /**
@@ -149,30 +229,96 @@ static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
 }
 
 /**
- * octeon_i2c_unblock - unblock the bus
+ * octeon_i2c_int_enable78 - enable the CORE interrupt
+ * @i2c: The struct octeon_i2c
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in the
+ * SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable78(struct octeon_i2c *i2c)
+{
+	atomic_inc_return(&i2c->int_enable_cnt);
+	enable_irq(i2c->irq);
+}
+
+static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq)
+{
+	int count;
+
+	/*
+	 * The interrupt can be disabled in two places, but we only
+	 * want to make the disable_irq_nosync() call once, so keep
+	 * track with the atomic variable.
+	 */
+	count = atomic_dec_if_positive(cnt);
+	if (count >= 0)
+		disable_irq_nosync(irq);
+}
+
+/* disable the CORE interrupt */
+static void octeon_i2c_int_disable78(struct octeon_i2c *i2c)
+{
+	__octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq);
+}
+
+/**
+ * octeon_i2c_hlc_int_enable78 - enable the ST interrupt
  * @i2c: The struct octeon_i2c
  *
- * If there was a reset while a device was driving 0 to bus, bus is blocked.
- * We toggle it free manually by some clock cycles and send a stop.
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c)
+{
+	atomic_inc_return(&i2c->hlc_int_enable_cnt);
+	enable_irq(i2c->hlc_irq);
+}
+
+/* disable the ST interrupt */
+static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c)
+{
+	__octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq);
+}
+
+/*
+ * Cleanup low-level state & enable high-level controller.
  */
-static void octeon_i2c_unblock(struct octeon_i2c *i2c)
+static void octeon_i2c_hlc_enable(struct octeon_i2c *i2c)
 {
-	int i;
+	int try = 0;
+	u64 val;
+
+	if (i2c->hlc_enabled)
+		return;
+	i2c->hlc_enabled = true;
+
+	while (1) {
+		val = octeon_i2c_ctl_read(i2c);
+		if (!(val & (TWSI_CTL_STA | TWSI_CTL_STP)))
+			break;
 
-	dev_dbg(i2c->dev, "%s\n", __func__);
+		/* clear IFLG event */
+		if (val & TWSI_CTL_IFLG)
+			octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
+
+		if (try++ > 100) {
+			pr_err("%s: giving up\n", __func__);
+			break;
+		}
 
-	for (i = 0; i < 9; i++) {
-		octeon_i2c_write_int(i2c, 0);
-		udelay(5);
-		octeon_i2c_write_int(i2c, TWSI_INT_SCL_OVR);
-		udelay(5);
+		/* spin until any start/stop has finished */
+		udelay(10);
 	}
-	/* hand-crank a STOP */
-	octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR | TWSI_INT_SCL_OVR);
-	udelay(5);
-	octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR);
-	udelay(5);
-	octeon_i2c_write_int(i2c, 0);
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_CE | TWSI_CTL_AAK | TWSI_CTL_ENAB);
+}
+
+static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
+{
+	if (!i2c->hlc_enabled)
+		return;
+
+	i2c->hlc_enabled = false;
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
 }
 
 /* interrupt service routine */
@@ -180,16 +326,44 @@ static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
 {
 	struct octeon_i2c *i2c = dev_id;
 
-	octeon_i2c_int_disable(i2c);
+	i2c->int_disable(i2c);
+	wake_up(&i2c->queue);
+
+	return IRQ_HANDLED;
+}
+
+/* HLC interrupt service routine */
+static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id)
+{
+	struct octeon_i2c *i2c = dev_id;
+
+	i2c->hlc_int_disable(i2c);
 	wake_up(&i2c->queue);
 
 	return IRQ_HANDLED;
 }
 
+static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c)
+{
+	return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG);
+}
 
-static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
+static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first)
 {
-	return (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_CTL) & TWSI_CTL_IFLG) != 0;
+	if (octeon_i2c_test_iflg(i2c))
+		return true;
+
+	if (*first) {
+		*first = false;
+		return false;
+	}
+
+	/*
+	 * IRQ has signaled an event but IFLG hasn't changed.
+	 * Sleep and retry once.
+	 */
+	usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT);
+	return octeon_i2c_test_iflg(i2c);
 }
 
 /**
@@ -201,64 +375,493 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
 static int octeon_i2c_wait(struct octeon_i2c *i2c)
 {
 	long time_left;
+	bool first = 1;
 
-	octeon_i2c_int_enable(i2c);
-	time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c),
+	/*
+	 * Some chip revisions don't assert the irq in the interrupt
+	 * controller. So we must poll for the IFLG change.
+	 */
+	if (i2c->broken_irq_mode) {
+		u64 end = get_jiffies_64() + i2c->adap.timeout;
+
+		while (!octeon_i2c_test_iflg(i2c) &&
+		       time_before64(get_jiffies_64(), end))
+			usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT);
+
+		return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT;
+	}
+
+	i2c->int_enable(i2c);
+	time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first),
 				       i2c->adap.timeout);
-	octeon_i2c_int_disable(i2c);
-	if (!time_left) {
-		dev_dbg(i2c->dev, "%s: timeout\n", __func__);
-		return -ETIMEDOUT;
+	i2c->int_disable(i2c);
+
+	if (i2c->broken_irq_check && !time_left &&
+	    octeon_i2c_test_iflg(i2c)) {
+		dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n");
+		i2c->broken_irq_mode = true;
+		return 0;
 	}
 
+	if (!time_left)
+		return -ETIMEDOUT;
+
 	return 0;
 }
 
+static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
+{
+	u8 stat = octeon_i2c_stat_read(i2c);
+
+	switch (stat) {
+	/* Everything is fine */
+	case STAT_IDLE:
+	case STAT_AD2W_ACK:
+	case STAT_RXADDR_ACK:
+	case STAT_TXADDR_ACK:
+	case STAT_TXDATA_ACK:
+		return 0;
+
+	/* ACK allowed on pre-terminal bytes only */
+	case STAT_RXDATA_ACK:
+		if (!final_read)
+			return 0;
+		return -EIO;
+
+	/* NAK allowed on terminal byte only */
+	case STAT_RXDATA_NAK:
+		if (final_read)
+			return 0;
+		return -EIO;
+
+	/* Arbitration lost */
+	case STAT_LOST_ARB_38:
+	case STAT_LOST_ARB_68:
+	case STAT_LOST_ARB_78:
+	case STAT_LOST_ARB_B0:
+		return -EAGAIN;
+
+	/* Being addressed as slave, should back off & listen */
+	case STAT_SLAVE_60:
+	case STAT_SLAVE_70:
+	case STAT_GENDATA_ACK:
+	case STAT_GENDATA_NAK:
+		return -EOPNOTSUPP;
+
+	/* Core busy as slave */
+	case STAT_SLAVE_80:
+	case STAT_SLAVE_88:
+	case STAT_SLAVE_A0:
+	case STAT_SLAVE_A8:
+	case STAT_SLAVE_LOST:
+	case STAT_SLAVE_NAK:
+	case STAT_SLAVE_ACK:
+		return -EOPNOTSUPP;
+
+	case STAT_TXDATA_NAK:
+		return -EIO;
+	case STAT_TXADDR_NAK:
+	case STAT_RXADDR_NAK:
+	case STAT_AD2W_NAK:
+		return -ENXIO;
+	default:
+		dev_err(i2c->dev, "unhandled state: %d\n", stat);
+		return -EIO;
+	}
+}
+
+static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c)
+{
+	return (__raw_readq(i2c->twsi_base + SW_TWSI) & SW_TWSI_V) == 0;
+}
+
+static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c, bool *first)
+{
+	/* check if valid bit is cleared */
+	if (octeon_i2c_hlc_test_valid(i2c))
+		return true;
+
+	if (*first) {
+		*first = false;
+		return false;
+	}
+
+	/*
+	 * IRQ has signaled an event but valid bit isn't cleared.
+	 * Sleep and retry once.
+	 */
+	usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT);
+	return octeon_i2c_hlc_test_valid(i2c);
+}
+
+static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c)
+{
+	octeon_i2c_write_int(i2c, TWSI_INT_ST_EN);
+}
+
+static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c)
+{
+	/* clear ST/TS events, listen for neither */
+	octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT);
+}
+
 /**
- * octeon_i2c_start - send START to the bus
+ * octeon_i2c_hlc_wait - wait for an HLC operation to complete
  * @i2c: The struct octeon_i2c
  *
- * Returns 0 on success, otherwise a negative errno.
+ * Returns 0 on success, otherwise -ETIMEDOUT.
  */
-static int octeon_i2c_start(struct octeon_i2c *i2c)
+static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
 {
-	int result;
-	u8 data;
+	bool first = 1;
+	int time_left;
 
-	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
-			    TWSI_CTL_ENAB | TWSI_CTL_STA);
+	/*
+	 * Some cn38xx boards don't assert the irq in the interrupt
+	 * controller. So we must poll for the valid bit change.
+	 */
+	if (i2c->broken_irq_mode) {
+		u64 end = get_jiffies_64() + i2c->adap.timeout;
 
-	result = octeon_i2c_wait(i2c);
-	if (result) {
-		if (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT) == STAT_IDLE) {
+		while (!octeon_i2c_hlc_test_valid(i2c) &&
+		       time_before64(get_jiffies_64(), end))
+			usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT);
+
+		return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT;
+	}
+
+	i2c->hlc_int_enable(i2c);
+	time_left = wait_event_timeout(i2c->queue,
+				       octeon_i2c_hlc_test_ready(i2c, &first),
+				       i2c->adap.timeout);
+	i2c->hlc_int_disable(i2c);
+	if (!time_left)
+		octeon_i2c_hlc_int_clear(i2c);
+
+	if (i2c->broken_irq_check && !time_left &&
+	    octeon_i2c_hlc_test_valid(i2c)) {
+		dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n");
+		i2c->broken_irq_mode = true;
+		return 0;
+	}
+
+	if (!time_left)
+		return -ETIMEDOUT;
+	return 0;
+}
+
+/* high-level-controller pure read of up to 8 bytes */
+static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+	int i, j, ret = 0;
+	u64 cmd;
+
+	octeon_i2c_hlc_enable(i2c);
+	octeon_i2c_hlc_int_clear(i2c);
+
+	cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+	/* SIZE */
+	cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
+	/* A */
+	cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+	if (msgs[0].flags & I2C_M_TEN)
+		cmd |= SW_TWSI_OP_10;
+	else
+		cmd |= SW_TWSI_OP_7;
+
+	octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI);
+	ret = octeon_i2c_hlc_wait(i2c);
+	if (ret)
+		goto err;
+
+	cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
+	if ((cmd & SW_TWSI_R) == 0)
+		return -EAGAIN;
+
+	for (i = 0, j = msgs[0].len - 1; i  < msgs[0].len && i < 4; i++, j--)
+		msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
+
+	if (msgs[0].len > 4) {
+		cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT);
+		for (i = 0; i  < msgs[0].len - 4 && i < 4; i++, j--)
+			msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff;
+	}
+
+err:
+	return ret;
+}
+
+/* high-level-controller pure write of up to 8 bytes */
+static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+	int i, j, ret = 0;
+	u64 cmd;
+
+	octeon_i2c_hlc_enable(i2c);
+	octeon_i2c_hlc_int_clear(i2c);
+
+	cmd = SW_TWSI_V | SW_TWSI_SOVR;
+	/* SIZE */
+	cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
+	/* A */
+	cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+	if (msgs[0].flags & I2C_M_TEN)
+		cmd |= SW_TWSI_OP_10;
+	else
+		cmd |= SW_TWSI_OP_7;
+
+	for (i = 0, j = msgs[0].len - 1; i  < msgs[0].len && i < 4; i++, j--)
+		cmd |= (u64)msgs[0].buf[j] << (8 * i);
+
+	if (msgs[0].len > 4) {
+		u64 ext = 0;
+
+		for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--)
+			ext |= (u64)msgs[0].buf[j] << (8 * i);
+		octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT);
+	}
+
+	octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI);
+	ret = octeon_i2c_hlc_wait(i2c);
+	if (ret)
+		goto err;
+
+	cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
+	if ((cmd & SW_TWSI_R) == 0)
+		return -EAGAIN;
+
+	ret = octeon_i2c_check_status(i2c, false);
+
+err:
+	return ret;
+}
+
+/* high-level-controller composite write+read, msg0=addr, msg1=data */
+static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+	int i, j, ret = 0;
+	u64 cmd;
+
+	octeon_i2c_hlc_enable(i2c);
+
+	cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
+	/* SIZE */
+	cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
+	/* A */
+	cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+	if (msgs[0].flags & I2C_M_TEN)
+		cmd |= SW_TWSI_OP_10_IA;
+	else
+		cmd |= SW_TWSI_OP_7_IA;
+
+	if (msgs[0].len == 2) {
+		u64 ext = 0;
+
+		cmd |= SW_TWSI_EIA;
+		ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+		cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
+		octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT);
+	} else {
+		cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+	}
+
+	octeon_i2c_hlc_int_clear(i2c);
+	octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI);
+
+	ret = octeon_i2c_hlc_wait(i2c);
+	if (ret)
+		goto err;
+
+	cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
+	if ((cmd & SW_TWSI_R) == 0)
+		return -EAGAIN;
+
+	for (i = 0, j = msgs[1].len - 1; i  < msgs[1].len && i < 4; i++, j--)
+		msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
+
+	if (msgs[1].len > 4) {
+		cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT);
+		for (i = 0; i  < msgs[1].len - 4 && i < 4; i++, j--)
+			msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff;
+	}
+
+err:
+	return ret;
+}
+
+/* high-level-controller composite write+write, m[0]len<=2, m[1]len<=8 */
+static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
+{
+	bool set_ext = false;
+	int i, j, ret = 0;
+	u64 cmd, ext = 0;
+
+	octeon_i2c_hlc_enable(i2c);
+
+	cmd = SW_TWSI_V | SW_TWSI_SOVR;
+	/* SIZE */
+	cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
+	/* A */
+	cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
+
+	if (msgs[0].flags & I2C_M_TEN)
+		cmd |= SW_TWSI_OP_10_IA;
+	else
+		cmd |= SW_TWSI_OP_7_IA;
+
+	if (msgs[0].len == 2) {
+		cmd |= SW_TWSI_EIA;
+		ext |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+		set_ext = true;
+		cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
+	} else {
+		cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
+	}
+
+	for (i = 0, j = msgs[1].len - 1; i  < msgs[1].len && i < 4; i++, j--)
+		cmd |= (u64)msgs[1].buf[j] << (8 * i);
+
+	if (msgs[1].len > 4) {
+		for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--)
+			ext |= (u64)msgs[1].buf[j] << (8 * i);
+		set_ext = true;
+	}
+	if (set_ext)
+		octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT);
+
+	octeon_i2c_hlc_int_clear(i2c);
+	octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI);
+
+	ret = octeon_i2c_hlc_wait(i2c);
+	if (ret)
+		goto err;
+
+	cmd = __raw_readq(i2c->twsi_base + SW_TWSI);
+	if ((cmd & SW_TWSI_R) == 0)
+		return -EAGAIN;
+
+	ret = octeon_i2c_check_status(i2c, false);
+
+err:
+	return ret;
+}
+
+/* calculate and set clock divisors */
+static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
+{
+	int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
+	int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
+
+	for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
+		/*
+		 * An mdiv value of less than 2 seems to not work well
+		 * with ds1337 RTCs, so we constrain it to larger values.
+		 */
+		for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
 			/*
-			 * Controller refused to send start flag May
-			 * be a client is holding SDA low - let's try
-			 * to free it.
+			 * For given ndiv and mdiv values check the
+			 * two closest thp values.
 			 */
-			octeon_i2c_unblock(i2c);
-			octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
-					    TWSI_CTL_ENAB | TWSI_CTL_STA);
-			result = octeon_i2c_wait(i2c);
+			tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
+			tclk *= (1 << ndiv_idx);
+			thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
+
+			for (inc = 0; inc <= 1; inc++) {
+				thp_idx = thp_base + inc;
+				if (thp_idx < 5 || thp_idx > 0xff)
+					continue;
+
+				foscl = i2c->sys_freq / (2 * (thp_idx + 1));
+				foscl = foscl / (1 << ndiv_idx);
+				foscl = foscl / (mdiv_idx + 1) / 10;
+				diff = abs(foscl - i2c->twsi_freq);
+				if (diff < delta_hz) {
+					delta_hz = diff;
+					thp = thp_idx;
+					mdiv = mdiv_idx;
+					ndiv = ndiv_idx;
+				}
+			}
 		}
-		if (result)
-			return result;
+	}
+	octeon_i2c_reg_write(i2c, SW_TWSI_OP_TWSI_CLK, thp);
+	octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+}
+
+static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
+{
+	u8 status = 0;
+	int tries;
+
+	/* reset controller */
+	octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+
+	for (tries = 10; tries && status != STAT_IDLE; tries--) {
+		udelay(1);
+		status = octeon_i2c_stat_read(i2c);
+		if (status == STAT_IDLE)
+			break;
 	}
 
-	data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
-	if ((data != STAT_START) && (data != STAT_RSTART)) {
-		dev_err(i2c->dev, "%s: bad status (0x%x)\n", __func__, data);
+	if (status != STAT_IDLE) {
+		dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n",
+			__func__, status);
 		return -EIO;
 	}
 
+	/* toggle twice to force both teardowns */
+	octeon_i2c_hlc_enable(i2c);
+	octeon_i2c_hlc_disable(i2c);
 	return 0;
 }
 
+static int octeon_i2c_recovery(struct octeon_i2c *i2c)
+{
+	int ret;
+
+	ret = i2c_recover_bus(&i2c->adap);
+	if (ret)
+		/* recover failed, try hardware re-init */
+		ret = octeon_i2c_init_lowlevel(i2c);
+	return ret;
+}
+
+/**
+ * octeon_i2c_start - send START to the bus
+ * @i2c: The struct octeon_i2c
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_start(struct octeon_i2c *i2c)
+{
+	int ret;
+	u8 stat;
+
+	octeon_i2c_hlc_disable(i2c);
+
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA);
+	ret = octeon_i2c_wait(i2c);
+	if (ret)
+		goto error;
+
+	stat = octeon_i2c_stat_read(i2c);
+	if (stat == STAT_START || stat == STAT_REP_START)
+		/* START successful, bail out */
+		return 0;
+
+error:
+	/* START failed, try to recover */
+	ret = octeon_i2c_recovery(i2c);
+	return (ret) ? ret : -EAGAIN;
+}
+
 /* send STOP to the bus */
 static void octeon_i2c_stop(struct octeon_i2c *i2c)
 {
-	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
-			    TWSI_CTL_ENAB | TWSI_CTL_STP);
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STP);
 }
 
 /**
@@ -276,31 +879,21 @@ static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
 			    const u8 *data, int length)
 {
 	int i, result;
-	u8 tmp;
-
-	result = octeon_i2c_start(i2c);
-	if (result)
-		return result;
 
-	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, target << 1);
-	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+	octeon_i2c_data_write(i2c, target << 1);
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
 
 	result = octeon_i2c_wait(i2c);
 	if (result)
 		return result;
 
 	for (i = 0; i < length; i++) {
-		tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
-
-		if ((tmp != STAT_TXADDR_ACK) && (tmp != STAT_TXDATA_ACK)) {
-			dev_err(i2c->dev,
-				"%s: bad status before write (0x%x)\n",
-				__func__, tmp);
-			return -EIO;
-		}
+		result = octeon_i2c_check_status(i2c, false);
+		if (result)
+			return result;
 
-		octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, data[i]);
-		octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+		octeon_i2c_data_write(i2c, data[i]);
+		octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
 
 		result = octeon_i2c_wait(i2c);
 		if (result)
@@ -326,53 +919,52 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
 			   u8 *data, u16 *rlength, bool recv_len)
 {
 	int i, result, length = *rlength;
-	u8 tmp;
+	bool final_read = false;
 
-	if (length < 1)
-		return -EINVAL;
+	octeon_i2c_data_write(i2c, (target << 1) | 1);
+	octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
 
-	result = octeon_i2c_start(i2c);
+	result = octeon_i2c_wait(i2c);
 	if (result)
 		return result;
 
-	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, (target << 1) | 1);
-	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
-
-	result = octeon_i2c_wait(i2c);
+	/* address OK ? */
+	result = octeon_i2c_check_status(i2c, false);
 	if (result)
 		return result;
 
 	for (i = 0; i < length; i++) {
-		tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
-
-		if ((tmp != STAT_RXDATA_ACK) && (tmp != STAT_RXADDR_ACK)) {
-			dev_err(i2c->dev,
-				"%s: bad status before read (0x%x)\n",
-				__func__, tmp);
-			return -EIO;
-		}
+		/*
+		 * For the last byte to receive TWSI_CTL_AAK must not be set.
+		 *
+		 * A special case is I2C_M_RECV_LEN where we don't know the
+		 * additional length yet. If recv_len is set we assume we're
+		 * not reading the final byte and therefore need to set
+		 * TWSI_CTL_AAK.
+		 */
+		if ((i + 1 == length) && !(recv_len && i == 0))
+			final_read = true;
 
-		if (i + 1 < length)
-			octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
-					    TWSI_CTL_ENAB | TWSI_CTL_AAK);
+		/* clear iflg to allow next event */
+		if (final_read)
+			octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB);
 		else
-			octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
-					    TWSI_CTL_ENAB);
+			octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_AAK);
 
 		result = octeon_i2c_wait(i2c);
 		if (result)
 			return result;
 
-		data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
+		data[i] = octeon_i2c_data_read(i2c);
 		if (recv_len && i == 0) {
-			if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) {
-				dev_err(i2c->dev,
-					"%s: read len > I2C_SMBUS_BLOCK_MAX %d\n",
-					__func__, data[i]);
+			if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
 				return -EPROTO;
-			}
 			length += data[i];
 		}
+
+		result = octeon_i2c_check_status(i2c, final_read);
+		if (result)
+			return result;
 	}
 	*rlength = length;
 	return 0;
@@ -392,13 +984,41 @@ static int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
 	int i, ret = 0;
 
+	if (num == 1) {
+		if (msgs[0].len > 0 && msgs[0].len <= 8) {
+			if (msgs[0].flags & I2C_M_RD)
+				ret = octeon_i2c_hlc_read(i2c, msgs);
+			else
+				ret = octeon_i2c_hlc_write(i2c, msgs);
+			goto out;
+		}
+	} else if (num == 2) {
+		if ((msgs[0].flags & I2C_M_RD) == 0 &&
+		    (msgs[1].flags & I2C_M_RECV_LEN) == 0 &&
+		    msgs[0].len > 0 && msgs[0].len <= 2 &&
+		    msgs[1].len > 0 && msgs[1].len <= 8 &&
+		    msgs[0].addr == msgs[1].addr) {
+			if (msgs[1].flags & I2C_M_RD)
+				ret = octeon_i2c_hlc_comp_read(i2c, msgs);
+			else
+				ret = octeon_i2c_hlc_comp_write(i2c, msgs);
+			goto out;
+		}
+	}
+
 	for (i = 0; ret == 0 && i < num; i++) {
 		struct i2c_msg *pmsg = &msgs[i];
 
-		dev_dbg(i2c->dev,
-			"Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n",
-			 pmsg->flags & I2C_M_RD ? "read" : "write",
-			 pmsg->len, pmsg->addr, i + 1, num);
+		/* zero-length messages are not supported */
+		if (!pmsg->len) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		ret = octeon_i2c_start(i2c);
+		if (ret)
+			return ret;
+
 		if (pmsg->flags & I2C_M_RD)
 			ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
 					      &pmsg->len, pmsg->flags & I2C_M_RECV_LEN);
@@ -407,102 +1027,105 @@ static int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 					       pmsg->len);
 	}
 	octeon_i2c_stop(i2c);
-
+out:
 	return (ret != 0) ? ret : num;
 }
 
-static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
+static int octeon_i2c_get_scl(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
-	       I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+	u64 state;
+
+	state = octeon_i2c_read_int(i2c);
+	return state & TWSI_INT_SCL;
 }
 
-static const struct i2c_algorithm octeon_i2c_algo = {
-	.master_xfer = octeon_i2c_xfer,
-	.functionality = octeon_i2c_functionality,
-};
+static void octeon_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
 
-static struct i2c_adapter octeon_i2c_ops = {
-	.owner = THIS_MODULE,
-	.name = "OCTEON adapter",
-	.algo = &octeon_i2c_algo,
-	.timeout = HZ / 50,
-};
+	octeon_i2c_write_int(i2c, TWSI_INT_SCL_OVR);
+}
 
-/* calculate and set clock divisors */
-static void octeon_i2c_set_clock(struct octeon_i2c *i2c)
+static int octeon_i2c_get_sda(struct i2c_adapter *adap)
 {
-	int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
-	int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+	u64 state;
 
-	for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
-		/*
-		 * An mdiv value of less than 2 seems to not work well
-		 * with ds1337 RTCs, so we constrain it to larger values.
-		 */
-		for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
-			/*
-			 * For given ndiv and mdiv values check the
-			 * two closest thp values.
-			 */
-			tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
-			tclk *= (1 << ndiv_idx);
-			thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
+	state = octeon_i2c_read_int(i2c);
+	return state & TWSI_INT_SDA;
+}
 
-			for (inc = 0; inc <= 1; inc++) {
-				thp_idx = thp_base + inc;
-				if (thp_idx < 5 || thp_idx > 0xff)
-					continue;
+static void octeon_i2c_prepare_recovery(struct i2c_adapter *adap)
+{
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
 
-				foscl = i2c->sys_freq / (2 * (thp_idx + 1));
-				foscl = foscl / (1 << ndiv_idx);
-				foscl = foscl / (mdiv_idx + 1) / 10;
-				diff = abs(foscl - i2c->twsi_freq);
-				if (diff < delta_hz) {
-					delta_hz = diff;
-					thp = thp_idx;
-					mdiv = mdiv_idx;
-					ndiv = ndiv_idx;
-				}
-			}
-		}
-	}
-	octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
-	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+	/*
+	 * The stop resets the state machine, does not _transmit_ STOP unless
+	 * engine was active.
+	 */
+	octeon_i2c_stop(i2c);
+
+	octeon_i2c_hlc_disable(i2c);
+	octeon_i2c_write_int(i2c, 0);
 }
 
-static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c)
+static void octeon_i2c_unprepare_recovery(struct i2c_adapter *adap)
 {
-	u8 status;
-	int tries;
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
 
-	/* disable high level controller, enable bus access */
-	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+	octeon_i2c_write_int(i2c, 0);
+}
 
-	/* reset controller */
-	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+static struct i2c_bus_recovery_info octeon_i2c_recovery_info = {
+	.recover_bus = i2c_generic_scl_recovery,
+	.get_scl = octeon_i2c_get_scl,
+	.set_scl = octeon_i2c_set_scl,
+	.get_sda = octeon_i2c_get_sda,
+	.prepare_recovery = octeon_i2c_prepare_recovery,
+	.unprepare_recovery = octeon_i2c_unprepare_recovery,
+};
 
-	for (tries = 10; tries; tries--) {
-		udelay(1);
-		status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
-		if (status == STAT_IDLE)
-			return 0;
-	}
-	dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", __func__, status);
-	return -EIO;
+static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+	       I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
 }
 
+static const struct i2c_algorithm octeon_i2c_algo = {
+	.master_xfer = octeon_i2c_xfer,
+	.functionality = octeon_i2c_functionality,
+};
+
+static struct i2c_adapter octeon_i2c_ops = {
+	.owner = THIS_MODULE,
+	.name = "OCTEON adapter",
+	.algo = &octeon_i2c_algo,
+};
+
 static int octeon_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node;
+	int irq, result = 0, hlc_irq = 0;
 	struct resource *res_mem;
 	struct octeon_i2c *i2c;
-	int irq, result = 0;
-
-	/* All adaptors have an irq.  */
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
+	bool cn78xx_style;
+
+	cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi");
+	if (cn78xx_style) {
+		hlc_irq = platform_get_irq(pdev, 0);
+		if (hlc_irq < 0)
+			return hlc_irq;
+
+		irq = platform_get_irq(pdev, 2);
+		if (irq < 0)
+			return irq;
+	} else {
+		/* All adaptors have an irq.  */
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0)
+			return irq;
+	}
 
 	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
 	if (!i2c) {
@@ -537,6 +1160,31 @@ static int octeon_i2c_probe(struct platform_device *pdev)
 
 	i2c->irq = irq;
 
+	if (cn78xx_style) {
+		i2c->hlc_irq = hlc_irq;
+
+		i2c->int_enable = octeon_i2c_int_enable78;
+		i2c->int_disable = octeon_i2c_int_disable78;
+		i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78;
+		i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78;
+
+		irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN);
+		irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN);
+
+		result = devm_request_irq(&pdev->dev, i2c->hlc_irq,
+					  octeon_i2c_hlc_isr78, 0,
+					  DRV_NAME, i2c);
+		if (result < 0) {
+			dev_err(i2c->dev, "failed to attach interrupt\n");
+			goto out;
+		}
+	} else {
+		i2c->int_enable = octeon_i2c_int_enable;
+		i2c->int_disable = octeon_i2c_int_disable;
+		i2c->hlc_int_enable = octeon_i2c_hlc_int_enable;
+		i2c->hlc_int_disable = octeon_i2c_int_disable;
+	}
+
 	result = devm_request_irq(&pdev->dev, i2c->irq,
 				  octeon_i2c_isr, 0, DRV_NAME, i2c);
 	if (result < 0) {
@@ -544,6 +1192,9 @@ static int octeon_i2c_probe(struct platform_device *pdev)
 		goto out;
 	}
 
+	if (OCTEON_IS_MODEL(OCTEON_CN38XX))
+		i2c->broken_irq_check = true;
+
 	result = octeon_i2c_init_lowlevel(i2c);
 	if (result) {
 		dev_err(i2c->dev, "init low level failed\n");
@@ -553,6 +1204,9 @@ static int octeon_i2c_probe(struct platform_device *pdev)
 	octeon_i2c_set_clock(i2c);
 
 	i2c->adap = octeon_i2c_ops;
+	i2c->adap.timeout = msecs_to_jiffies(2);
+	i2c->adap.retries = 5;
+	i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
 	i2c->adap.dev.parent = &pdev->dev;
 	i2c->adap.dev.of_node = node;
 	i2c_set_adapdata(&i2c->adap, i2c);
@@ -580,6 +1234,7 @@ static int octeon_i2c_remove(struct platform_device *pdev)
 
 static const struct of_device_id octeon_i2c_match[] = {
 	{ .compatible = "cavium,octeon-3860-twsi", },
+	{ .compatible = "cavium,octeon-7890-twsi", },
 	{},
 };
 MODULE_DEVICE_TABLE(of, octeon_i2c_match);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 50c035c..ab1279b 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -185,7 +185,6 @@ enum {
 #define OMAP_I2C_IP_V2_INTERRUPTS_MASK	0x6FFF
 
 struct omap_i2c_dev {
-	spinlock_t		lock;		/* IRQ synchronization */
 	struct device		*dev;
 	void __iomem		*base;		/* virtual */
 	int			irq;
@@ -1008,12 +1007,10 @@ static irqreturn_t
 omap_i2c_isr_thread(int this_irq, void *dev_id)
 {
 	struct omap_i2c_dev *omap = dev_id;
-	unsigned long flags;
 	u16 bits;
 	u16 stat;
 	int err = 0, count = 0;
 
-	spin_lock_irqsave(&omap->lock, flags);
 	do {
 		bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
 		stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
@@ -1139,8 +1136,6 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
 	omap_i2c_complete_cmd(omap, err);
 
 out:
-	spin_unlock_irqrestore(&omap->lock, flags);
-
 	return IRQ_HANDLED;
 }
 
@@ -1327,8 +1322,6 @@ omap_i2c_probe(struct platform_device *pdev)
 	omap->dev = &pdev->dev;
 	omap->irq = irq;
 
-	spin_lock_init(&omap->lock);
-
 	platform_set_drvdata(pdev, omap);
 	init_completion(&omap->cmd_complete);
 
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 6abcf69..b0d9dee 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -150,13 +150,11 @@ static int i2c_powermac_master_xfer(	struct i2c_adapter *adap,
 {
 	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adap);
 	int			rc = 0;
-	int			read;
 	int			addrdir;
 
 	if (msgs->flags & I2C_M_TEN)
 		return -EINVAL;
-	read = (msgs->flags & I2C_M_RD) != 0;
-	addrdir = (msgs->addr << 1) | read;
+	addrdir = i2c_8bit_addr_from_msg(msgs);
 
 	rc = pmac_i2c_open(bus, 0);
 	if (rc) {
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index a5eb09c..041050e 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -515,7 +515,7 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
 static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
 			    struct i2c_msg *msg,  int is_dma)
 {
-	u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
+	u16 addr = i2c_8bit_addr_from_msg(msg);
 	int len = 0;
 	int data_len;
 
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 68ecb56..52407f3 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -21,6 +21,8 @@
  */
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -43,6 +45,8 @@
 #define ICSAR	0x1C	/* slave address */
 #define ICMAR	0x20	/* master address */
 #define ICRXTX	0x24	/* data port */
+#define ICDMAER	0x3c	/* DMA enable */
+#define ICFBSCR	0x38	/* first bit setup cycle */
 
 /* ICSCR */
 #define SDBS	(1 << 3)	/* slave data buffer select */
@@ -78,6 +82,16 @@
 #define MDR	(1 << 1)
 #define MAT	(1 << 0)	/* slave addr xfer done */
 
+/* ICDMAER */
+#define RSDMAE	(1 << 3)	/* DMA Slave Received Enable */
+#define TSDMAE	(1 << 2)	/* DMA Slave Transmitted Enable */
+#define RMDMAE	(1 << 1)	/* DMA Master Received Enable */
+#define TMDMAE	(1 << 0)	/* DMA Master Transmitted Enable */
+
+/* ICFBSCR */
+#define TCYC06	0x04		/*  6*Tcyc delay 1st bit between SDA and SCL */
+#define TCYC17	0x0f		/* 17*Tcyc delay 1st bit between SDA and SCL */
+
 
 #define RCAR_BUS_PHASE_START	(MDBS | MIE | ESG)
 #define RCAR_BUS_PHASE_DATA	(MDBS | MIE)
@@ -120,6 +134,12 @@ struct rcar_i2c_priv {
 	u32 flags;
 	enum rcar_i2c_type devtype;
 	struct i2c_client *slave;
+
+	struct resource *res;
+	struct dma_chan *dma_tx;
+	struct dma_chan *dma_rx;
+	struct scatterlist sg;
+	enum dma_data_direction dma_direction;
 };
 
 #define rcar_i2c_priv_to_dev(p)		((p)->adap.dev.parent)
@@ -287,6 +307,118 @@ static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
 /*
  *		interrupt functions
  */
+static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv)
+{
+	struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE
+		? priv->dma_rx : priv->dma_tx;
+
+	/* Disable DMA Master Received/Transmitted */
+	rcar_i2c_write(priv, ICDMAER, 0);
+
+	/* Reset default delay */
+	rcar_i2c_write(priv, ICFBSCR, TCYC06);
+
+	dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg),
+			 priv->msg->len, priv->dma_direction);
+
+	priv->dma_direction = DMA_NONE;
+}
+
+static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv)
+{
+	if (priv->dma_direction == DMA_NONE)
+		return;
+	else if (priv->dma_direction == DMA_FROM_DEVICE)
+		dmaengine_terminate_all(priv->dma_rx);
+	else if (priv->dma_direction == DMA_TO_DEVICE)
+		dmaengine_terminate_all(priv->dma_tx);
+
+	rcar_i2c_dma_unmap(priv);
+}
+
+static void rcar_i2c_dma_callback(void *data)
+{
+	struct rcar_i2c_priv *priv = data;
+
+	priv->pos += sg_dma_len(&priv->sg);
+
+	rcar_i2c_dma_unmap(priv);
+}
+
+static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
+{
+	struct device *dev = rcar_i2c_priv_to_dev(priv);
+	struct i2c_msg *msg = priv->msg;
+	bool read = msg->flags & I2C_M_RD;
+	enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+	struct dma_chan *chan = read ? priv->dma_rx : priv->dma_tx;
+	struct dma_async_tx_descriptor *txdesc;
+	dma_addr_t dma_addr;
+	dma_cookie_t cookie;
+	unsigned char *buf;
+	int len;
+
+	/* Do not use DMA if it's not available or for messages < 8 bytes */
+	if (IS_ERR(chan) || msg->len < 8)
+		return;
+
+	if (read) {
+		/*
+		 * The last two bytes needs to be fetched using PIO in
+		 * order for the STOP phase to work.
+		 */
+		buf = priv->msg->buf;
+		len = priv->msg->len - 2;
+	} else {
+		/*
+		 * First byte in message was sent using PIO.
+		 */
+		buf = priv->msg->buf + 1;
+		len = priv->msg->len - 1;
+	}
+
+	dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
+	if (dma_mapping_error(dev, dma_addr)) {
+		dev_dbg(dev, "dma map failed, using PIO\n");
+		return;
+	}
+
+	sg_dma_len(&priv->sg) = len;
+	sg_dma_address(&priv->sg) = dma_addr;
+
+	priv->dma_direction = dir;
+
+	txdesc = dmaengine_prep_slave_sg(chan, &priv->sg, 1,
+					 read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
+					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!txdesc) {
+		dev_dbg(dev, "dma prep slave sg failed, using PIO\n");
+		rcar_i2c_cleanup_dma(priv);
+		return;
+	}
+
+	txdesc->callback = rcar_i2c_dma_callback;
+	txdesc->callback_param = priv;
+
+	cookie = dmaengine_submit(txdesc);
+	if (dma_submit_error(cookie)) {
+		dev_dbg(dev, "submitting dma failed, using PIO\n");
+		rcar_i2c_cleanup_dma(priv);
+		return;
+	}
+
+	/* Set delay for DMA operations */
+	rcar_i2c_write(priv, ICFBSCR, TCYC17);
+
+	/* Enable DMA Master Received/Transmitted */
+	if (read)
+		rcar_i2c_write(priv, ICDMAER, RMDMAE);
+	else
+		rcar_i2c_write(priv, ICDMAER, TMDMAE);
+
+	dma_async_issue_pending(chan);
+}
+
 static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
 {
 	struct i2c_msg *msg = priv->msg;
@@ -306,6 +438,12 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
 		rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
 		priv->pos++;
 
+		/*
+		 * Try to use DMA to transmit the rest of the data if
+		 * address transfer pashe just finished.
+		 */
+		if (msr & MAT)
+			rcar_i2c_dma(priv);
 	} else {
 		/*
 		 * The last data was pushed to ICRXTX on _PREV_ empty irq.
@@ -340,7 +478,11 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
 		return;
 
 	if (msr & MAT) {
-		/* Address transfer phase finished, but no data at this point. */
+		/*
+		 * Address transfer phase finished, but no data at this point.
+		 * Try to use DMA to receive data.
+		 */
+		rcar_i2c_dma(priv);
 	} else if (priv->pos < msg->len) {
 		/* get received data */
 		msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
@@ -472,6 +614,81 @@ out:
 	return IRQ_HANDLED;
 }
 
+static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev,
+					enum dma_transfer_direction dir,
+					dma_addr_t port_addr)
+{
+	struct dma_chan *chan;
+	struct dma_slave_config cfg;
+	char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
+	int ret;
+
+	chan = dma_request_chan(dev, chan_name);
+	if (IS_ERR(chan)) {
+		ret = PTR_ERR(chan);
+		dev_dbg(dev, "request_channel failed for %s (%d)\n",
+			chan_name, ret);
+		return chan;
+	}
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.direction = dir;
+	if (dir == DMA_MEM_TO_DEV) {
+		cfg.dst_addr = port_addr;
+		cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	} else {
+		cfg.src_addr = port_addr;
+		cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	}
+
+	ret = dmaengine_slave_config(chan, &cfg);
+	if (ret) {
+		dev_dbg(dev, "slave_config failed for %s (%d)\n",
+			chan_name, ret);
+		dma_release_channel(chan);
+		return ERR_PTR(ret);
+	}
+
+	dev_dbg(dev, "got DMA channel for %s\n", chan_name);
+	return chan;
+}
+
+static void rcar_i2c_request_dma(struct rcar_i2c_priv *priv,
+				 struct i2c_msg *msg)
+{
+	struct device *dev = rcar_i2c_priv_to_dev(priv);
+	bool read;
+	struct dma_chan *chan;
+	enum dma_transfer_direction dir;
+
+	read = msg->flags & I2C_M_RD;
+
+	chan = read ? priv->dma_rx : priv->dma_tx;
+	if (PTR_ERR(chan) != -EPROBE_DEFER)
+		return;
+
+	dir = read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+	chan = rcar_i2c_request_dma_chan(dev, dir, priv->res->start + ICRXTX);
+
+	if (read)
+		priv->dma_rx = chan;
+	else
+		priv->dma_tx = chan;
+}
+
+static void rcar_i2c_release_dma(struct rcar_i2c_priv *priv)
+{
+	if (!IS_ERR(priv->dma_tx)) {
+		dma_release_channel(priv->dma_tx);
+		priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
+	}
+
+	if (!IS_ERR(priv->dma_rx)) {
+		dma_release_channel(priv->dma_rx);
+		priv->dma_rx = ERR_PTR(-EPROBE_DEFER);
+	}
+}
+
 static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
 				struct i2c_msg *msgs,
 				int num)
@@ -493,6 +710,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
 			ret = -EOPNOTSUPP;
 			goto out;
 		}
+		rcar_i2c_request_dma(priv, msgs + i);
 	}
 
 	/* init first message */
@@ -504,6 +722,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
 	time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
 				     num * adap->timeout);
 	if (!time_left) {
+		rcar_i2c_cleanup_dma(priv);
 		rcar_i2c_init(priv);
 		ret = -ETIMEDOUT;
 	} else if (priv->flags & ID_NACK) {
@@ -591,7 +810,6 @@ static int rcar_i2c_probe(struct platform_device *pdev)
 {
 	struct rcar_i2c_priv *priv;
 	struct i2c_adapter *adap;
-	struct resource *res;
 	struct device *dev = &pdev->dev;
 	struct i2c_timings i2c_t;
 	int irq, ret;
@@ -606,8 +824,9 @@ static int rcar_i2c_probe(struct platform_device *pdev)
 		return PTR_ERR(priv->clk);
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	priv->io = devm_ioremap_resource(dev, res);
+	priv->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	priv->io = devm_ioremap_resource(dev, priv->res);
 	if (IS_ERR(priv->io))
 		return PTR_ERR(priv->io);
 
@@ -626,6 +845,11 @@ static int rcar_i2c_probe(struct platform_device *pdev)
 
 	i2c_parse_fw_timings(dev, &i2c_t, false);
 
+	/* Init DMA */
+	sg_init_table(&priv->sg, 1);
+	priv->dma_direction = DMA_NONE;
+	priv->dma_rx = priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
+
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 	ret = rcar_i2c_clock_calculate(priv, &i2c_t);
@@ -673,6 +897,7 @@ static int rcar_i2c_remove(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 
 	i2c_del_adapter(&priv->adap);
+	rcar_i2c_release_dma(priv);
 	if (priv->flags & ID_P_PM_BLOCKED)
 		pm_runtime_put(dev);
 	pm_runtime_disable(dev);
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 3dcc5f3..80bed02 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -101,10 +101,7 @@ struct rk3x_i2c {
 	struct notifier_block clk_rate_nb;
 
 	/* Settings */
-	unsigned int scl_frequency;
-	unsigned int scl_rise_ns;
-	unsigned int scl_fall_ns;
-	unsigned int sda_fall_ns;
+	struct i2c_timings t;
 
 	/* Synchronization & notification */
 	spinlock_t lock;
@@ -437,10 +434,7 @@ out:
  * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
- * @scl_rate: Desired SCL rate
- * @scl_rise_ns: How many ns it takes for SCL to rise.
- * @scl_fall_ns: How many ns it takes for SCL to fall.
- * @sda_fall_ns: How many ns it takes for SDA to fall.
+ * @t: Known I2C timing information.
  * @div_low: Divider output for low
  * @div_high: Divider output for high
  *
@@ -448,11 +442,10 @@ out:
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  */
-static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
-			      unsigned long scl_rise_ns,
-			      unsigned long scl_fall_ns,
-			      unsigned long sda_fall_ns,
-			      unsigned long *div_low, unsigned long *div_high)
+static int rk3x_i2c_calc_divs(unsigned long clk_rate,
+			      struct i2c_timings *t,
+			      unsigned long *div_low,
+			      unsigned long *div_high)
 {
 	unsigned long spec_min_low_ns, spec_min_high_ns;
 	unsigned long spec_setup_start, spec_max_data_hold_ns;
@@ -472,12 +465,12 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
 	int ret = 0;
 
 	/* Only support standard-mode and fast-mode */
-	if (WARN_ON(scl_rate > 400000))
-		scl_rate = 400000;
+	if (WARN_ON(t->bus_freq_hz > 400000))
+		t->bus_freq_hz = 400000;
 
 	/* prevent scl_rate_khz from becoming 0 */
-	if (WARN_ON(scl_rate < 1000))
-		scl_rate = 1000;
+	if (WARN_ON(t->bus_freq_hz < 1000))
+		t->bus_freq_hz = 1000;
 
 	/*
 	 * min_low_ns:  The minimum number of ns we need to hold low to
@@ -491,7 +484,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
 	 *	 This is because the i2c host on Rockchip holds the data line
 	 *	 for half the low time.
 	 */
-	if (scl_rate <= 100000) {
+	if (t->bus_freq_hz <= 100000) {
 		/* Standard-mode */
 		spec_min_low_ns = 4700;
 		spec_setup_start = 4700;
@@ -506,7 +499,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
 		spec_max_data_hold_ns = 900;
 		data_hold_buffer_ns = 50;
 	}
-	min_high_ns = scl_rise_ns + spec_min_high_ns;
+	min_high_ns = t->scl_rise_ns + spec_min_high_ns;
 
 	/*
 	 * Timings for repeated start:
@@ -517,18 +510,18 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
 	 * we meet tSU;STA and tHD;STA times.
 	 */
 	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((scl_rise_ns + spec_setup_start) * 1000, 875));
+		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
 	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((scl_rise_ns + spec_setup_start +
-			      sda_fall_ns + spec_min_high_ns), 2));
+		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
+			      t->sda_fall_ns + spec_min_high_ns), 2));
 
-	min_low_ns = scl_fall_ns + spec_min_low_ns;
+	min_low_ns = t->scl_fall_ns + spec_min_low_ns;
 	max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
 	min_total_ns = min_low_ns + min_high_ns;
 
 	/* Adjust to avoid overflow */
 	clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
-	scl_rate_khz = scl_rate / 1000;
+	scl_rate_khz = t->bus_freq_hz / 1000;
 
 	/*
 	 * We need the total div to be >= this number
@@ -616,14 +609,13 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
 
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
+	struct i2c_timings *t = &i2c->t;
 	unsigned long div_low, div_high;
 	u64 t_low_ns, t_high_ns;
 	int ret;
 
-	ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, i2c->scl_rise_ns,
-				 i2c->scl_fall_ns, i2c->sda_fall_ns,
-				 &div_low, &div_high);
-	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency);
+	ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high);
+	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
 	clk_enable(i2c->clk);
 	i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV);
@@ -634,7 +626,7 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 	dev_dbg(i2c->dev,
 		"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
 		clk_rate / 1000,
-		1000000000 / i2c->scl_frequency,
+		1000000000 / t->bus_freq_hz,
 		t_low_ns, t_high_ns);
 }
 
@@ -664,9 +656,7 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency,
-				       i2c->scl_rise_ns, i2c->scl_fall_ns,
-				       i2c->sda_fall_ns,
+		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t,
 				       &div_low, &div_high) != 0)
 			return NOTIFY_STOP;
 
@@ -880,37 +870,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 	match = of_match_node(rk3x_i2c_match, np);
 	i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data;
 
-	if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-				 &i2c->scl_frequency)) {
-		dev_info(&pdev->dev, "using default SCL frequency: %d\n",
-			 DEFAULT_SCL_RATE);
-		i2c->scl_frequency = DEFAULT_SCL_RATE;
-	}
-
-	if (i2c->scl_frequency == 0 || i2c->scl_frequency > 400 * 1000) {
-		dev_warn(&pdev->dev, "invalid SCL frequency specified.\n");
-		dev_warn(&pdev->dev, "using default SCL frequency: %d\n",
-			 DEFAULT_SCL_RATE);
-		i2c->scl_frequency = DEFAULT_SCL_RATE;
-	}
-
-	/*
-	 * Read rise and fall time from device tree. If not available use
-	 * the default maximum timing from the specification.
-	 */
-	if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-rising-time-ns",
-				 &i2c->scl_rise_ns)) {
-		if (i2c->scl_frequency <= 100000)
-			i2c->scl_rise_ns = 1000;
-		else
-			i2c->scl_rise_ns = 300;
-	}
-	if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-falling-time-ns",
-				 &i2c->scl_fall_ns))
-		i2c->scl_fall_ns = 300;
-	if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns",
-				 &i2c->sda_fall_ns))
-		i2c->sda_fall_ns = i2c->scl_fall_ns;
+	/* use common interface to get I2C timing properties */
+	i2c_parse_fw_timings(&pdev->dev, &i2c->t, true);
 
 	strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
 	i2c->adap.owner = THIS_MODULE;
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 362a6de..38dc1ca 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -163,15 +163,14 @@ static const struct of_device_id s3c24xx_i2c_match[] = {
 MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
 #endif
 
-/* s3c24xx_get_device_quirks
- *
+/*
  * Get controller type either from device tree or platform device variant.
-*/
-
+ */
 static inline kernel_ulong_t s3c24xx_get_device_quirks(struct platform_device *pdev)
 {
 	if (pdev->dev.of_node) {
 		const struct of_device_id *match;
+
 		match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node);
 		return (kernel_ulong_t)match->data;
 	}
@@ -179,12 +178,10 @@ static inline kernel_ulong_t s3c24xx_get_device_quirks(struct platform_device *p
 	return platform_get_device_id(pdev)->driver_data;
 }
 
-/* s3c24xx_i2c_master_complete
- *
- * complete the message and wake up the caller, using the given return code,
+/*
+ * Complete the message and wake up the caller, using the given return code,
  * or zero to mean ok.
-*/
-
+ */
 static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
 {
 	dev_dbg(i2c->dev, "master_complete %d\n", ret);
@@ -217,7 +214,6 @@ static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
 }
 
 /* irq enable/disable functions */
-
 static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
 {
 	unsigned long tmp;
@@ -251,11 +247,9 @@ static bool is_ack(struct s3c24xx_i2c *i2c)
 	return false;
 }
 
-/* s3c24xx_i2c_message_start
- *
+/*
  * put the start of a message onto the bus
-*/
-
+ */
 static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
 				      struct i2c_msg *msg)
 {
@@ -284,9 +278,10 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
 	dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
 	writeb(addr, i2c->regs + S3C2410_IICDS);
 
-	/* delay here to ensure the data byte has gotten onto the bus
-	 * before the transaction is started */
-
+	/*
+	 * delay here to ensure the data byte has gotten onto the bus
+	 * before the transaction is started
+	 */
 	ndelay(i2c->tx_setup);
 
 	dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
@@ -361,50 +356,46 @@ static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
 	s3c24xx_i2c_disable_irq(i2c);
 }
 
-/* helper functions to determine the current state in the set of
- * messages we are sending */
+/*
+ * helper functions to determine the current state in the set of
+ * messages we are sending
+ */
 
-/* is_lastmsg()
- *
+/*
  * returns TRUE if the current message is the last in the set
-*/
-
+ */
 static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
 {
 	return i2c->msg_idx >= (i2c->msg_num - 1);
 }
 
-/* is_msglast
- *
+/*
  * returns TRUE if we this is the last byte in the current message
-*/
-
+ */
 static inline int is_msglast(struct s3c24xx_i2c *i2c)
 {
-	/* msg->len is always 1 for the first byte of smbus block read.
+	/*
+	 * msg->len is always 1 for the first byte of smbus block read.
 	 * Actual length will be read from slave. More bytes will be
-	 * read according to the length then. */
+	 * read according to the length then.
+	 */
 	if (i2c->msg->flags & I2C_M_RECV_LEN && i2c->msg->len == 1)
 		return 0;
 
 	return i2c->msg_ptr == i2c->msg->len-1;
 }
 
-/* is_msgend
- *
+/*
  * returns TRUE if we reached the end of the current message
-*/
-
+ */
 static inline int is_msgend(struct s3c24xx_i2c *i2c)
 {
 	return i2c->msg_ptr >= i2c->msg->len;
 }
 
-/* i2c_s3c_irq_nextbyte
- *
+/*
  * process an interrupt and work out what to do
  */
-
 static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 {
 	unsigned long tmp;
@@ -423,14 +414,13 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 		goto out_ack;
 
 	case STATE_START:
-		/* last thing we did was send a start condition on the
+		/*
+		 * last thing we did was send a start condition on the
 		 * bus, or started a new i2c message
 		 */
-
 		if (iicstat & S3C2410_IICSTAT_LASTBIT &&
 		    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
 			/* ack was not received... */
-
 			dev_dbg(i2c->dev, "ack was not received\n");
 			s3c24xx_i2c_stop(i2c, -ENXIO);
 			goto out_ack;
@@ -441,9 +431,10 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 		else
 			i2c->state = STATE_WRITE;
 
-		/* terminate the transfer if there is nothing to do
-		 * as this is used by the i2c probe to find devices. */
-
+		/*
+		 * Terminate the transfer if there is nothing to do
+		 * as this is used by the i2c probe to find devices.
+		 */
 		if (is_lastmsg(i2c) && i2c->msg->len == 0) {
 			s3c24xx_i2c_stop(i2c, 0);
 			goto out_ack;
@@ -452,14 +443,16 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 		if (i2c->state == STATE_READ)
 			goto prepare_read;
 
-		/* fall through to the write state, as we will need to
-		 * send a byte as well */
+		/*
+		 * fall through to the write state, as we will need to
+		 * send a byte as well
+		 */
 
 	case STATE_WRITE:
-		/* we are writing data to the device... check for the
+		/*
+		 * we are writing data to the device... check for the
 		 * end of the message, and if so, work out what to do
 		 */
-
 		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
 			if (iicstat & S3C2410_IICSTAT_LASTBIT) {
 				dev_dbg(i2c->dev, "WRITE: No Ack\n");
@@ -475,12 +468,13 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 			byte = i2c->msg->buf[i2c->msg_ptr++];
 			writeb(byte, i2c->regs + S3C2410_IICDS);
 
-			/* delay after writing the byte to allow the
+			/*
+			 * delay after writing the byte to allow the
 			 * data setup time on the bus, as writing the
 			 * data to the register causes the first bit
 			 * to appear on SDA, and SCL will change as
-			 * soon as the interrupt is acknowledged */
-
+			 * soon as the interrupt is acknowledged
+			 */
 			ndelay(i2c->tx_setup);
 
 		} else if (!is_lastmsg(i2c)) {
@@ -496,10 +490,11 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 			if (i2c->msg->flags & I2C_M_NOSTART) {
 
 				if (i2c->msg->flags & I2C_M_RD) {
-					/* cannot do this, the controller
+					/*
+					 * cannot do this, the controller
 					 * forces us to send a new START
-					 * when we change direction */
-
+					 * when we change direction
+					 */
 					s3c24xx_i2c_stop(i2c, -EINVAL);
 				}
 
@@ -512,17 +507,16 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 
 		} else {
 			/* send stop */
-
 			s3c24xx_i2c_stop(i2c, 0);
 		}
 		break;
 
 	case STATE_READ:
-		/* we have a byte of data in the data register, do
+		/*
+		 * we have a byte of data in the data register, do
 		 * something with it, and then work out whether we are
 		 * going to do any more read/write
 		 */
-
 		byte = readb(i2c->regs + S3C2410_IICDS);
 		i2c->msg->buf[i2c->msg_ptr++] = byte;
 
@@ -537,9 +531,10 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 				s3c24xx_i2c_disable_ack(i2c);
 
 		} else if (is_msgend(i2c)) {
-			/* ok, we've read the entire buffer, see if there
-			 * is anything else we need to do */
-
+			/*
+			 * ok, we've read the entire buffer, see if there
+			 * is anything else we need to do
+			 */
 			if (is_lastmsg(i2c)) {
 				/* last message, send stop and complete */
 				dev_dbg(i2c->dev, "READ: Send Stop\n");
@@ -568,11 +563,9 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 	return ret;
 }
 
-/* s3c24xx_i2c_irq
- *
+/*
  * top level IRQ servicing routine
-*/
-
+ */
 static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
 {
 	struct s3c24xx_i2c *i2c = dev_id;
@@ -595,9 +588,10 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
 		goto out;
 	}
 
-	/* pretty much this leaves us with the fact that we've
-	 * transmitted or received whatever byte we last sent */
-
+	/*
+	 * pretty much this leaves us with the fact that we've
+	 * transmitted or received whatever byte we last sent
+	 */
 	i2c_s3c_irq_nextbyte(i2c, status);
 
  out:
@@ -630,11 +624,9 @@ static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c)
 }
 
 
-/* s3c24xx_i2c_set_master
- *
+/*
  * get the i2c bus for a master transaction
-*/
-
+ */
 static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
 {
 	unsigned long iicstat;
@@ -652,11 +644,9 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
 	return -ETIMEDOUT;
 }
 
-/* s3c24xx_i2c_wait_idle
- *
+/*
  * wait for the i2c bus to become idle.
-*/
-
+ */
 static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
 {
 	unsigned long iicstat;
@@ -706,11 +696,9 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
 		dev_warn(i2c->dev, "timeout waiting for bus idle\n");
 }
 
-/* s3c24xx_i2c_doxfer
- *
+/*
  * this starts an i2c transfer
-*/
-
+ */
 static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
 			      struct i2c_msg *msgs, int num)
 {
@@ -749,9 +737,10 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
 
 	ret = i2c->msg_idx;
 
-	/* having these next two as dev_err() makes life very
-	 * noisy when doing an i2cdetect */
-
+	/*
+	 * Having these next two as dev_err() makes life very
+	 * noisy when doing an i2cdetect
+	 */
 	if (timeout == 0)
 		dev_dbg(i2c->dev, "timeout\n");
 	else if (ret != num)
@@ -771,12 +760,10 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
 	return ret;
 }
 
-/* s3c24xx_i2c_xfer
- *
+/*
  * first port of call from the i2c bus code when an message needs
  * transferring across the i2c bus.
-*/
-
+ */
 static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
 			struct i2c_msg *msgs, int num)
 {
@@ -814,17 +801,14 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
 }
 
 /* i2c bus registration info */
-
 static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
 	.master_xfer		= s3c24xx_i2c_xfer,
 	.functionality		= s3c24xx_i2c_func,
 };
 
-/* s3c24xx_i2c_calcdivisor
- *
+/*
  * return the divisor settings for a given frequency
-*/
-
+ */
 static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
 				   unsigned int *div1, unsigned int *divs)
 {
@@ -850,13 +834,11 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
 	return clkin / (calc_divs * calc_div1);
 }
 
-/* s3c24xx_i2c_clockrate
- *
+/*
  * work out a divisor for the user requested frequency setting,
  * either by the requested frequency, or scanning the acceptable
  * range of frequencies until something is found
-*/
-
+ */
 static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
 {
 	struct s3c2410_platform_i2c *pdata = i2c->pdata;
@@ -944,7 +926,7 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
 		i2c_unlock_adapter(&i2c->adap);
 
 		if (ret < 0)
-			dev_err(i2c->dev, "cannot find frequency\n");
+			dev_err(i2c->dev, "cannot find frequency (%d)\n", ret);
 		else
 			dev_info(i2c->dev, "setting freq %d\n", got);
 	}
@@ -995,7 +977,8 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
 
 		ret = gpio_request(gpio, "i2c-bus");
 		if (ret) {
-			dev_err(i2c->dev, "gpio [%d] request failed\n", gpio);
+			dev_err(i2c->dev, "gpio [%d] request failed (%d)\n",
+				gpio, ret);
 			goto free_gpio;
 		}
 	}
@@ -1028,11 +1011,9 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
 }
 #endif
 
-/* s3c24xx_i2c_init
- *
+/*
  * initialise the controller, set the IO lines and frequency
-*/
-
+ */
 static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
 {
 	struct s3c2410_platform_i2c *pdata;
@@ -1068,11 +1049,9 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
 }
 
 #ifdef CONFIG_OF
-/* s3c24xx_i2c_parse_dt
- *
+/*
  * Parse the device tree node and retreive the platform data.
-*/
-
+ */
 static void
 s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
 {
@@ -1105,17 +1084,9 @@ s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
 }
 #else
 static void
-s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
-{
-	return;
-}
+s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) { }
 #endif
 
-/* s3c24xx_i2c_probe
- *
- * called by the bus driver when a suitable device is found
-*/
-
 static int s3c24xx_i2c_probe(struct platform_device *pdev)
 {
 	struct s3c24xx_i2c *i2c;
@@ -1156,7 +1127,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 	init_waitqueue_head(&i2c->wait);
 
 	/* find the clock and enable it */
-
 	i2c->dev = &pdev->dev;
 	i2c->clk = devm_clk_get(&pdev->dev, "i2c");
 	if (IS_ERR(i2c->clk)) {
@@ -1166,9 +1136,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 
 	dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
 
-
 	/* map the registers */
-
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	i2c->regs = devm_ioremap_resource(&pdev->dev, res);
 
@@ -1179,33 +1147,35 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 		i2c->regs, res);
 
 	/* setup info block for the i2c core */
-
 	i2c->adap.algo_data = i2c;
 	i2c->adap.dev.parent = &pdev->dev;
-
 	i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);
 
 	/* inititalise the i2c gpio lines */
-
-	if (i2c->pdata->cfg_gpio) {
+	if (i2c->pdata->cfg_gpio)
 		i2c->pdata->cfg_gpio(to_platform_device(i2c->dev));
-	} else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) {
+	else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c))
 		return -EINVAL;
-	}
 
 	/* initialise the i2c controller */
+	ret = clk_prepare_enable(i2c->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "I2C clock enable failed\n");
+		return ret;
+	}
 
-	clk_prepare_enable(i2c->clk);
 	ret = s3c24xx_i2c_init(i2c);
 	clk_disable(i2c->clk);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "I2C controller init failed\n");
+		clk_unprepare(i2c->clk);
 		return ret;
 	}
-	/* find the IRQ for this unit (note, this relies on the init call to
+
+	/*
+	 * find the IRQ for this unit (note, this relies on the init call to
 	 * ensure no current IRQs pending
 	 */
-
 	if (!(i2c->quirks & QUIRK_POLL)) {
 		i2c->irq = ret = platform_get_irq(pdev, 0);
 		if (ret <= 0) {
@@ -1214,9 +1184,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 			return ret;
 		}
 
-	ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
-				dev_name(&pdev->dev), i2c);
-
+		ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq,
+				       0, dev_name(&pdev->dev), i2c);
 		if (ret != 0) {
 			dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
 			clk_unprepare(i2c->clk);
@@ -1231,12 +1200,12 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	/* Note, previous versions of the driver used i2c_add_adapter()
+	/*
+	 * Note, previous versions of the driver used i2c_add_adapter()
 	 * to add the bus at any number. We now pass the bus number via
 	 * the platform data, so if unset it will now default to always
 	 * being bus 0.
 	 */
-
 	i2c->adap.nr = i2c->pdata->bus_num;
 	i2c->adap.dev.of_node = pdev->dev.of_node;
 
@@ -1257,11 +1226,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 	return 0;
 }
 
-/* s3c24xx_i2c_remove
- *
- * called when device is removed from the bus
-*/
-
 static int s3c24xx_i2c_remove(struct platform_device *pdev)
 {
 	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
@@ -1316,14 +1280,8 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
 
 #ifdef CONFIG_PM
 static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
-#ifdef CONFIG_PM_SLEEP
-	.suspend_noirq = s3c24xx_i2c_suspend_noirq,
-	.resume_noirq = s3c24xx_i2c_resume_noirq,
-	.freeze_noirq = s3c24xx_i2c_suspend_noirq,
-	.thaw_noirq = s3c24xx_i2c_resume_noirq,
-	.poweroff_noirq = s3c24xx_i2c_suspend_noirq,
-	.restore_noirq = s3c24xx_i2c_resume_noirq,
-#endif
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(s3c24xx_i2c_suspend_noirq,
+				      s3c24xx_i2c_resume_noirq)
 };
 
 #define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
@@ -1331,8 +1289,6 @@ static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
 #define S3C24XX_DEV_PM_OPS NULL
 #endif
 
-/* device driver for platform bus bits */
-
 static struct platform_driver s3c24xx_i2c_driver = {
 	.probe		= s3c24xx_i2c_probe,
 	.remove		= s3c24xx_i2c_remove,
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 7d2bd3e..6fb3e26 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -398,8 +398,7 @@ static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
 {
 	switch (pd->pos) {
 	case -1:
-		*buf = (pd->msg->addr & 0x7f) << 1;
-		*buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
+		*buf = i2c_8bit_addr_from_msg(pd->msg);
 		break;
 	default:
 		*buf = pd->msg->buf[pd->pos];
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 13e51ef..792a42b 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -190,9 +190,7 @@ static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
 
 	writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
 
-	addr = msg->addr << 1;	/* Generate address */
-	if (msg->flags & I2C_M_RD)
-		addr |= 1;
+	addr = i2c_8bit_addr_from_msg(msg);
 
 	/* Reverse direction bit */
 	if (msg->flags & I2C_M_REV_DIR_ADDR)
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 6ee7715..944ec42 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -337,10 +337,42 @@ static void st_i2c_hw_config(struct st_i2c_dev *i2c_dev)
 	writel_relaxed(val, i2c_dev->base + SSC_NOISE_SUPP_WIDTH_DATAOUT);
 }
 
+static int st_i2c_recover_bus(struct i2c_adapter *i2c_adap)
+{
+	struct st_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
+	u32 ctl;
+
+	dev_dbg(i2c_dev->dev, "Trying to recover bus\n");
+
+	/*
+	 * SSP IP is dual role SPI/I2C to generate 9 clock pulses
+	 * we switch to SPI node, 9 bit words and write a 0. This
+	 * has been validate with a oscilloscope and is easier
+	 * than switching to GPIO mode.
+	 */
+
+	/* Disable interrupts */
+	writel_relaxed(0, i2c_dev->base + SSC_IEN);
+
+	st_i2c_hw_config(i2c_dev);
+
+	ctl = SSC_CTL_EN | SSC_CTL_MS |	SSC_CTL_EN_RX_FIFO | SSC_CTL_EN_TX_FIFO;
+	st_i2c_set_bits(i2c_dev->base + SSC_CTL, ctl);
+
+	st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM);
+	usleep_range(8000, 10000);
+
+	writel_relaxed(0, i2c_dev->base + SSC_TBUF);
+	usleep_range(2000, 4000);
+	st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM);
+
+	return 0;
+}
+
 static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
 {
 	u32 sta;
-	int i;
+	int i, ret;
 
 	for (i = 0; i < 10; i++) {
 		sta = readl_relaxed(i2c_dev->base + SSC_STA);
@@ -352,6 +384,12 @@ static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
 
 	dev_err(i2c_dev->dev, "bus not free (status = 0x%08x)\n", sta);
 
+	ret = i2c_recover_bus(&i2c_dev->adap);
+	if (ret) {
+		dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret);
+		return ret;
+	}
+
 	return -EBUSY;
 }
 
@@ -614,8 +652,7 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg,
 	unsigned long timeout;
 	int ret;
 
-	c->addr		= (u8)(msg->addr << 1);
-	c->addr		|= (msg->flags & I2C_M_RD);
+	c->addr		= i2c_8bit_addr_from_msg(msg);
 	c->buf		= msg->buf;
 	c->count	= msg->len;
 	c->xfered	= 0;
@@ -744,6 +781,10 @@ static struct i2c_algorithm st_i2c_algo = {
 	.functionality = st_i2c_func,
 };
 
+static struct i2c_bus_recovery_info st_i2c_recovery_info = {
+	.recover_bus = st_i2c_recover_bus,
+};
+
 static int st_i2c_of_get_deglitch(struct device_node *np,
 		struct st_i2c_dev *i2c_dev)
 {
@@ -826,6 +867,7 @@ static int st_i2c_probe(struct platform_device *pdev)
 	adap->timeout = 2 * HZ;
 	adap->retries = 0;
 	adap->algo = &st_i2c_algo;
+	adap->bus_recovery_info = &st_i2c_recovery_info;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 929185a..b126dba 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -38,6 +38,7 @@
 #define I2C_CNFG_DEBOUNCE_CNT_SHIFT		12
 #define I2C_CNFG_PACKET_MODE_EN			(1<<10)
 #define I2C_CNFG_NEW_MASTER_FSM			(1<<11)
+#define I2C_CNFG_MULTI_MASTER_MODE		(1<<17)
 #define I2C_STATUS				0x01C
 #define I2C_SL_CNFG				0x020
 #define I2C_SL_CNFG_NACK			(1<<1)
@@ -106,6 +107,9 @@
 #define I2C_SLV_CONFIG_LOAD			(1 << 1)
 #define I2C_TIMEOUT_CONFIG_LOAD			(1 << 2)
 
+#define I2C_CLKEN_OVERRIDE			0x090
+#define I2C_MST_CORE_CLKEN_OVR			(1 << 0)
+
 /*
  * msg_end_type: The bus control which need to be send at end of transfer.
  * @MSG_END_STOP: Send stop pulse at end of transfer.
@@ -143,6 +147,8 @@ struct tegra_i2c_hw_feature {
 	int clk_divisor_hs_mode;
 	int clk_divisor_std_fast_mode;
 	u16 clk_divisor_fast_plus_mode;
+	bool has_multi_master_mode;
+	bool has_slcg_override_reg;
 };
 
 /**
@@ -184,6 +190,7 @@ struct tegra_i2c_dev {
 	u32 bus_clk_rate;
 	u16 clk_divisor_non_hs_mode;
 	bool is_suspended;
+	bool is_multimaster_mode;
 };
 
 static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg)
@@ -438,6 +445,10 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 
 	val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
 		(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
+
+	if (i2c_dev->hw->has_multi_master_mode)
+		val |= I2C_CNFG_MULTI_MASTER_MODE;
+
 	i2c_writel(i2c_dev, val, I2C_CNFG);
 	i2c_writel(i2c_dev, 0, I2C_INT_MASK);
 
@@ -463,25 +474,29 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
 	if (tegra_i2c_flush_fifos(i2c_dev))
 		err = -ETIMEDOUT;
 
+	if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
+		i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
+
 	if (i2c_dev->hw->has_config_load_reg) {
 		i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
 		while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) {
 			if (time_after(jiffies, timeout)) {
 				dev_warn(i2c_dev->dev,
 					"timeout waiting for config load\n");
-				return -ETIMEDOUT;
+				err = -ETIMEDOUT;
+				goto err;
 			}
 			msleep(1);
 		}
 	}
 
-	tegra_i2c_clock_disable(i2c_dev);
-
 	if (i2c_dev->irq_disabled) {
 		i2c_dev->irq_disabled = 0;
 		enable_irq(i2c_dev->irq);
 	}
 
+err:
+	tegra_i2c_clock_disable(i2c_dev);
 	return err;
 }
 
@@ -688,6 +703,20 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap)
 	return ret;
 }
 
+static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
+{
+	struct device_node *np = i2c_dev->dev->of_node;
+	int ret;
+
+	ret = of_property_read_u32(np, "clock-frequency",
+			&i2c_dev->bus_clk_rate);
+	if (ret)
+		i2c_dev->bus_clk_rate = 100000; /* default clock rate */
+
+	i2c_dev->is_multimaster_mode = of_property_read_bool(np,
+			"multi-master");
+}
+
 static const struct i2c_algorithm tegra_i2c_algo = {
 	.master_xfer	= tegra_i2c_xfer,
 	.functionality	= tegra_i2c_func,
@@ -707,6 +736,8 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
 	.clk_divisor_std_fast_mode = 0,
 	.clk_divisor_fast_plus_mode = 0,
 	.has_config_load_reg = false,
+	.has_multi_master_mode = false,
+	.has_slcg_override_reg = false,
 };
 
 static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
@@ -717,6 +748,8 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
 	.clk_divisor_std_fast_mode = 0,
 	.clk_divisor_fast_plus_mode = 0,
 	.has_config_load_reg = false,
+	.has_multi_master_mode = false,
+	.has_slcg_override_reg = false,
 };
 
 static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
@@ -727,6 +760,8 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
 	.clk_divisor_std_fast_mode = 0x19,
 	.clk_divisor_fast_plus_mode = 0x10,
 	.has_config_load_reg = false,
+	.has_multi_master_mode = false,
+	.has_slcg_override_reg = false,
 };
 
 static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
@@ -737,10 +772,25 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
 	.clk_divisor_std_fast_mode = 0x19,
 	.clk_divisor_fast_plus_mode = 0x10,
 	.has_config_load_reg = true,
+	.has_multi_master_mode = false,
+	.has_slcg_override_reg = true,
+};
+
+static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
+	.has_continue_xfer_support = true,
+	.has_per_pkt_xfer_complete_irq = true,
+	.has_single_clk_source = true,
+	.clk_divisor_hs_mode = 1,
+	.clk_divisor_std_fast_mode = 0x19,
+	.clk_divisor_fast_plus_mode = 0x10,
+	.has_config_load_reg = true,
+	.has_multi_master_mode = true,
+	.has_slcg_override_reg = true,
 };
 
 /* Match table for of_platform binding */
 static const struct of_device_id tegra_i2c_of_match[] = {
+	{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
 	{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
 	{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
 	{ .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
@@ -797,10 +847,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 		return PTR_ERR(i2c_dev->rst);
 	}
 
-	ret = of_property_read_u32(i2c_dev->dev->of_node, "clock-frequency",
-					&i2c_dev->bus_clk_rate);
-	if (ret)
-		i2c_dev->bus_clk_rate = 100000; /* default clock rate */
+	tegra_i2c_parse_dt(i2c_dev);
 
 	i2c_dev->hw = &tegra20_i2c_hw;
 
@@ -853,17 +900,26 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 		goto unprepare_fast_clk;
 	}
 
+	if (i2c_dev->is_multimaster_mode) {
+		ret = clk_enable(i2c_dev->div_clk);
+		if (ret < 0) {
+			dev_err(i2c_dev->dev, "div_clk enable failed %d\n",
+				ret);
+			goto unprepare_div_clk;
+		}
+	}
+
 	ret = tegra_i2c_init(i2c_dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to initialize i2c controller");
-		goto unprepare_div_clk;
+		goto disable_div_clk;
 	}
 
 	ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
 			tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
-		goto unprepare_div_clk;
+		goto disable_div_clk;
 	}
 
 	i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
@@ -878,11 +934,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 	ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to add I2C adapter\n");
-		goto unprepare_div_clk;
+		goto disable_div_clk;
 	}
 
 	return 0;
 
+disable_div_clk:
+	if (i2c_dev->is_multimaster_mode)
+		clk_disable(i2c_dev->div_clk);
+
 unprepare_div_clk:
 	clk_unprepare(i2c_dev->div_clk);
 
@@ -898,6 +958,9 @@ static int tegra_i2c_remove(struct platform_device *pdev)
 	struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
 	i2c_del_adapter(&i2c_dev->adapter);
 
+	if (i2c_dev->is_multimaster_mode)
+		clk_disable(i2c_dev->div_clk);
+
 	clk_unprepare(i2c_dev->div_clk);
 	if (!i2c_dev->hw->has_single_clk_source)
 		clk_unprepare(i2c_dev->fast_clk);
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index 213ba55..aeead0d 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -524,7 +524,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(dev, "failed to get IRQ number");
+		dev_err(dev, "failed to get IRQ number\n");
 		return irq;
 	}
 
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
index 89eaa8a..475a5eb 100644
--- a/drivers/i2c/busses/i2c-uniphier.c
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -381,7 +381,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(dev, "failed to get IRQ number");
+		dev_err(dev, "failed to get IRQ number\n");
 		return irq;
 	}
 
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
index e33022e..6e5fac6 100644
--- a/drivers/i2c/i2c-boardinfo.c
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -56,9 +56,7 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
  * The board info passed can safely be __initdata, but be careful of embedded
  * pointers (for platform_data, functions, etc) since that won't be copied.
  */
-int __init
-i2c_register_board_info(int busnum,
-	struct i2c_board_info const *info, unsigned len)
+int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
 {
 	int status;
 
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index e584d88..af11b65 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -954,48 +954,40 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
 }
 
 /**
- * i2c_lock_adapter - Get exclusive access to an I2C bus segment
+ * i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
  * @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT
+ *	locks only this branch in the adapter tree
  */
-void i2c_lock_adapter(struct i2c_adapter *adapter)
+static void i2c_adapter_lock_bus(struct i2c_adapter *adapter,
+				 unsigned int flags)
 {
-	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
-
-	if (parent)
-		i2c_lock_adapter(parent);
-	else
-		rt_mutex_lock(&adapter->bus_lock);
+	rt_mutex_lock(&adapter->bus_lock);
 }
-EXPORT_SYMBOL_GPL(i2c_lock_adapter);
 
 /**
- * i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
+ * i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment
  * @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ROOT_ADAPTER trylocks the root i2c adapter, I2C_LOCK_SEGMENT
+ *	trylocks only this branch in the adapter tree
  */
-static int i2c_trylock_adapter(struct i2c_adapter *adapter)
+static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter,
+				   unsigned int flags)
 {
-	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
-
-	if (parent)
-		return i2c_trylock_adapter(parent);
-	else
-		return rt_mutex_trylock(&adapter->bus_lock);
+	return rt_mutex_trylock(&adapter->bus_lock);
 }
 
 /**
- * i2c_unlock_adapter - Release exclusive access to an I2C bus segment
+ * i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment
  * @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ROOT_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT
+ *	unlocks only this branch in the adapter tree
  */
-void i2c_unlock_adapter(struct i2c_adapter *adapter)
+static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter,
+				   unsigned int flags)
 {
-	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
-
-	if (parent)
-		i2c_unlock_adapter(parent);
-	else
-		rt_mutex_unlock(&adapter->bus_lock);
+	rt_mutex_unlock(&adapter->bus_lock);
 }
-EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
 
 static void i2c_dev_set_name(struct i2c_adapter *adap,
 			     struct i2c_client *client)
@@ -1541,7 +1533,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 		return -EINVAL;
 	}
 
+	if (!adap->lock_bus) {
+		adap->lock_bus = i2c_adapter_lock_bus;
+		adap->trylock_bus = i2c_adapter_trylock_bus;
+		adap->unlock_bus = i2c_adapter_unlock_bus;
+	}
+
 	rt_mutex_init(&adap->bus_lock);
+	rt_mutex_init(&adap->mux_lock);
 	mutex_init(&adap->userspace_clients_lock);
 	INIT_LIST_HEAD(&adap->userspace_clients);
 
@@ -1559,6 +1558,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
 
 	pm_runtime_no_callbacks(&adap->dev);
+	pm_suspend_ignore_children(&adap->dev, true);
 	pm_runtime_enable(&adap->dev);
 
 #ifdef CONFIG_I2C_COMPAT
@@ -1594,10 +1594,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 
 			bri->get_scl = get_scl_gpio_value;
 			bri->set_scl = set_scl_gpio_value;
-		} else if (!bri->set_scl || !bri->get_scl) {
+		} else if (bri->recover_bus == i2c_generic_scl_recovery) {
 			/* Generic SCL recovery */
-			dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n");
-			adap->bus_recovery_info = NULL;
+			if (!bri->set_scl || !bri->get_scl) {
+				dev_err(&adap->dev, "No {get|set}_scl() found, not using recovery\n");
+				adap->bus_recovery_info = NULL;
+			}
 		}
 	}
 
@@ -2309,16 +2311,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 #endif
 
 		if (in_atomic() || irqs_disabled()) {
-			ret = i2c_trylock_adapter(adap);
+			ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT);
 			if (!ret)
 				/* I2C activity is ongoing. */
 				return -EAGAIN;
 		} else {
-			i2c_lock_adapter(adap);
+			i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
 		}
 
 		ret = __i2c_transfer(adap, msgs, num);
-		i2c_unlock_adapter(adap);
+		i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
 
 		return ret;
 	} else {
@@ -2646,7 +2648,7 @@ static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
 static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
 {
 	/* The address will be sent first */
-	u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD);
+	u8 addr = i2c_8bit_addr_from_msg(msg);
 	pec = i2c_smbus_pec(pec, &addr, 1);
 
 	/* The data buffer follows */
@@ -3093,7 +3095,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
 	flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
 
 	if (adapter->algo->smbus_xfer) {
-		i2c_lock_adapter(adapter);
+		i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
 
 		/* Retry automatically on arbitration loss */
 		orig_jiffies = jiffies;
@@ -3107,7 +3109,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
 				       orig_jiffies + adapter->timeout))
 				break;
 		}
-		i2c_unlock_adapter(adapter);
+		i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
 
 		if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
 			goto trace;
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 0b1108d..6ecfd76 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -22,6 +22,7 @@
 
 /* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
 
+#include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/i2c-dev.h>
@@ -47,9 +48,10 @@ struct i2c_dev {
 	struct list_head list;
 	struct i2c_adapter *adap;
 	struct device *dev;
+	struct cdev cdev;
 };
 
-#define I2C_MINORS	256
+#define I2C_MINORS	MINORMASK
 static LIST_HEAD(i2c_dev_list);
 static DEFINE_SPINLOCK(i2c_dev_list_lock);
 
@@ -89,7 +91,7 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
 	return i2c_dev;
 }
 
-static void return_i2c_dev(struct i2c_dev *i2c_dev)
+static void put_i2c_dev(struct i2c_dev *i2c_dev)
 {
 	spin_lock(&i2c_dev_list_lock);
 	list_del(&i2c_dev->list);
@@ -552,6 +554,12 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
 	if (IS_ERR(i2c_dev))
 		return PTR_ERR(i2c_dev);
 
+	cdev_init(&i2c_dev->cdev, &i2cdev_fops);
+	i2c_dev->cdev.owner = THIS_MODULE;
+	res = cdev_add(&i2c_dev->cdev, MKDEV(I2C_MAJOR, adap->nr), 1);
+	if (res)
+		goto error_cdev;
+
 	/* register this i2c device with the driver core */
 	i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
 				     MKDEV(I2C_MAJOR, adap->nr), NULL,
@@ -565,7 +573,9 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
 		 adap->name, adap->nr);
 	return 0;
 error:
-	return_i2c_dev(i2c_dev);
+	cdev_del(&i2c_dev->cdev);
+error_cdev:
+	put_i2c_dev(i2c_dev);
 	return res;
 }
 
@@ -582,7 +592,8 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
 	if (!i2c_dev) /* attach_adapter must have failed */
 		return 0;
 
-	return_i2c_dev(i2c_dev);
+	cdev_del(&i2c_dev->cdev);
+	put_i2c_dev(i2c_dev);
 	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
 
 	pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
@@ -620,7 +631,7 @@ static int __init i2c_dev_init(void)
 
 	printk(KERN_INFO "i2c /dev entries driver\n");
 
-	res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
+	res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c");
 	if (res)
 		goto out;
 
@@ -644,7 +655,7 @@ static int __init i2c_dev_init(void)
 out_unreg_class:
 	class_destroy(i2c_dev_class);
 out_unreg_chrdev:
-	unregister_chrdev(I2C_MAJOR, "i2c");
+	unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
 out:
 	printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
 	return res;
@@ -655,7 +666,7 @@ static void __exit i2c_dev_exit(void)
 	bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
 	i2c_for_each_dev(NULL, i2cdev_detach_adapter);
 	class_destroy(i2c_dev_class);
-	unregister_chrdev(I2C_MAJOR, "i2c");
+	unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index d402287..8eee986 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -31,30 +31,66 @@
 struct i2c_mux_priv {
 	struct i2c_adapter adap;
 	struct i2c_algorithm algo;
-
-	struct i2c_adapter *parent;
-	struct device *mux_dev;
-	void *mux_priv;
+	struct i2c_mux_core *muxc;
 	u32 chan_id;
-
-	int (*select)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
-	int (*deselect)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
 };
 
+static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
+				 struct i2c_msg msgs[], int num)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	/* Switch to the right mux port and perform the transfer. */
+
+	ret = muxc->select(muxc, priv->chan_id);
+	if (ret >= 0)
+		ret = __i2c_transfer(parent, msgs, num);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+
+	return ret;
+}
+
 static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 			       struct i2c_msg msgs[], int num)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
-	struct i2c_adapter *parent = priv->parent;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
 	int ret;
 
 	/* Switch to the right mux port and perform the transfer. */
 
-	ret = priv->select(parent, priv->mux_priv, priv->chan_id);
+	ret = muxc->select(muxc, priv->chan_id);
 	if (ret >= 0)
-		ret = __i2c_transfer(parent, msgs, num);
-	if (priv->deselect)
-		priv->deselect(parent, priv->mux_priv, priv->chan_id);
+		ret = i2c_transfer(parent, msgs, num);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+
+	return ret;
+}
+
+static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
+				u16 addr, unsigned short flags,
+				char read_write, u8 command,
+				int size, union i2c_smbus_data *data)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	/* Select the right mux port and perform the transfer. */
+
+	ret = muxc->select(muxc, priv->chan_id);
+	if (ret >= 0)
+		ret = parent->algo->smbus_xfer(parent, addr, flags,
+					read_write, command, size, data);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
 
 	return ret;
 }
@@ -65,17 +101,18 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 			      int size, union i2c_smbus_data *data)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
-	struct i2c_adapter *parent = priv->parent;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
 	int ret;
 
 	/* Select the right mux port and perform the transfer. */
 
-	ret = priv->select(parent, priv->mux_priv, priv->chan_id);
+	ret = muxc->select(muxc, priv->chan_id);
 	if (ret >= 0)
-		ret = parent->algo->smbus_xfer(parent, addr, flags,
-					read_write, command, size, data);
-	if (priv->deselect)
-		priv->deselect(parent, priv->mux_priv, priv->chan_id);
+		ret = i2c_smbus_xfer(parent, addr, flags,
+				     read_write, command, size, data);
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
 
 	return ret;
 }
@@ -84,7 +121,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 static u32 i2c_mux_functionality(struct i2c_adapter *adap)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
-	struct i2c_adapter *parent = priv->parent;
+	struct i2c_adapter *parent = priv->muxc->parent;
 
 	return parent->algo->functionality(parent);
 }
@@ -102,38 +139,167 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
 	return class;
 }
 
-struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
-				struct device *mux_dev,
-				void *mux_priv, u32 force_nr, u32 chan_id,
-				unsigned int class,
-				int (*select) (struct i2c_adapter *,
-					       void *, u32),
-				int (*deselect) (struct i2c_adapter *,
-						 void *, u32))
+static void i2c_mux_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	rt_mutex_lock(&parent->mux_lock);
+	if (!(flags & I2C_LOCK_ROOT_ADAPTER))
+		return;
+	i2c_lock_bus(parent, flags);
+}
+
+static int i2c_mux_trylock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	if (!rt_mutex_trylock(&parent->mux_lock))
+		return 0;	/* mux_lock not locked, failure */
+	if (!(flags & I2C_LOCK_ROOT_ADAPTER))
+		return 1;	/* we only want mux_lock, success */
+	if (parent->trylock_bus(parent, flags))
+		return 1;	/* parent locked too, success */
+	rt_mutex_unlock(&parent->mux_lock);
+	return 0;		/* parent not locked, failure */
+}
+
+static void i2c_mux_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	if (flags & I2C_LOCK_ROOT_ADAPTER)
+		i2c_unlock_bus(parent, flags);
+	rt_mutex_unlock(&parent->mux_lock);
+}
+
+static void i2c_parent_lock_bus(struct i2c_adapter *adapter,
+				unsigned int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	rt_mutex_lock(&parent->mux_lock);
+	i2c_lock_bus(parent, flags);
+}
+
+static int i2c_parent_trylock_bus(struct i2c_adapter *adapter,
+				  unsigned int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	if (!rt_mutex_trylock(&parent->mux_lock))
+		return 0;	/* mux_lock not locked, failure */
+	if (parent->trylock_bus(parent, flags))
+		return 1;	/* parent locked too, success */
+	rt_mutex_unlock(&parent->mux_lock);
+	return 0;		/* parent not locked, failure */
+}
+
+static void i2c_parent_unlock_bus(struct i2c_adapter *adapter,
+				  unsigned int flags)
+{
+	struct i2c_mux_priv *priv = adapter->algo_data;
+	struct i2c_adapter *parent = priv->muxc->parent;
+
+	i2c_unlock_bus(parent, flags);
+	rt_mutex_unlock(&parent->mux_lock);
+}
+
+struct i2c_adapter *i2c_root_adapter(struct device *dev)
+{
+	struct device *i2c;
+	struct i2c_adapter *i2c_root;
+
+	/*
+	 * Walk up the device tree to find an i2c adapter, indicating
+	 * that this is an i2c client device. Check all ancestors to
+	 * handle mfd devices etc.
+	 */
+	for (i2c = dev; i2c; i2c = i2c->parent) {
+		if (i2c->type == &i2c_adapter_type)
+			break;
+	}
+	if (!i2c)
+		return NULL;
+
+	/* Continue up the tree to find the root i2c adapter */
+	i2c_root = to_i2c_adapter(i2c);
+	while (i2c_parent_is_i2c_adapter(i2c_root))
+		i2c_root = i2c_parent_is_i2c_adapter(i2c_root);
+
+	return i2c_root;
+}
+EXPORT_SYMBOL_GPL(i2c_root_adapter);
+
+struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
+				   struct device *dev, int max_adapters,
+				   int sizeof_priv, u32 flags,
+				   int (*select)(struct i2c_mux_core *, u32),
+				   int (*deselect)(struct i2c_mux_core *, u32))
+{
+	struct i2c_mux_core *muxc;
+
+	muxc = devm_kzalloc(dev, sizeof(*muxc)
+			    + max_adapters * sizeof(muxc->adapter[0])
+			    + sizeof_priv, GFP_KERNEL);
+	if (!muxc)
+		return NULL;
+	if (sizeof_priv)
+		muxc->priv = &muxc->adapter[max_adapters];
+
+	muxc->parent = parent;
+	muxc->dev = dev;
+	if (flags & I2C_MUX_LOCKED)
+		muxc->mux_locked = true;
+	muxc->select = select;
+	muxc->deselect = deselect;
+	muxc->max_adapters = max_adapters;
+
+	return muxc;
+}
+EXPORT_SYMBOL_GPL(i2c_mux_alloc);
+
+int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
+			u32 force_nr, u32 chan_id,
+			unsigned int class)
 {
+	struct i2c_adapter *parent = muxc->parent;
 	struct i2c_mux_priv *priv;
 	char symlink_name[20];
 	int ret;
 
-	priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
+	if (muxc->num_adapters >= muxc->max_adapters) {
+		dev_err(muxc->dev, "No room for more i2c-mux adapters\n");
+		return -EINVAL;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
-		return NULL;
+		return -ENOMEM;
 
 	/* Set up private adapter data */
-	priv->parent = parent;
-	priv->mux_dev = mux_dev;
-	priv->mux_priv = mux_priv;
+	priv->muxc = muxc;
 	priv->chan_id = chan_id;
-	priv->select = select;
-	priv->deselect = deselect;
 
 	/* Need to do algo dynamically because we don't know ahead
 	 * of time what sort of physical adapter we'll be dealing with.
 	 */
-	if (parent->algo->master_xfer)
-		priv->algo.master_xfer = i2c_mux_master_xfer;
-	if (parent->algo->smbus_xfer)
-		priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
+	if (parent->algo->master_xfer) {
+		if (muxc->mux_locked)
+			priv->algo.master_xfer = i2c_mux_master_xfer;
+		else
+			priv->algo.master_xfer = __i2c_mux_master_xfer;
+	}
+	if (parent->algo->smbus_xfer) {
+		if (muxc->mux_locked)
+			priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
+		else
+			priv->algo.smbus_xfer = __i2c_mux_smbus_xfer;
+	}
 	priv->algo.functionality = i2c_mux_functionality;
 
 	/* Now fill out new adapter structure */
@@ -146,6 +312,15 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 	priv->adap.retries = parent->retries;
 	priv->adap.timeout = parent->timeout;
 	priv->adap.quirks = parent->quirks;
+	if (muxc->mux_locked) {
+		priv->adap.lock_bus = i2c_mux_lock_bus;
+		priv->adap.trylock_bus = i2c_mux_trylock_bus;
+		priv->adap.unlock_bus = i2c_mux_unlock_bus;
+	} else {
+		priv->adap.lock_bus = i2c_parent_lock_bus;
+		priv->adap.trylock_bus = i2c_parent_trylock_bus;
+		priv->adap.unlock_bus = i2c_parent_unlock_bus;
+	}
 
 	/* Sanity check on class */
 	if (i2c_mux_parent_classes(parent) & class)
@@ -159,11 +334,11 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 	 * Try to populate the mux adapter's of_node, expands to
 	 * nothing if !CONFIG_OF.
 	 */
-	if (mux_dev->of_node) {
+	if (muxc->dev->of_node) {
 		struct device_node *child;
 		u32 reg;
 
-		for_each_child_of_node(mux_dev->of_node, child) {
+		for_each_child_of_node(muxc->dev->of_node, child) {
 			ret = of_property_read_u32(child, "reg", &reg);
 			if (ret)
 				continue;
@@ -177,8 +352,9 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 	/*
 	 * Associate the mux channel with an ACPI node.
 	 */
-	if (has_acpi_companion(mux_dev))
-		acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev),
+	if (has_acpi_companion(muxc->dev))
+		acpi_preset_companion(&priv->adap.dev,
+				      ACPI_COMPANION(muxc->dev),
 				      chan_id);
 
 	if (force_nr) {
@@ -192,35 +368,45 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
 			"failed to add mux-adapter (error=%d)\n",
 			ret);
 		kfree(priv);
-		return NULL;
+		return ret;
 	}
 
-	WARN(sysfs_create_link(&priv->adap.dev.kobj, &mux_dev->kobj, "mux_device"),
-			       "can't create symlink to mux device\n");
+	WARN(sysfs_create_link(&priv->adap.dev.kobj, &muxc->dev->kobj,
+			       "mux_device"),
+	     "can't create symlink to mux device\n");
 
 	snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
-	WARN(sysfs_create_link(&mux_dev->kobj, &priv->adap.dev.kobj, symlink_name),
-			       "can't create symlink for channel %u\n", chan_id);
+	WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj,
+			       symlink_name),
+	     "can't create symlink for channel %u\n", chan_id);
 	dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
 		 i2c_adapter_id(&priv->adap));
 
-	return &priv->adap;
+	muxc->adapter[muxc->num_adapters++] = &priv->adap;
+	return 0;
 }
-EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
+EXPORT_SYMBOL_GPL(i2c_mux_add_adapter);
 
-void i2c_del_mux_adapter(struct i2c_adapter *adap)
+void i2c_mux_del_adapters(struct i2c_mux_core *muxc)
 {
-	struct i2c_mux_priv *priv = adap->algo_data;
 	char symlink_name[20];
 
-	snprintf(symlink_name, sizeof(symlink_name), "channel-%u", priv->chan_id);
-	sysfs_remove_link(&priv->mux_dev->kobj, symlink_name);
+	while (muxc->num_adapters) {
+		struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters];
+		struct i2c_mux_priv *priv = adap->algo_data;
+
+		muxc->adapter[muxc->num_adapters] = NULL;
+
+		snprintf(symlink_name, sizeof(symlink_name),
+			 "channel-%u", priv->chan_id);
+		sysfs_remove_link(&muxc->dev->kobj, symlink_name);
 
-	sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
-	i2c_del_adapter(adap);
-	kfree(priv);
+		sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
+		i2c_del_adapter(adap);
+		kfree(priv);
+	}
 }
-EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);
+EXPORT_SYMBOL_GPL(i2c_mux_del_adapters);
 
 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses");
diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
index 402e3a6..a90bbc4 100644
--- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
+++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c
@@ -28,8 +28,6 @@
 /**
  * struct i2c_arbitrator_data - Driver data for I2C arbitrator
  *
- * @parent: Parent adapter
- * @child: Child bus
  * @our_gpio: GPIO we'll use to claim.
  * @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
  *   this then consider it released.
@@ -42,8 +40,6 @@
  */
 
 struct i2c_arbitrator_data {
-	struct i2c_adapter *parent;
-	struct i2c_adapter *child;
 	int our_gpio;
 	int our_gpio_release;
 	int their_gpio;
@@ -59,9 +55,9 @@ struct i2c_arbitrator_data {
  *
  * Use the GPIO-based signalling protocol; return -EBUSY if we fail.
  */
-static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
+static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	const struct i2c_arbitrator_data *arb = data;
+	const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
 	unsigned long stop_retry, stop_time;
 
 	/* Start a round of trying to claim the bus */
@@ -93,7 +89,7 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
 	/* Give up, release our claim */
 	gpio_set_value(arb->our_gpio, arb->our_gpio_release);
 	udelay(arb->slew_delay_us);
-	dev_err(&adap->dev, "Could not claim bus, timeout\n");
+	dev_err(muxc->dev, "Could not claim bus, timeout\n");
 	return -EBUSY;
 }
 
@@ -102,10 +98,9 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
  *
  * Release the I2C bus using the GPIO-based signalling protocol.
  */
-static int i2c_arbitrator_deselect(struct i2c_adapter *adap, void *data,
-				   u32 chan)
+static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	const struct i2c_arbitrator_data *arb = data;
+	const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
 
 	/* Release the bus and wait for the other master to notice */
 	gpio_set_value(arb->our_gpio, arb->our_gpio_release);
@@ -119,6 +114,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
 	struct device_node *parent_np;
+	struct i2c_mux_core *muxc;
 	struct i2c_arbitrator_data *arb;
 	enum of_gpio_flags gpio_flags;
 	unsigned long out_init;
@@ -134,12 +130,13 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
-	if (!arb) {
-		dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
+	muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), 0,
+			     i2c_arbitrator_select, i2c_arbitrator_deselect);
+	if (!muxc)
 		return -ENOMEM;
-	}
-	platform_set_drvdata(pdev, arb);
+	arb = i2c_mux_priv(muxc);
+
+	platform_set_drvdata(pdev, muxc);
 
 	/* Request GPIOs */
 	ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
@@ -196,21 +193,18 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 		dev_err(dev, "Cannot parse i2c-parent\n");
 		return -EINVAL;
 	}
-	arb->parent = of_get_i2c_adapter_by_node(parent_np);
+	muxc->parent = of_get_i2c_adapter_by_node(parent_np);
 	of_node_put(parent_np);
-	if (!arb->parent) {
+	if (!muxc->parent) {
 		dev_err(dev, "Cannot find parent bus\n");
 		return -EPROBE_DEFER;
 	}
 
 	/* Actually add the mux adapter */
-	arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
-					 i2c_arbitrator_select,
-					 i2c_arbitrator_deselect);
-	if (!arb->child) {
+	ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
+	if (ret) {
 		dev_err(dev, "Failed to add adapter\n");
-		ret = -ENODEV;
-		i2c_put_adapter(arb->parent);
+		i2c_put_adapter(muxc->parent);
 	}
 
 	return ret;
@@ -218,11 +212,10 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
 
 static int i2c_arbitrator_remove(struct platform_device *pdev)
 {
-	struct i2c_arbitrator_data *arb = platform_get_drvdata(pdev);
-
-	i2c_del_mux_adapter(arb->child);
-	i2c_put_adapter(arb->parent);
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
 
+	i2c_mux_del_adapters(muxc);
+	i2c_put_adapter(muxc->parent);
 	return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index b8e11c1..e5cf26e 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -15,11 +15,10 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
+#include "../../gpio/gpiolib.h"
 #include <linux/of_gpio.h>
 
 struct gpiomux {
-	struct i2c_adapter *parent;
-	struct i2c_adapter **adap; /* child busses */
 	struct i2c_mux_gpio_platform_data data;
 	unsigned gpio_base;
 };
@@ -33,18 +32,18 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
 					val & (1 << i));
 }
 
-static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan)
+static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct gpiomux *mux = data;
+	struct gpiomux *mux = i2c_mux_priv(muxc);
 
 	i2c_mux_gpio_set(mux, chan);
 
 	return 0;
 }
 
-static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan)
+static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct gpiomux *mux = data;
+	struct gpiomux *mux = i2c_mux_priv(muxc);
 
 	i2c_mux_gpio_set(mux, mux->data.idle);
 
@@ -136,19 +135,16 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
 
 static int i2c_mux_gpio_probe(struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc;
 	struct gpiomux *mux;
 	struct i2c_adapter *parent;
-	int (*deselect) (struct i2c_adapter *, void *, u32);
+	struct i2c_adapter *root;
 	unsigned initial_state, gpio_base;
 	int i, ret;
 
 	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
-	if (!mux) {
-		dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
+	if (!mux)
 		return -ENOMEM;
-	}
-
-	platform_set_drvdata(pdev, mux);
 
 	if (!dev_get_platdata(&pdev->dev)) {
 		ret = i2c_mux_gpio_probe_dt(mux, pdev);
@@ -180,27 +176,32 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 	if (!parent)
 		return -EPROBE_DEFER;
 
-	mux->parent = parent;
-	mux->gpio_base = gpio_base;
-
-	mux->adap = devm_kzalloc(&pdev->dev,
-				 sizeof(*mux->adap) * mux->data.n_values,
-				 GFP_KERNEL);
-	if (!mux->adap) {
-		dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
+	muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
+			     i2c_mux_gpio_select, NULL);
+	if (!muxc) {
 		ret = -ENOMEM;
 		goto alloc_failed;
 	}
+	muxc->priv = mux;
+
+	platform_set_drvdata(pdev, muxc);
+
+	root = i2c_root_adapter(&parent->dev);
+
+	muxc->mux_locked = true;
+	mux->gpio_base = gpio_base;
 
 	if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
 		initial_state = mux->data.idle;
-		deselect = i2c_mux_gpio_deselect;
+		muxc->deselect = i2c_mux_gpio_deselect;
 	} else {
 		initial_state = mux->data.values[0];
-		deselect = NULL;
 	}
 
 	for (i = 0; i < mux->data.n_gpios; i++) {
+		struct device *gpio_dev;
+		struct gpio_desc *gpio_desc;
+
 		ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
 		if (ret) {
 			dev_err(&pdev->dev, "Failed to request GPIO %d\n",
@@ -217,17 +218,24 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 			i++;	/* gpio_request above succeeded, so must free */
 			goto err_request_gpio;
 		}
+
+		if (!muxc->mux_locked)
+			continue;
+
+		gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]);
+		gpio_dev = &gpio_desc->gdev->dev;
+		muxc->mux_locked = i2c_root_adapter(gpio_dev) == root;
 	}
 
+	if (muxc->mux_locked)
+		dev_info(&pdev->dev, "mux-locked i2c mux\n");
+
 	for (i = 0; i < mux->data.n_values; i++) {
 		u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
 		unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
 
-		mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr,
-						   mux->data.values[i], class,
-						   i2c_mux_gpio_select, deselect);
-		if (!mux->adap[i]) {
-			ret = -ENODEV;
+		ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
+		if (ret) {
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
 			goto add_adapter_failed;
 		}
@@ -239,8 +247,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 	return 0;
 
 add_adapter_failed:
-	for (; i > 0; i--)
-		i2c_del_mux_adapter(mux->adap[i - 1]);
+	i2c_mux_del_adapters(muxc);
 	i = mux->data.n_gpios;
 err_request_gpio:
 	for (; i > 0; i--)
@@ -253,16 +260,16 @@ alloc_failed:
 
 static int i2c_mux_gpio_remove(struct platform_device *pdev)
 {
-	struct gpiomux *mux = platform_get_drvdata(pdev);
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
+	struct gpiomux *mux = i2c_mux_priv(muxc);
 	int i;
 
-	for (i = 0; i < mux->data.n_values; i++)
-		i2c_del_mux_adapter(mux->adap[i]);
+	i2c_mux_del_adapters(muxc);
 
 	for (i = 0; i < mux->data.n_gpios; i++)
 		gpio_free(mux->gpio_base + mux->data.gpios[i]);
 
-	i2c_put_adapter(mux->parent);
+	i2c_put_adapter(muxc->parent);
 
 	return 0;
 }
diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c
index d0ba424..3cb8af6 100644
--- a/drivers/i2c/muxes/i2c-mux-pca9541.c
+++ b/drivers/i2c/muxes/i2c-mux-pca9541.c
@@ -73,7 +73,7 @@
 #define SELECT_DELAY_LONG	1000
 
 struct pca9541 {
-	struct i2c_adapter *mux_adap;
+	struct i2c_client *client;
 	unsigned long select_timeout;
 	unsigned long arb_timeout;
 };
@@ -217,7 +217,8 @@ static const u8 pca9541_control[16] = {
  */
 static int pca9541_arbitrate(struct i2c_client *client)
 {
-	struct pca9541 *data = i2c_get_clientdata(client);
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	struct pca9541 *data = i2c_mux_priv(muxc);
 	int reg;
 
 	reg = pca9541_reg_read(client, PCA9541_CONTROL);
@@ -285,9 +286,10 @@ static int pca9541_arbitrate(struct i2c_client *client)
 	return 0;
 }
 
-static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
+static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct pca9541 *data = i2c_get_clientdata(client);
+	struct pca9541 *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
 	int ret;
 	unsigned long timeout = jiffies + ARB2_TIMEOUT;
 		/* give up after this time */
@@ -309,9 +311,11 @@ static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
 	return -ETIMEDOUT;
 }
 
-static int pca9541_release_chan(struct i2c_adapter *adap,
-				void *client, u32 chan)
+static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan)
 {
+	struct pca9541 *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
+
 	pca9541_release_bus(client);
 	return 0;
 }
@@ -324,20 +328,13 @@ static int pca9541_probe(struct i2c_client *client,
 {
 	struct i2c_adapter *adap = client->adapter;
 	struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
+	struct i2c_mux_core *muxc;
 	struct pca9541 *data;
 	int force;
-	int ret = -ENODEV;
+	int ret;
 
 	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
-		goto err;
-
-	data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	i2c_set_clientdata(client, data);
+		return -ENODEV;
 
 	/*
 	 * I2C accesses are unprotected here.
@@ -352,34 +349,33 @@ static int pca9541_probe(struct i2c_client *client,
 	force = 0;
 	if (pdata)
 		force = pdata->modes[0].adap_id;
-	data->mux_adap = i2c_add_mux_adapter(adap, &client->dev, client,
-					     force, 0, 0,
-					     pca9541_select_chan,
-					     pca9541_release_chan);
+	muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), 0,
+			     pca9541_select_chan, pca9541_release_chan);
+	if (!muxc)
+		return -ENOMEM;
 
-	if (data->mux_adap == NULL) {
+	data = i2c_mux_priv(muxc);
+	data->client = client;
+
+	i2c_set_clientdata(client, muxc);
+
+	ret = i2c_mux_add_adapter(muxc, force, 0, 0);
+	if (ret) {
 		dev_err(&client->dev, "failed to register master selector\n");
-		goto exit_free;
+		return ret;
 	}
 
 	dev_info(&client->dev, "registered master selector for I2C %s\n",
 		 client->name);
 
 	return 0;
-
-exit_free:
-	kfree(data);
-err:
-	return ret;
 }
 
 static int pca9541_remove(struct i2c_client *client)
 {
-	struct pca9541 *data = i2c_get_clientdata(client);
-
-	i2c_del_mux_adapter(data->mux_adap);
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
 
-	kfree(data);
+	i2c_mux_del_adapters(muxc);
 	return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index acfcef3..528e755 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -60,9 +60,10 @@ enum pca_type {
 
 struct pca954x {
 	enum pca_type type;
-	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
 
 	u8 last_chan;		/* last register value */
+	u8 deselect;
+	struct i2c_client *client;
 };
 
 struct chip_desc {
@@ -146,10 +147,10 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
 	return ret;
 }
 
-static int pca954x_select_chan(struct i2c_adapter *adap,
-			       void *client, u32 chan)
+static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct pca954x *data = i2c_get_clientdata(client);
+	struct pca954x *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
 	const struct chip_desc *chip = &chips[data->type];
 	u8 regval;
 	int ret = 0;
@@ -162,21 +163,24 @@ static int pca954x_select_chan(struct i2c_adapter *adap,
 
 	/* Only select the channel if its different from the last channel */
 	if (data->last_chan != regval) {
-		ret = pca954x_reg_write(adap, client, regval);
+		ret = pca954x_reg_write(muxc->parent, client, regval);
 		data->last_chan = regval;
 	}
 
 	return ret;
 }
 
-static int pca954x_deselect_mux(struct i2c_adapter *adap,
-				void *client, u32 chan)
+static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct pca954x *data = i2c_get_clientdata(client);
+	struct pca954x *data = i2c_mux_priv(muxc);
+	struct i2c_client *client = data->client;
+
+	if (!(data->deselect & (1 << chan)))
+		return 0;
 
 	/* Deselect active channel */
 	data->last_chan = 0;
-	return pca954x_reg_write(adap, client, data->last_chan);
+	return pca954x_reg_write(muxc->parent, client, data->last_chan);
 }
 
 /*
@@ -191,17 +195,22 @@ static int pca954x_probe(struct i2c_client *client,
 	bool idle_disconnect_dt;
 	struct gpio_desc *gpio;
 	int num, force, class;
+	struct i2c_mux_core *muxc;
 	struct pca954x *data;
 	int ret;
 
 	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
 		return -ENODEV;
 
-	data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL);
-	if (!data)
+	muxc = i2c_mux_alloc(adap, &client->dev,
+			     PCA954X_MAX_NCHANS, sizeof(*data), 0,
+			     pca954x_select_chan, pca954x_deselect_mux);
+	if (!muxc)
 		return -ENOMEM;
+	data = i2c_mux_priv(muxc);
 
-	i2c_set_clientdata(client, data);
+	i2c_set_clientdata(client, muxc);
+	data->client = client;
 
 	/* Get the mux out of reset if a reset GPIO is specified. */
 	gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
@@ -238,16 +247,13 @@ static int pca954x_probe(struct i2c_client *client,
 				/* discard unconfigured channels */
 				break;
 			idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
+			data->deselect |= (idle_disconnect_pd
+					   || idle_disconnect_dt) << num;
 		}
 
-		data->virt_adaps[num] =
-			i2c_add_mux_adapter(adap, &client->dev, client,
-				force, num, class, pca954x_select_chan,
-				(idle_disconnect_pd || idle_disconnect_dt)
-					? pca954x_deselect_mux : NULL);
+		ret = i2c_mux_add_adapter(muxc, force, num, class);
 
-		if (data->virt_adaps[num] == NULL) {
-			ret = -ENODEV;
+		if (ret) {
 			dev_err(&client->dev,
 				"failed to register multiplexed adapter"
 				" %d as bus %d\n", num, force);
@@ -263,23 +269,15 @@ static int pca954x_probe(struct i2c_client *client,
 	return 0;
 
 virt_reg_failed:
-	for (num--; num >= 0; num--)
-		i2c_del_mux_adapter(data->virt_adaps[num]);
+	i2c_mux_del_adapters(muxc);
 	return ret;
 }
 
 static int pca954x_remove(struct i2c_client *client)
 {
-	struct pca954x *data = i2c_get_clientdata(client);
-	const struct chip_desc *chip = &chips[data->type];
-	int i;
-
-	for (i = 0; i < chip->nchans; ++i)
-		if (data->virt_adaps[i]) {
-			i2c_del_mux_adapter(data->virt_adaps[i]);
-			data->virt_adaps[i] = NULL;
-		}
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
 
+	i2c_mux_del_adapters(muxc);
 	return 0;
 }
 
@@ -287,7 +285,8 @@ static int pca954x_remove(struct i2c_client *client)
 static int pca954x_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	struct pca954x *data = i2c_get_clientdata(client);
+	struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+	struct pca954x *data = i2c_mux_priv(muxc);
 
 	data->last_chan = 0;
 	return i2c_smbus_write_byte(client, 0);
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index b5a982b..35bb775 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -24,36 +24,32 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include "../../pinctrl/core.h"
 
 struct i2c_mux_pinctrl {
-	struct device *dev;
 	struct i2c_mux_pinctrl_platform_data *pdata;
 	struct pinctrl *pinctrl;
 	struct pinctrl_state **states;
 	struct pinctrl_state *state_idle;
-	struct i2c_adapter *parent;
-	struct i2c_adapter **busses;
 };
 
-static int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data,
-				  u32 chan)
+static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_mux_pinctrl *mux = data;
+	struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
 
 	return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
 }
 
-static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
-				    u32 chan)
+static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct i2c_mux_pinctrl *mux = data;
+	struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
 
 	return pinctrl_select_state(mux->pinctrl, mux->state_idle);
 }
 
 #ifdef CONFIG_OF
 static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
-				struct platform_device *pdev)
+				    struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	int num_names, i, ret;
@@ -64,15 +60,12 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 		return 0;
 
 	mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
-	if (!mux->pdata) {
-		dev_err(mux->dev,
-			"Cannot allocate i2c_mux_pinctrl_platform_data\n");
+	if (!mux->pdata)
 		return -ENOMEM;
-	}
 
 	num_names = of_property_count_strings(np, "pinctrl-names");
 	if (num_names < 0) {
-		dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
+		dev_err(&pdev->dev, "Cannot parse pinctrl-names: %d\n",
 			num_names);
 		return num_names;
 	}
@@ -80,23 +73,22 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 	mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
 		sizeof(*mux->pdata->pinctrl_states) * num_names,
 		GFP_KERNEL);
-	if (!mux->pdata->pinctrl_states) {
-		dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
+	if (!mux->pdata->pinctrl_states)
 		return -ENOMEM;
-	}
 
 	for (i = 0; i < num_names; i++) {
 		ret = of_property_read_string_index(np, "pinctrl-names", i,
 			&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
 		if (ret < 0) {
-			dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
+			dev_err(&pdev->dev, "Cannot parse pinctrl-names: %d\n",
 				ret);
 			return ret;
 		}
 		if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
 			    "idle")) {
 			if (i != num_names - 1) {
-				dev_err(mux->dev, "idle state must be last\n");
+				dev_err(&pdev->dev,
+					"idle state must be last\n");
 				return -EINVAL;
 			}
 			mux->pdata->pinctrl_state_idle = "idle";
@@ -107,13 +99,13 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 
 	adapter_np = of_parse_phandle(np, "i2c-parent", 0);
 	if (!adapter_np) {
-		dev_err(mux->dev, "Cannot parse i2c-parent\n");
+		dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
 		return -ENODEV;
 	}
 	adapter = of_find_i2c_adapter_by_node(adapter_np);
 	of_node_put(adapter_np);
 	if (!adapter) {
-		dev_err(mux->dev, "Cannot find parent bus\n");
+		dev_err(&pdev->dev, "Cannot find parent bus\n");
 		return -EPROBE_DEFER;
 	}
 	mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
@@ -129,21 +121,38 @@ static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 }
 #endif
 
+static struct i2c_adapter *i2c_mux_pinctrl_root_adapter(
+	struct pinctrl_state *state)
+{
+	struct i2c_adapter *root = NULL;
+	struct pinctrl_setting *setting;
+	struct i2c_adapter *pin_root;
+
+	list_for_each_entry(setting, &state->settings, node) {
+		pin_root = i2c_root_adapter(setting->pctldev->dev);
+		if (!pin_root)
+			return NULL;
+		if (!root)
+			root = pin_root;
+		else if (root != pin_root)
+			return NULL;
+	}
+
+	return root;
+}
+
 static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc;
 	struct i2c_mux_pinctrl *mux;
-	int (*deselect)(struct i2c_adapter *, void *, u32);
+	struct i2c_adapter *root;
 	int i, ret;
 
 	mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
 	if (!mux) {
-		dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
 		ret = -ENOMEM;
 		goto err;
 	}
-	platform_set_drvdata(pdev, mux);
-
-	mux->dev = &pdev->dev;
 
 	mux->pdata = dev_get_platdata(&pdev->dev);
 	if (!mux->pdata) {
@@ -166,14 +175,15 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	mux->busses = devm_kzalloc(&pdev->dev,
-				   sizeof(*mux->busses) * mux->pdata->bus_count,
-				   GFP_KERNEL);
-	if (!mux->busses) {
-		dev_err(&pdev->dev, "Cannot allocate busses\n");
+	muxc = i2c_mux_alloc(NULL, &pdev->dev, mux->pdata->bus_count, 0, 0,
+			     i2c_mux_pinctrl_select, NULL);
+	if (!muxc) {
 		ret = -ENOMEM;
 		goto err;
 	}
+	muxc->priv = mux;
+
+	platform_set_drvdata(pdev, muxc);
 
 	mux->pinctrl = devm_pinctrl_get(&pdev->dev);
 	if (IS_ERR(mux->pinctrl)) {
@@ -184,13 +194,13 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 	for (i = 0; i < mux->pdata->bus_count; i++) {
 		mux->states[i] = pinctrl_lookup_state(mux->pinctrl,
 						mux->pdata->pinctrl_states[i]);
-			if (IS_ERR(mux->states[i])) {
-				ret = PTR_ERR(mux->states[i]);
-				dev_err(&pdev->dev,
-					"Cannot look up pinctrl state %s: %d\n",
-					mux->pdata->pinctrl_states[i], ret);
-				goto err;
-			}
+		if (IS_ERR(mux->states[i])) {
+			ret = PTR_ERR(mux->states[i]);
+			dev_err(&pdev->dev,
+				"Cannot look up pinctrl state %s: %d\n",
+				mux->pdata->pinctrl_states[i], ret);
+			goto err;
+		}
 	}
 	if (mux->pdata->pinctrl_state_idle) {
 		mux->state_idle = pinctrl_lookup_state(mux->pinctrl,
@@ -203,29 +213,39 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 			goto err;
 		}
 
-		deselect = i2c_mux_pinctrl_deselect;
-	} else {
-		deselect = NULL;
+		muxc->deselect = i2c_mux_pinctrl_deselect;
 	}
 
-	mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
-	if (!mux->parent) {
+	muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
+	if (!muxc->parent) {
 		dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
 			mux->pdata->parent_bus_num);
 		ret = -EPROBE_DEFER;
 		goto err;
 	}
 
+	root = i2c_root_adapter(&muxc->parent->dev);
+
+	muxc->mux_locked = true;
+	for (i = 0; i < mux->pdata->bus_count; i++) {
+		if (root != i2c_mux_pinctrl_root_adapter(mux->states[i])) {
+			muxc->mux_locked = false;
+			break;
+		}
+	}
+	if (muxc->mux_locked && mux->pdata->pinctrl_state_idle &&
+	    root != i2c_mux_pinctrl_root_adapter(mux->state_idle))
+		muxc->mux_locked = false;
+
+	if (muxc->mux_locked)
+		dev_info(&pdev->dev, "mux-locked i2c mux\n");
+
 	for (i = 0; i < mux->pdata->bus_count; i++) {
 		u32 bus = mux->pdata->base_bus_num ?
 				(mux->pdata->base_bus_num + i) : 0;
 
-		mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
-						     mux, bus, i, 0,
-						     i2c_mux_pinctrl_select,
-						     deselect);
-		if (!mux->busses[i]) {
-			ret = -ENODEV;
+		ret = i2c_mux_add_adapter(muxc, bus, i, 0);
+		if (ret) {
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
 			goto err_del_adapter;
 		}
@@ -234,23 +254,18 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 	return 0;
 
 err_del_adapter:
-	for (; i > 0; i--)
-		i2c_del_mux_adapter(mux->busses[i - 1]);
-	i2c_put_adapter(mux->parent);
+	i2c_mux_del_adapters(muxc);
+	i2c_put_adapter(muxc->parent);
 err:
 	return ret;
 }
 
 static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
 {
-	struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev);
-	int i;
-
-	for (i = 0; i < mux->pdata->bus_count; i++)
-		i2c_del_mux_adapter(mux->busses[i]);
-
-	i2c_put_adapter(mux->parent);
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
 
+	i2c_mux_del_adapters(muxc);
+	i2c_put_adapter(muxc->parent);
 	return 0;
 }
 
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index 49fc2c7..c6a90b4 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -21,8 +21,6 @@
 #include <linux/slab.h>
 
 struct regmux {
-	struct i2c_adapter *parent;
-	struct i2c_adapter **adap; /* child busses */
 	struct i2c_mux_reg_platform_data data;
 };
 
@@ -64,18 +62,16 @@ static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id)
 	return 0;
 }
 
-static int i2c_mux_reg_select(struct i2c_adapter *adap, void *data,
-			      unsigned int chan)
+static int i2c_mux_reg_select(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct regmux *mux = data;
+	struct regmux *mux = i2c_mux_priv(muxc);
 
 	return i2c_mux_reg_set(mux, chan);
 }
 
-static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
-				unsigned int chan)
+static int i2c_mux_reg_deselect(struct i2c_mux_core *muxc, u32 chan)
 {
-	struct regmux *mux = data;
+	struct regmux *mux = i2c_mux_priv(muxc);
 
 	if (mux->data.idle_in_use)
 		return i2c_mux_reg_set(mux, mux->data.idle);
@@ -85,7 +81,7 @@ static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
 
 #ifdef CONFIG_OF
 static int i2c_mux_reg_probe_dt(struct regmux *mux,
-					struct platform_device *pdev)
+				struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *adapter_np, *child;
@@ -107,7 +103,6 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
 	if (!adapter)
 		return -EPROBE_DEFER;
 
-	mux->parent = adapter;
 	mux->data.parent = i2c_adapter_id(adapter);
 	put_device(&adapter->dev);
 
@@ -161,7 +156,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
 }
 #else
 static int i2c_mux_reg_probe_dt(struct regmux *mux,
-					struct platform_device *pdev)
+				struct platform_device *pdev)
 {
 	return 0;
 }
@@ -169,10 +164,10 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
 
 static int i2c_mux_reg_probe(struct platform_device *pdev)
 {
+	struct i2c_mux_core *muxc;
 	struct regmux *mux;
 	struct i2c_adapter *parent;
 	struct resource *res;
-	int (*deselect)(struct i2c_adapter *, void *, u32);
 	unsigned int class;
 	int i, ret, nr;
 
@@ -180,17 +175,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 	if (!mux)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, mux);
-
 	if (dev_get_platdata(&pdev->dev)) {
 		memcpy(&mux->data, dev_get_platdata(&pdev->dev),
 			sizeof(mux->data));
-
-		parent = i2c_get_adapter(mux->data.parent);
-		if (!parent)
-			return -EPROBE_DEFER;
-
-		mux->parent = parent;
 	} else {
 		ret = i2c_mux_reg_probe_dt(mux, pdev);
 		if (ret < 0) {
@@ -199,6 +186,10 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 		}
 	}
 
+	parent = i2c_get_adapter(mux->data.parent);
+	if (!parent)
+		return -EPROBE_DEFER;
+
 	if (!mux->data.reg) {
 		dev_info(&pdev->dev,
 			"Register not set, using platform resource\n");
@@ -215,55 +206,45 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	mux->adap = devm_kzalloc(&pdev->dev,
-				 sizeof(*mux->adap) * mux->data.n_values,
-				 GFP_KERNEL);
-	if (!mux->adap) {
-		dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
+	muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
+			     i2c_mux_reg_select, NULL);
+	if (!muxc)
 		return -ENOMEM;
-	}
+	muxc->priv = mux;
+
+	platform_set_drvdata(pdev, muxc);
 
 	if (mux->data.idle_in_use)
-		deselect = i2c_mux_reg_deselect;
-	else
-		deselect = NULL;
+		muxc->deselect = i2c_mux_reg_deselect;
 
 	for (i = 0; i < mux->data.n_values; i++) {
 		nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
 		class = mux->data.classes ? mux->data.classes[i] : 0;
 
-		mux->adap[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev, mux,
-						   nr, mux->data.values[i],
-						   class, i2c_mux_reg_select,
-						   deselect);
-		if (!mux->adap[i]) {
-			ret = -ENODEV;
+		ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
+		if (ret) {
 			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
 			goto add_adapter_failed;
 		}
 	}
 
 	dev_dbg(&pdev->dev, "%d port mux on %s adapter\n",
-		 mux->data.n_values, mux->parent->name);
+		 mux->data.n_values, muxc->parent->name);
 
 	return 0;
 
 add_adapter_failed:
-	for (; i > 0; i--)
-		i2c_del_mux_adapter(mux->adap[i - 1]);
+	i2c_mux_del_adapters(muxc);
 
 	return ret;
 }
 
 static int i2c_mux_reg_remove(struct platform_device *pdev)
 {
-	struct regmux *mux = platform_get_drvdata(pdev);
-	int i;
-
-	for (i = 0; i < mux->data.n_values; i++)
-		i2c_del_mux_adapter(mux->adap[i]);
+	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
 
-	i2c_put_adapter(mux->parent);
+	i2c_mux_del_adapters(muxc);
+	i2c_put_adapter(muxc->parent);
 
 	return 0;
 }
@@ -279,6 +260,7 @@ static struct platform_driver i2c_mux_reg_driver = {
 	.remove	= i2c_mux_reg_remove,
 	.driver	= {
 		.name	= "i2c-mux-reg",
+		.of_match_table = of_match_ptr(i2c_mux_reg_of_match),
 	},
 };
 
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 505e921..6743b18 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -46,6 +46,14 @@ config IIO_CONSUMERS_PER_TRIGGER
 	This value controls the maximum number of consumers that a
 	given trigger may handle. Default is 2.
 
+config IIO_SW_DEVICE
+	tristate "Enable software IIO device support"
+	select IIO_CONFIGFS
+	help
+	 Provides IIO core support for software devices. A software
+	 device can be created via configfs or directly by a driver
+	 using the API provided.
+
 config IIO_SW_TRIGGER
 	tristate "Enable software triggers support"
 	select IIO_CONFIGFS
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 20f6490..87e4c43 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -8,6 +8,7 @@ industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
 industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
 
 obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o
+obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o
 obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o
 obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
 
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index b0d3ecf..89d7820 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -17,6 +17,16 @@ config BMA180
 	  To compile this driver as a module, choose M here: the
 	  module will be called bma180.
 
+config BMA220
+    tristate "Bosch BMA220 3-Axis Accelerometer Driver"
+	depends on SPI
+    help
+      Say yes here to add support for the Bosch BMA220 triaxial
+      acceleration sensor.
+
+      To compile this driver as a module, choose M here: the
+      module will be called bma220_spi.
+
 config BMC150_ACCEL
 	tristate "Bosch BMC150 Accelerometer Driver"
 	select IIO_BUFFER
@@ -64,7 +74,7 @@ config IIO_ST_ACCEL_3AXIS
 	help
 	  Say yes here to build support for STMicroelectronics accelerometers:
 	  LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
-	  LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12.
+	  LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL.
 
 	  This driver can also be built as a module. If so, these modules
 	  will be created:
@@ -136,14 +146,25 @@ config MMA7455_SPI
 	  To compile this driver as a module, choose M here: the module
 	  will be called mma7455_spi.
 
+config MMA7660
+	tristate "Freescale MMA7660FC 3-Axis Accelerometer Driver"
+	depends on I2C
+	help
+	  Say yes here to get support for the Freescale MMA7660FC 3-Axis
+	  accelerometer.
+
+	  Choosing M will build the driver as a module. If so, the module
+	  will be called mma7660.
+
 config MMA8452
-	tristate "Freescale MMA8452Q and similar Accelerometers Driver"
+	tristate "Freescale / NXP MMA8452Q and similar Accelerometers Driver"
 	depends on I2C
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	help
-	  Say yes here to build support for the following Freescale 3-axis
-	  accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC.
+	  Say yes here to build support for the following Freescale / NXP 3-axis
+	  accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC,
+	  FXLS8471Q.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called mma8452.
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 71b6794..6cedbec 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -4,6 +4,7 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_BMA180) += bma180.o
+obj-$(CONFIG_BMA220) += bma220_spi.o
 obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
 obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
 obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
@@ -15,6 +16,8 @@ obj-$(CONFIG_MMA7455)		+= mma7455_core.o
 obj-$(CONFIG_MMA7455_I2C)	+= mma7455_i2c.o
 obj-$(CONFIG_MMA7455_SPI)	+= mma7455_spi.o
 
+obj-$(CONFIG_MMA7660)	+= mma7660.o
+
 obj-$(CONFIG_MMA8452)	+= mma8452.o
 
 obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index f04b884..e3f88ba 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -654,7 +654,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct bma180_data *data = iio_priv(indio_dev);
-	int64_t time_ns = iio_get_time_ns();
+	s64 time_ns = iio_get_time_ns(indio_dev);
 	int bit, ret, i = 0;
 
 	mutex_lock(&data->mutex);
diff --git b/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c
new file mode 100644
index 0000000..1098d10
--- /dev/null
+++ b/drivers/iio/accel/bma220_spi.c
@@ -0,0 +1,338 @@
+/**
+ * BMA220 Digital triaxial acceleration sensor driver
+ *
+ * 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.
+ */
+
+#include <linux/acpi.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/spi/spi.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define BMA220_REG_ID				0x00
+#define BMA220_REG_ACCEL_X			0x02
+#define BMA220_REG_ACCEL_Y			0x03
+#define BMA220_REG_ACCEL_Z			0x04
+#define BMA220_REG_RANGE			0x11
+#define BMA220_REG_SUSPEND			0x18
+
+#define BMA220_CHIP_ID				0xDD
+#define BMA220_READ_MASK			0x80
+#define BMA220_RANGE_MASK			0x03
+#define BMA220_DATA_SHIFT			2
+#define BMA220_SUSPEND_SLEEP			0xFF
+#define BMA220_SUSPEND_WAKE			0x00
+
+#define BMA220_DEVICE_NAME			"bma220"
+#define BMA220_SCALE_AVAILABLE			"0.623 1.248 2.491 4.983"
+
+#define BMA220_ACCEL_CHANNEL(index, reg, axis) {			\
+	.type = IIO_ACCEL,						\
+	.address = reg,							\
+	.modified = 1,							\
+	.channel2 = IIO_MOD_##axis,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\
+	.scan_index = index,						\
+	.scan_type = {							\
+		.sign = 's',						\
+		.realbits = 6,						\
+		.storagebits = 8,					\
+		.shift = BMA220_DATA_SHIFT,				\
+		.endianness = IIO_CPU,					\
+	},								\
+}
+
+enum bma220_axis {
+	AXIS_X,
+	AXIS_Y,
+	AXIS_Z,
+};
+
+static IIO_CONST_ATTR(in_accel_scale_available, BMA220_SCALE_AVAILABLE);
+
+static struct attribute *bma220_attributes[] = {
+	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group bma220_attribute_group = {
+	.attrs = bma220_attributes,
+};
+
+static const int bma220_scale_table[][4] = {
+	{0, 623000}, {1, 248000}, {2, 491000}, {4, 983000}
+};
+
+struct bma220_data {
+	struct spi_device *spi_device;
+	struct mutex lock;
+	s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */
+	u8 tx_buf[2] ____cacheline_aligned;
+};
+
+static const struct iio_chan_spec bma220_channels[] = {
+	BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X),
+	BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y),
+	BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static inline int bma220_read_reg(struct spi_device *spi, u8 reg)
+{
+	return spi_w8r8(spi, reg | BMA220_READ_MASK);
+}
+
+static const unsigned long bma220_accel_scan_masks[] = {
+	BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
+	0
+};
+
+static irqreturn_t bma220_trigger_handler(int irq, void *p)
+{
+	int ret;
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct bma220_data *data = iio_priv(indio_dev);
+	struct spi_device *spi = data->spi_device;
+
+	mutex_lock(&data->lock);
+	data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK;
+	ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer,
+				  ARRAY_SIZE(bma220_channels) - 1);
+	if (ret < 0)
+		goto err;
+
+	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+					   pf->timestamp);
+err:
+	mutex_unlock(&data->lock);
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static int bma220_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	int ret;
+	u8 range_idx;
+	struct bma220_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = bma220_read_reg(data->spi_device, chan->address);
+		if (ret < 0)
+			return -EINVAL;
+		*val = sign_extend32(ret >> BMA220_DATA_SHIFT, 5);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		ret = bma220_read_reg(data->spi_device, BMA220_REG_RANGE);
+		if (ret < 0)
+			return ret;
+		range_idx = ret & BMA220_RANGE_MASK;
+		*val = bma220_scale_table[range_idx][0];
+		*val2 = bma220_scale_table[range_idx][1];
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+
+	return -EINVAL;
+}
+
+static int bma220_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	int i;
+	int ret;
+	int index = -1;
+	struct bma220_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		for (i = 0; i < ARRAY_SIZE(bma220_scale_table); i++)
+			if (val == bma220_scale_table[i][0] &&
+			    val2 == bma220_scale_table[i][1]) {
+				index = i;
+				break;
+			}
+		if (index < 0)
+			return -EINVAL;
+
+		mutex_lock(&data->lock);
+		data->tx_buf[0] = BMA220_REG_RANGE;
+		data->tx_buf[1] = index;
+		ret = spi_write(data->spi_device, data->tx_buf,
+				sizeof(data->tx_buf));
+		if (ret < 0)
+			dev_err(&data->spi_device->dev,
+				"failed to set measurement range\n");
+		mutex_unlock(&data->lock);
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info bma220_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= bma220_read_raw,
+	.write_raw		= bma220_write_raw,
+	.attrs			= &bma220_attribute_group,
+};
+
+static int bma220_init(struct spi_device *spi)
+{
+	int ret;
+
+	ret = bma220_read_reg(spi, BMA220_REG_ID);
+	if (ret != BMA220_CHIP_ID)
+		return -ENODEV;
+
+	/* Make sure the chip is powered on */
+	ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
+	if (ret < 0)
+		return ret;
+	else if (ret == BMA220_SUSPEND_WAKE)
+		return bma220_read_reg(spi, BMA220_REG_SUSPEND);
+
+	return 0;
+}
+
+static int bma220_deinit(struct spi_device *spi)
+{
+	int ret;
+
+	/* Make sure the chip is powered off */
+	ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
+	if (ret < 0)
+		return ret;
+	else if (ret == BMA220_SUSPEND_SLEEP)
+		return bma220_read_reg(spi, BMA220_REG_SUSPEND);
+
+	return 0;
+}
+
+static int bma220_probe(struct spi_device *spi)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct bma220_data *data;
+
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
+	if (!indio_dev) {
+		dev_err(&spi->dev, "iio allocation failed!\n");
+		return -ENOMEM;
+	}
+
+	data = iio_priv(indio_dev);
+	data->spi_device = spi;
+	spi_set_drvdata(spi, indio_dev);
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->info = &bma220_info;
+	indio_dev->name = BMA220_DEVICE_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = bma220_channels;
+	indio_dev->num_channels = ARRAY_SIZE(bma220_channels);
+	indio_dev->available_scan_masks = bma220_accel_scan_masks;
+
+	ret = bma220_init(data->spi_device);
+	if (ret < 0)
+		return ret;
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+					 bma220_trigger_handler, NULL);
+	if (ret < 0) {
+		dev_err(&spi->dev, "iio triggered buffer setup failed\n");
+		goto err_suspend;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&spi->dev, "iio_device_register failed\n");
+		iio_triggered_buffer_cleanup(indio_dev);
+		goto err_suspend;
+	}
+
+	return 0;
+
+err_suspend:
+	return bma220_deinit(spi);
+}
+
+static int bma220_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+
+	return bma220_deinit(spi);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bma220_suspend(struct device *dev)
+{
+	struct bma220_data *data =
+			iio_priv(spi_get_drvdata(to_spi_device(dev)));
+
+	/* The chip can be suspended/woken up by a simple register read. */
+	return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
+}
+
+static int bma220_resume(struct device *dev)
+{
+	struct bma220_data *data =
+			iio_priv(spi_get_drvdata(to_spi_device(dev)));
+
+	return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
+}
+
+static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume);
+
+#define BMA220_PM_OPS (&bma220_pm_ops)
+#else
+#define BMA220_PM_OPS NULL
+#endif
+
+static const struct spi_device_id bma220_spi_id[] = {
+	{"bma220", 0},
+	{}
+};
+
+static const struct acpi_device_id bma220_acpi_id[] = {
+	{"BMA0220", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(spi, bma220_spi_id);
+
+static struct spi_driver bma220_driver = {
+	.driver = {
+		.name = "bma220_spi",
+		.pm = BMA220_PM_OPS,
+		.acpi_match_table = ACPI_PTR(bma220_acpi_id),
+	},
+	.probe =            bma220_probe,
+	.remove =           bma220_remove,
+	.id_table =         bma220_spi_id,
+};
+
+module_spi_driver(bma220_driver);
+
+MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
+MODULE_DESCRIPTION("BMA220 acceleration sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 2072a31..bf17aae 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -25,7 +25,6 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/iio/iio.h>
@@ -138,6 +137,7 @@ enum bmc150_accel_axis {
 	AXIS_X,
 	AXIS_Y,
 	AXIS_Z,
+	AXIS_MAX,
 };
 
 enum bmc150_power_modes {
@@ -188,7 +188,6 @@ enum bmc150_accel_trigger_id {
 
 struct bmc150_accel_data {
 	struct regmap *regmap;
-	struct device *dev;
 	int irq;
 	struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
 	atomic_t active_intr;
@@ -246,16 +245,18 @@ static const struct {
 				       {500000, BMC150_ACCEL_SLEEP_500_MS},
 				       {1000000, BMC150_ACCEL_SLEEP_1_SEC} };
 
-static const struct regmap_config bmc150_i2c_regmap_conf = {
+const struct regmap_config bmc150_regmap_conf = {
 	.reg_bits = 8,
 	.val_bits = 8,
 	.max_register = 0x3f,
 };
+EXPORT_SYMBOL_GPL(bmc150_regmap_conf);
 
 static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
 				 enum bmc150_power_modes mode,
 				 int dur_us)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int i;
 	int ret;
 	u8 lpw_bits;
@@ -279,11 +280,11 @@ static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
 	lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT;
 	lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT);
 
-	dev_dbg(data->dev, "Set Mode bits %x\n", lpw_bits);
+	dev_dbg(dev, "Set Mode bits %x\n", lpw_bits);
 
 	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_LPW, lpw_bits);
 	if (ret < 0) {
-		dev_err(data->dev, "Error writing reg_pmu_lpw\n");
+		dev_err(dev, "Error writing reg_pmu_lpw\n");
 		return ret;
 	}
 
@@ -316,23 +317,24 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
 
 static int bmc150_accel_update_slope(struct bmc150_accel_data *data)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 
 	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_6,
 					data->slope_thres);
 	if (ret < 0) {
-		dev_err(data->dev, "Error writing reg_int_6\n");
+		dev_err(dev, "Error writing reg_int_6\n");
 		return ret;
 	}
 
 	ret = regmap_update_bits(data->regmap, BMC150_ACCEL_REG_INT_5,
 				 BMC150_ACCEL_SLOPE_DUR_MASK, data->slope_dur);
 	if (ret < 0) {
-		dev_err(data->dev, "Error updating reg_int_5\n");
+		dev_err(dev, "Error updating reg_int_5\n");
 		return ret;
 	}
 
-	dev_dbg(data->dev, "%s: %x %x\n", __func__, data->slope_thres,
+	dev_dbg(dev, "%s: %x %x\n", __func__, data->slope_thres,
 		data->slope_dur);
 
 	return ret;
@@ -378,20 +380,21 @@ static int bmc150_accel_get_startup_times(struct bmc150_accel_data *data)
 
 static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 
 	if (on) {
-		ret = pm_runtime_get_sync(data->dev);
+		ret = pm_runtime_get_sync(dev);
 	} else {
-		pm_runtime_mark_last_busy(data->dev);
-		ret = pm_runtime_put_autosuspend(data->dev);
+		pm_runtime_mark_last_busy(dev);
+		ret = pm_runtime_put_autosuspend(dev);
 	}
 
 	if (ret < 0) {
-		dev_err(data->dev,
+		dev_err(dev,
 			"Failed: bmc150_accel_set_power_state for %d\n", on);
 		if (on)
-			pm_runtime_put_noidle(data->dev);
+			pm_runtime_put_noidle(dev);
 
 		return ret;
 	}
@@ -445,6 +448,7 @@ static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
 static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
 				      bool state)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	struct bmc150_accel_interrupt *intr = &data->interrupts[i];
 	const struct bmc150_accel_interrupt_info *info = intr->info;
 	int ret;
@@ -474,7 +478,7 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
 	ret = regmap_update_bits(data->regmap, info->map_reg, info->map_bitmask,
 				 (state ? info->map_bitmask : 0));
 	if (ret < 0) {
-		dev_err(data->dev, "Error updating reg_int_map\n");
+		dev_err(dev, "Error updating reg_int_map\n");
 		goto out_fix_power_state;
 	}
 
@@ -482,7 +486,7 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
 	ret = regmap_update_bits(data->regmap, info->en_reg, info->en_bitmask,
 				 (state ? info->en_bitmask : 0));
 	if (ret < 0) {
-		dev_err(data->dev, "Error updating reg_int_en\n");
+		dev_err(dev, "Error updating reg_int_en\n");
 		goto out_fix_power_state;
 	}
 
@@ -500,6 +504,7 @@ out_fix_power_state:
 
 static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret, i;
 
 	for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) {
@@ -508,8 +513,7 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
 				     BMC150_ACCEL_REG_PMU_RANGE,
 				     data->chip_info->scale_table[i].reg_range);
 			if (ret < 0) {
-				dev_err(data->dev,
-					"Error writing pmu_range\n");
+				dev_err(dev, "Error writing pmu_range\n");
 				return ret;
 			}
 
@@ -523,6 +527,7 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
 
 static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 	unsigned int value;
 
@@ -530,7 +535,7 @@ static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val)
 
 	ret = regmap_read(data->regmap, BMC150_ACCEL_REG_TEMP, &value);
 	if (ret < 0) {
-		dev_err(data->dev, "Error reading reg_temp\n");
+		dev_err(dev, "Error reading reg_temp\n");
 		mutex_unlock(&data->mutex);
 		return ret;
 	}
@@ -545,6 +550,7 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
 				 struct iio_chan_spec const *chan,
 				 int *val)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 	int axis = chan->scan_index;
 	__le16 raw_val;
@@ -559,7 +565,7 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
 	ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis),
 			       &raw_val, sizeof(raw_val));
 	if (ret < 0) {
-		dev_err(data->dev, "Error reading axis %d\n", axis);
+		dev_err(dev, "Error reading axis %d\n", axis);
 		bmc150_accel_set_power_state(data, false);
 		mutex_unlock(&data->mutex);
 		return ret;
@@ -831,6 +837,7 @@ static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val)
 static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data,
 				      char *buffer, int samples)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int sample_length = 3 * 2;
 	int ret;
 	int total_length = samples * sample_length;
@@ -854,7 +861,8 @@ static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data,
 	}
 
 	if (ret)
-		dev_err(data->dev, "Error transferring data from fifo in single steps of %zu\n",
+		dev_err(dev,
+			"Error transferring data from fifo in single steps of %zu\n",
 			step);
 
 	return ret;
@@ -864,6 +872,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
 				     unsigned samples, bool irq)
 {
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret, i;
 	u8 count;
 	u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
@@ -873,7 +882,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
 
 	ret = regmap_read(data->regmap, BMC150_ACCEL_REG_FIFO_STATUS, &val);
 	if (ret < 0) {
-		dev_err(data->dev, "Error reading reg_fifo_status\n");
+		dev_err(dev, "Error reading reg_fifo_status\n");
 		return ret;
 	}
 
@@ -892,7 +901,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
 	 */
 	if (!irq) {
 		data->old_timestamp = data->timestamp;
-		data->timestamp = iio_get_time_ns();
+		data->timestamp = iio_get_time_ns(indio_dev);
 	}
 
 	/*
@@ -1105,27 +1114,23 @@ static const struct iio_info bmc150_accel_info_fifo = {
 	.driver_module		= THIS_MODULE,
 };
 
+static const unsigned long bmc150_accel_scan_masks[] = {
+					BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
+					0};
+
 static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
 {
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
-	int bit, ret, i = 0;
-	unsigned int raw_val;
+	int ret;
 
 	mutex_lock(&data->mutex);
-	for_each_set_bit(bit, indio_dev->active_scan_mask,
-			 indio_dev->masklength) {
-		ret = regmap_bulk_read(data->regmap,
-				       BMC150_ACCEL_AXIS_TO_REG(bit), &raw_val,
-				       2);
-		if (ret < 0) {
-			mutex_unlock(&data->mutex);
-			goto err_read;
-		}
-		data->buffer[i++] = raw_val;
-	}
+	ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_REG_XOUT_L,
+			       data->buffer, AXIS_MAX * 2);
 	mutex_unlock(&data->mutex);
+	if (ret < 0)
+		goto err_read;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
 					   pf->timestamp);
@@ -1139,6 +1144,7 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
 {
 	struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
 	struct bmc150_accel_data *data = t->data;
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 
 	/* new data interrupts don't need ack */
@@ -1152,8 +1158,7 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
 			   BMC150_ACCEL_INT_MODE_LATCH_RESET);
 	mutex_unlock(&data->mutex);
 	if (ret < 0) {
-		dev_err(data->dev,
-			"Error writing reg_int_rst_latch\n");
+		dev_err(dev, "Error writing reg_int_rst_latch\n");
 		return ret;
 	}
 
@@ -1204,13 +1209,14 @@ static const struct iio_trigger_ops bmc150_accel_trigger_ops = {
 static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
 {
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(data->regmap);
 	int dir;
 	int ret;
 	unsigned int val;
 
 	ret = regmap_read(data->regmap, BMC150_ACCEL_REG_INT_STATUS_2, &val);
 	if (ret < 0) {
-		dev_err(data->dev, "Error reading reg_int_status_2\n");
+		dev_err(dev, "Error reading reg_int_status_2\n");
 		return ret;
 	}
 
@@ -1253,6 +1259,7 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
 {
 	struct iio_dev *indio_dev = private;
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(data->regmap);
 	bool ack = false;
 	int ret;
 
@@ -1276,7 +1283,7 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
 				   BMC150_ACCEL_INT_MODE_LATCH_INT |
 				   BMC150_ACCEL_INT_MODE_LATCH_RESET);
 		if (ret)
-			dev_err(data->dev, "Error writing reg_int_rst_latch\n");
+			dev_err(dev, "Error writing reg_int_rst_latch\n");
 
 		ret = IRQ_HANDLED;
 	} else {
@@ -1296,7 +1303,7 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private)
 	int i;
 
 	data->old_timestamp = data->timestamp;
-	data->timestamp = iio_get_time_ns();
+	data->timestamp = iio_get_time_ns(indio_dev);
 
 	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
 		if (data->triggers[i].enabled) {
@@ -1347,13 +1354,14 @@ static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data,
 static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
 				       struct bmc150_accel_data *data)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int i, ret;
 
 	for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
 		struct bmc150_accel_trigger *t = &data->triggers[i];
 
-		t->indio_trig = devm_iio_trigger_alloc(data->dev,
-					       bmc150_accel_triggers[i].name,
+		t->indio_trig = devm_iio_trigger_alloc(dev,
+					bmc150_accel_triggers[i].name,
 						       indio_dev->name,
 						       indio_dev->id);
 		if (!t->indio_trig) {
@@ -1361,7 +1369,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
 			break;
 		}
 
-		t->indio_trig->dev.parent = data->dev;
+		t->indio_trig->dev.parent = dev;
 		t->indio_trig->ops = &bmc150_accel_trigger_ops;
 		t->intr = bmc150_accel_triggers[i].intr;
 		t->data = data;
@@ -1385,12 +1393,13 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
 
 static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
 	int ret;
 
 	ret = regmap_write(data->regmap, reg, data->fifo_mode);
 	if (ret < 0) {
-		dev_err(data->dev, "Error writing reg_fifo_config1\n");
+		dev_err(dev, "Error writing reg_fifo_config1\n");
 		return ret;
 	}
 
@@ -1400,7 +1409,7 @@ static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
 	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_FIFO_CONFIG0,
 			   data->watermark);
 	if (ret < 0)
-		dev_err(data->dev, "Error writing reg_fifo_config0\n");
+		dev_err(dev, "Error writing reg_fifo_config0\n");
 
 	return ret;
 }
@@ -1484,17 +1493,17 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
 
 static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret, i;
 	unsigned int val;
 
 	ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val);
 	if (ret < 0) {
-		dev_err(data->dev,
-			"Error: Reading chip id\n");
+		dev_err(dev, "Error: Reading chip id\n");
 		return ret;
 	}
 
-	dev_dbg(data->dev, "Chip Id %x\n", val);
+	dev_dbg(dev, "Chip Id %x\n", val);
 	for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) {
 		if (bmc150_accel_chip_info_tbl[i].chip_id == val) {
 			data->chip_info = &bmc150_accel_chip_info_tbl[i];
@@ -1503,7 +1512,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
 	}
 
 	if (!data->chip_info) {
-		dev_err(data->dev, "Invalid chip %x\n", val);
+		dev_err(dev, "Invalid chip %x\n", val);
 		return -ENODEV;
 	}
 
@@ -1520,8 +1529,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
 	ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE,
 			   BMC150_ACCEL_DEF_RANGE_4G);
 	if (ret < 0) {
-		dev_err(data->dev,
-					"Error writing reg_pmu_range\n");
+		dev_err(dev, "Error writing reg_pmu_range\n");
 		return ret;
 	}
 
@@ -1539,8 +1547,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
 			   BMC150_ACCEL_INT_MODE_LATCH_INT |
 			   BMC150_ACCEL_INT_MODE_LATCH_RESET);
 	if (ret < 0) {
-		dev_err(data->dev,
-			"Error writing reg_int_rst_latch\n");
+		dev_err(dev, "Error writing reg_int_rst_latch\n");
 		return ret;
 	}
 
@@ -1560,7 +1567,6 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
 
 	data = iio_priv(indio_dev);
 	dev_set_drvdata(dev, indio_dev);
-	data->dev = dev;
 	data->irq = irq;
 
 	data->regmap = regmap;
@@ -1575,6 +1581,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
 	indio_dev->channels = data->chip_info->channels;
 	indio_dev->num_channels = data->chip_info->num_channels;
 	indio_dev->name = name ? name : data->chip_info->name;
+	indio_dev->available_scan_masks = bmc150_accel_scan_masks;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &bmc150_accel_info;
 
@@ -1583,13 +1590,13 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
 					 bmc150_accel_trigger_handler,
 					 &bmc150_accel_buffer_ops);
 	if (ret < 0) {
-		dev_err(data->dev, "Failed: iio triggered buffer setup\n");
+		dev_err(dev, "Failed: iio triggered buffer setup\n");
 		return ret;
 	}
 
 	if (data->irq > 0) {
 		ret = devm_request_threaded_irq(
-						data->dev, data->irq,
+						dev, data->irq,
 						bmc150_accel_irq_handler,
 						bmc150_accel_irq_thread_handler,
 						IRQF_TRIGGER_RISING,
@@ -1607,7 +1614,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
 		ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
 				   BMC150_ACCEL_INT_MODE_LATCH_RESET);
 		if (ret < 0) {
-			dev_err(data->dev, "Error writing reg_int_rst_latch\n");
+			dev_err(dev, "Error writing reg_int_rst_latch\n");
 			goto err_buffer_cleanup;
 		}
 
@@ -1656,9 +1663,9 @@ int bmc150_accel_core_remove(struct device *dev)
 
 	iio_device_unregister(indio_dev);
 
-	pm_runtime_disable(data->dev);
-	pm_runtime_set_suspended(data->dev);
-	pm_runtime_put_noidle(data->dev);
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_put_noidle(dev);
 
 	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
 
@@ -1707,7 +1714,7 @@ static int bmc150_accel_runtime_suspend(struct device *dev)
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
 	int ret;
 
-	dev_dbg(data->dev,  __func__);
+	dev_dbg(dev,  __func__);
 	ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
 	if (ret < 0)
 		return -EAGAIN;
@@ -1722,7 +1729,7 @@ static int bmc150_accel_runtime_resume(struct device *dev)
 	int ret;
 	int sleep_val;
 
-	dev_dbg(data->dev,  __func__);
+	dev_dbg(dev,  __func__);
 
 	ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
 	if (ret < 0)
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
index b41404b..8ca8041 100644
--- a/drivers/iio/accel/bmc150-accel-i2c.c
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -28,11 +28,6 @@
 
 #include "bmc150-accel.h"
 
-static const struct regmap_config bmc150_i2c_regmap_conf = {
-	.reg_bits = 8,
-	.val_bits = 8,
-};
-
 static int bmc150_accel_probe(struct i2c_client *client,
 			      const struct i2c_device_id *id)
 {
@@ -43,7 +38,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
 		i2c_check_functionality(client->adapter,
 					I2C_FUNC_SMBUS_READ_I2C_BLOCK);
 
-	regmap = devm_regmap_init_i2c(client, &bmc150_i2c_regmap_conf);
+	regmap = devm_regmap_init_i2c(client, &bmc150_regmap_conf);
 	if (IS_ERR(regmap)) {
 		dev_err(&client->dev, "Failed to initialize i2c regmap\n");
 		return PTR_ERR(regmap);
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
index 16b66f2..006794a 100644
--- a/drivers/iio/accel/bmc150-accel-spi.c
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -25,18 +25,12 @@
 
 #include "bmc150-accel.h"
 
-static const struct regmap_config bmc150_spi_regmap_conf = {
-	.reg_bits = 8,
-	.val_bits = 8,
-	.max_register = 0x3f,
-};
-
 static int bmc150_accel_probe(struct spi_device *spi)
 {
 	struct regmap *regmap;
 	const struct spi_device_id *id = spi_get_device_id(spi);
 
-	regmap = devm_regmap_init_spi(spi, &bmc150_spi_regmap_conf);
+	regmap = devm_regmap_init_spi(spi, &bmc150_regmap_conf);
 	if (IS_ERR(regmap)) {
 		dev_err(&spi->dev, "Failed to initialize spi regmap\n");
 		return PTR_ERR(regmap);
diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h
index ba03359..38a8b11 100644
--- a/drivers/iio/accel/bmc150-accel.h
+++ b/drivers/iio/accel/bmc150-accel.h
@@ -16,5 +16,6 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
 			    const char *name, bool block_supported);
 int bmc150_accel_core_remove(struct device *dev);
 extern const struct dev_pm_ops bmc150_accel_pm_ops;
+extern const struct regmap_config bmc150_regmap_conf;
 
 #endif  /* _BMC150_ACCEL_H_ */
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index edec1d0..765a723 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -20,7 +20,6 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/iio/iio.h>
@@ -115,6 +114,7 @@ enum kxcjk1013_axis {
 	AXIS_X,
 	AXIS_Y,
 	AXIS_Z,
+	AXIS_MAX,
 };
 
 enum kxcjk1013_mode {
@@ -922,7 +922,7 @@ static const struct iio_event_spec kxcjk1013_event = {
 		.realbits = 12,						\
 		.storagebits = 16,					\
 		.shift = 4,						\
-		.endianness = IIO_CPU,					\
+		.endianness = IIO_LE,					\
 	},								\
 	.event_spec = &kxcjk1013_event,				\
 	.num_event_specs = 1						\
@@ -953,25 +953,23 @@ static const struct iio_info kxcjk1013_info = {
 	.driver_module		= THIS_MODULE,
 };
 
+static const unsigned long kxcjk1013_scan_masks[] = {0x7, 0};
+
 static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
 {
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct kxcjk1013_data *data = iio_priv(indio_dev);
-	int bit, ret, i = 0;
+	int ret;
 
 	mutex_lock(&data->mutex);
-
-	for_each_set_bit(bit, indio_dev->active_scan_mask,
-			 indio_dev->masklength) {
-		ret = kxcjk1013_get_acc_reg(data, bit);
-		if (ret < 0) {
-			mutex_unlock(&data->mutex);
-			goto err;
-		}
-		data->buffer[i++] = ret;
-	}
+	ret = i2c_smbus_read_i2c_block_data_or_emulated(data->client,
+							KXCJK1013_REG_XOUT_L,
+							AXIS_MAX * 2,
+							(u8 *)data->buffer);
 	mutex_unlock(&data->mutex);
+	if (ret < 0)
+		goto err;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
 					   data->timestamp);
@@ -1131,7 +1129,7 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private)
 	struct iio_dev *indio_dev = private;
 	struct kxcjk1013_data *data = iio_priv(indio_dev);
 
-	data->timestamp = iio_get_time_ns();
+	data->timestamp = iio_get_time_ns(indio_dev);
 
 	if (data->dready_trigger_on)
 		iio_trigger_poll(data->dready_trig);
@@ -1204,6 +1202,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->channels = kxcjk1013_channels;
 	indio_dev->num_channels = ARRAY_SIZE(kxcjk1013_channels);
+	indio_dev->available_scan_masks = kxcjk1013_scan_masks;
 	indio_dev->name = name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &kxcjk1013_info;
diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c
index c633cc2..6551085 100644
--- a/drivers/iio/accel/mma7455_core.c
+++ b/drivers/iio/accel/mma7455_core.c
@@ -55,11 +55,11 @@
 
 struct mma7455_data {
 	struct regmap *regmap;
-	struct device *dev;
 };
 
 static int mma7455_drdy(struct mma7455_data *mma7455)
 {
+	struct device *dev = regmap_get_device(mma7455->regmap);
 	unsigned int reg;
 	int tries = 3;
 	int ret;
@@ -75,7 +75,7 @@ static int mma7455_drdy(struct mma7455_data *mma7455)
 		msleep(20);
 	}
 
-	dev_warn(mma7455->dev, "data not ready\n");
+	dev_warn(dev, "data not ready\n");
 
 	return -EIO;
 }
@@ -97,7 +97,8 @@ static irqreturn_t mma7455_trigger_handler(int irq, void *p)
 	if (ret)
 		goto done;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
+	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+					   iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -260,7 +261,6 @@ int mma7455_core_probe(struct device *dev, struct regmap *regmap,
 	dev_set_drvdata(dev, indio_dev);
 	mma7455 = iio_priv(indio_dev);
 	mma7455->regmap = regmap;
-	mma7455->dev = dev;
 
 	indio_dev->info = &mma7455_info;
 	indio_dev->name = name;
diff --git b/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c
new file mode 100644
index 0000000..0acdee5
--- /dev/null
+++ b/drivers/iio/accel/mma7660.c
@@ -0,0 +1,277 @@
+/**
+ * Freescale MMA7660FC 3-Axis Accelerometer
+ *
+ * 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.
+ *
+ * IIO driver for Freescale MMA7660FC; 7-bit I2C address: 0x4c.
+ */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define MMA7660_DRIVER_NAME	"mma7660"
+
+#define MMA7660_REG_XOUT	0x00
+#define MMA7660_REG_YOUT	0x01
+#define MMA7660_REG_ZOUT	0x02
+#define MMA7660_REG_OUT_BIT_ALERT	BIT(6)
+
+#define MMA7660_REG_MODE	0x07
+#define MMA7660_REG_MODE_BIT_MODE	BIT(0)
+#define MMA7660_REG_MODE_BIT_TON	BIT(2)
+
+#define MMA7660_I2C_READ_RETRIES	5
+
+/*
+ * The accelerometer has one measurement range:
+ *
+ * -1.5g - +1.5g (6-bit, signed)
+ *
+ * scale = (1.5 + 1.5) * 9.81 / (2^6 - 1)	= 0.467142857
+ */
+
+#define MMA7660_SCALE_AVAIL	"0.467142857"
+
+const int mma7660_nscale = 467142857;
+
+#define MMA7660_CHANNEL(reg, axis) {	\
+	.type = IIO_ACCEL,	\
+	.address = reg,	\
+	.modified = 1,	\
+	.channel2 = IIO_MOD_##axis,	\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+static const struct iio_chan_spec mma7660_channels[] = {
+	MMA7660_CHANNEL(MMA7660_REG_XOUT, X),
+	MMA7660_CHANNEL(MMA7660_REG_YOUT, Y),
+	MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z),
+};
+
+enum mma7660_mode {
+	MMA7660_MODE_STANDBY,
+	MMA7660_MODE_ACTIVE
+};
+
+struct mma7660_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	enum mma7660_mode mode;
+};
+
+static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL);
+
+static struct attribute *mma7660_attributes[] = {
+	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group mma7660_attribute_group = {
+	.attrs = mma7660_attributes
+};
+
+static int mma7660_set_mode(struct mma7660_data *data,
+				enum mma7660_mode mode)
+{
+	int ret;
+	struct i2c_client *client = data->client;
+
+	if (mode == data->mode)
+		return 0;
+
+	ret = i2c_smbus_read_byte_data(client, MMA7660_REG_MODE);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to read sensor mode\n");
+		return ret;
+	}
+
+	if (mode == MMA7660_MODE_ACTIVE) {
+		ret &= ~MMA7660_REG_MODE_BIT_TON;
+		ret |= MMA7660_REG_MODE_BIT_MODE;
+	} else {
+		ret &= ~MMA7660_REG_MODE_BIT_TON;
+		ret &= ~MMA7660_REG_MODE_BIT_MODE;
+	}
+
+	ret = i2c_smbus_write_byte_data(client, MMA7660_REG_MODE, ret);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to change sensor mode\n");
+		return ret;
+	}
+
+	data->mode = mode;
+
+	return ret;
+}
+
+static int mma7660_read_accel(struct mma7660_data *data, u8 address)
+{
+	int ret, retries = MMA7660_I2C_READ_RETRIES;
+	struct i2c_client *client = data->client;
+
+	/*
+	 * Read data. If the Alert bit is set, the register was read at
+	 * the same time as the device was attempting to update the content.
+	 * The solution is to read the register again. Do this only
+	 * MMA7660_I2C_READ_RETRIES times to avoid spending too much time
+	 * in the kernel.
+	 */
+	do {
+		ret = i2c_smbus_read_byte_data(client, address);
+		if (ret < 0) {
+			dev_err(&client->dev, "register read failed\n");
+			return ret;
+		}
+	} while (retries-- > 0 && ret & MMA7660_REG_OUT_BIT_ALERT);
+
+	if (ret & MMA7660_REG_OUT_BIT_ALERT) {
+		dev_err(&client->dev, "all register read retries failed\n");
+		return -ETIMEDOUT;
+	}
+
+	return ret;
+}
+
+static int mma7660_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct mma7660_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&data->lock);
+		ret = mma7660_read_accel(data, chan->address);
+		mutex_unlock(&data->lock);
+		if (ret < 0)
+			return ret;
+		*val = sign_extend32(ret, 5);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = mma7660_nscale;
+		return IIO_VAL_INT_PLUS_NANO;
+	default:
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info mma7660_info = {
+	.driver_module	= THIS_MODULE,
+	.read_raw		= mma7660_read_raw,
+	.attrs			= &mma7660_attribute_group,
+};
+
+static int mma7660_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct mma7660_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);
+	data->mode = MMA7660_MODE_STANDBY;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &mma7660_info;
+	indio_dev->name = MMA7660_DRIVER_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mma7660_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mma7660_channels);
+
+	ret = mma7660_set_mode(data, MMA7660_MODE_ACTIVE);
+	if (ret < 0)
+		return ret;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "device_register failed\n");
+		mma7660_set_mode(data, MMA7660_MODE_STANDBY);
+	}
+
+	return ret;
+}
+
+static int mma7660_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+
+	return mma7660_set_mode(iio_priv(indio_dev), MMA7660_MODE_STANDBY);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mma7660_suspend(struct device *dev)
+{
+	struct mma7660_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return mma7660_set_mode(data, MMA7660_MODE_STANDBY);
+}
+
+static int mma7660_resume(struct device *dev)
+{
+	struct mma7660_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return mma7660_set_mode(data, MMA7660_MODE_ACTIVE);
+}
+
+static SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, mma7660_resume);
+
+#define MMA7660_PM_OPS (&mma7660_pm_ops)
+#else
+#define MMA7660_PM_OPS NULL
+#endif
+
+static const struct i2c_device_id mma7660_i2c_id[] = {
+	{"mma7660", 0},
+	{}
+};
+
+static const struct acpi_device_id mma7660_acpi_id[] = {
+	{"MMA7660", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id);
+
+static struct i2c_driver mma7660_driver = {
+	.driver = {
+		.name = "mma7660",
+		.pm = MMA7660_PM_OPS,
+		.acpi_match_table = ACPI_PTR(mma7660_acpi_id),
+	},
+	.probe		= mma7660_probe,
+	.remove		= mma7660_remove,
+	.id_table	= mma7660_i2c_id,
+};
+
+module_i2c_driver(mma7660_driver);
+
+MODULE_AUTHOR("Constantin Musca <constantin.musca@intel.com>");
+MODULE_DESCRIPTION("Freescale MMA7660FC 3-Axis Accelerometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 7f4994f..d41e1b5 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1,22 +1,23 @@
 /*
- * mma8452.c - Support for following Freescale 3-axis accelerometers:
+ * mma8452.c - Support for following Freescale / NXP 3-axis accelerometers:
  *
- * MMA8451Q (14 bit)
- * MMA8452Q (12 bit)
- * MMA8453Q (10 bit)
- * MMA8652FC (12 bit)
- * MMA8653FC (10 bit)
+ * device name	digital output	7-bit I2C slave address (pin selectable)
+ * ---------------------------------------------------------------------
+ * MMA8451Q	14 bit		0x1c / 0x1d
+ * MMA8452Q	12 bit		0x1c / 0x1d
+ * MMA8453Q	10 bit		0x1c / 0x1d
+ * MMA8652FC	12 bit		0x1d
+ * MMA8653FC	10 bit		0x1d
+ * FXLS8471Q	14 bit		0x1e / 0x1d / 0x1c / 0x1f
  *
- * Copyright 2015 Martin Kepplinger <martin.kepplinger@theobroma-systems.com>
+ * Copyright 2015 Martin Kepplinger <martink@posteo.de>
  * Copyright 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 0x1c/0x1d (pin selectable)
- *
- * TODO: orientation events, autosleep
+ * TODO: orientation events
  */
 
 #include <linux/module.h>
@@ -31,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
+#include <linux/pm_runtime.h>
 
 #define MMA8452_STATUS				0x00
 #define  MMA8452_STATUS_DRDY			(BIT(2) | BIT(1) | BIT(0))
@@ -74,6 +76,8 @@
 #define  MMA8452_CTRL_DR_DEFAULT		0x4 /* 50 Hz sample frequency */
 #define MMA8452_CTRL_REG2			0x2b
 #define  MMA8452_CTRL_REG2_RST			BIT(6)
+#define  MMA8452_CTRL_REG2_MODS_SHIFT		3
+#define  MMA8452_CTRL_REG2_MODS_MASK		0x1b
 #define MMA8452_CTRL_REG4			0x2d
 #define MMA8452_CTRL_REG5			0x2e
 #define MMA8452_OFF_X				0x2f
@@ -91,6 +95,9 @@
 #define MMA8453_DEVICE_ID			0x3a
 #define MMA8652_DEVICE_ID			0x4a
 #define MMA8653_DEVICE_ID			0x5a
+#define FXLS8471_DEVICE_ID			0x6a
+
+#define MMA8452_AUTO_SUSPEND_DELAY_MS		2000
 
 struct mma8452_data {
 	struct i2c_client *client;
@@ -101,7 +108,7 @@ struct mma8452_data {
 };
 
 /**
- * struct mma_chip_info - chip specific data for Freescale's accelerometers
+ * struct mma_chip_info - chip specific data
  * @chip_id:			WHO_AM_I register's value
  * @channels:			struct iio_chan_spec matching the device's
  *				capabilities
@@ -172,6 +179,31 @@ static int mma8452_drdy(struct mma8452_data *data)
 	return -EIO;
 }
 
+static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
+{
+#ifdef CONFIG_PM
+	int ret;
+
+	if (on) {
+		ret = pm_runtime_get_sync(&client->dev);
+	} else {
+		pm_runtime_mark_last_busy(&client->dev);
+		ret = pm_runtime_put_autosuspend(&client->dev);
+	}
+
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"failed to change power state to %d\n", on);
+		if (on)
+			pm_runtime_put_noidle(&client->dev);
+
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
 static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
 {
 	int ret = mma8452_drdy(data);
@@ -179,8 +211,16 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
 	if (ret < 0)
 		return ret;
 
-	return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
-					     3 * sizeof(__be16), (u8 *)buf);
+	ret = mma8452_set_runtime_pm_state(data->client, true);
+	if (ret)
+		return ret;
+
+	ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
+					    3 * sizeof(__be16), (u8 *)buf);
+
+	ret = mma8452_set_runtime_pm_state(data->client, false);
+
+	return ret;
 }
 
 static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2],
@@ -219,20 +259,17 @@ static const int mma8452_samp_freq[8][2] = {
 	{6, 250000}, {1, 560000}
 };
 
-/* Datasheet table 35  (step time vs sample frequency) */
-static const int mma8452_transient_time_step_us[8] = {
-	1250,
-	2500,
-	5000,
-	10000,
-	20000,
-	20000,
-	20000,
-	20000
+/* Datasheet table: step time "Relationship with the ODR" (sample frequency) */
+static const int mma8452_transient_time_step_us[4][8] = {
+	{ 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 },  /* normal */
+	{ 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 },  /* l p l n */
+	{ 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 },	  /* high res*/
+	{ 1250, 2500, 5000, 10000, 20000, 80000, 160000, 160000 } /* l p */
 };
 
-/* Datasheet table 18 (normal mode) */
-static const int mma8452_hp_filter_cutoff[8][4][2] = {
+/* Datasheet table "High-Pass Filter Cutoff Options" */
+static const int mma8452_hp_filter_cutoff[4][8][4][2] = {
+	{ /* normal */
 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },		/* 800 Hz sample */
 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },		/* 400 Hz sample */
 	{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },		/* 200 Hz sample */
@@ -241,8 +278,61 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = {
 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 12.5 Hz sample */
 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 6.25 Hz sample */
 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }	/* 1.56 Hz sample */
+	},
+	{ /* low noise low power */
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },
+	{ {4, 0}, {2, 0}, {1, 0}, {0, 500000} },
+	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },
+	{ {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} },
+	{ {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} },
+	{ {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }
+	},
+	{ /* high resolution */
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} }
+	},
+	{ /* low power */
+	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
+	{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },
+	{ {4, 0}, {2, 0}, {1, 0}, {0, 500000} },
+	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },
+	{ {1, 0}, {0, 500000}, {0, 250000}, {0, 125000} },
+	{ {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} },
+	{ {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} },
+	{ {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }
+	}
 };
 
+/* Datasheet table "MODS Oversampling modes averaging values at each ODR" */
+static const u16 mma8452_os_ratio[4][8] = {
+	/* 800 Hz, 400 Hz, ... , 1.56 Hz */
+	{ 2, 4, 4, 4, 4, 16, 32, 128 },		/* normal */
+	{ 2, 4, 4, 4, 4, 4, 8, 32 },		/* low power low noise */
+	{ 2, 4, 8, 16, 32, 128, 256, 1024 },	/* high resolution */
+	{ 2, 2, 2, 2, 2, 2, 4, 16 }		/* low power */
+};
+
+static int mma8452_get_power_mode(struct mma8452_data *data)
+{
+	int reg;
+
+	reg = i2c_smbus_read_byte_data(data->client,
+				       MMA8452_CTRL_REG2);
+	if (reg < 0)
+		return reg;
+
+	return ((reg & MMA8452_CTRL_REG2_MODS_MASK) >>
+		MMA8452_CTRL_REG2_MODS_SHIFT);
+}
+
 static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
 					    struct device_attribute *attr,
 					    char *buf)
@@ -268,10 +358,39 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct mma8452_data *data = iio_priv(indio_dev);
+	int i, j;
+
+	i = mma8452_get_odr_index(data);
+	j = mma8452_get_power_mode(data);
+	if (j < 0)
+		return j;
+
+	return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[j][i],
+		ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]));
+}
+
+static ssize_t mma8452_show_os_ratio_avail(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct mma8452_data *data = iio_priv(indio_dev);
 	int i = mma8452_get_odr_index(data);
+	int j;
+	u16 val = 0;
+	size_t len = 0;
+
+	for (j = 0; j < ARRAY_SIZE(mma8452_os_ratio); j++) {
+		if (val == mma8452_os_ratio[j][i])
+			continue;
 
-	return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[i],
-		ARRAY_SIZE(mma8452_hp_filter_cutoff[0]));
+		val = mma8452_os_ratio[j][i];
+
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val);
+	}
+	buf[len - 1] = '\n';
+
+	return len;
 }
 
 static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
@@ -279,6 +398,8 @@ static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
 		       mma8452_show_scale_avail, NULL, 0);
 static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
 		       S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
+static IIO_DEVICE_ATTR(in_accel_oversampling_ratio_available, S_IRUGO,
+		       mma8452_show_os_ratio_avail, NULL, 0);
 
 static int mma8452_get_samp_freq_index(struct mma8452_data *data,
 				       int val, int val2)
@@ -297,24 +418,33 @@ static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
 static int mma8452_get_hp_filter_index(struct mma8452_data *data,
 				       int val, int val2)
 {
-	int i = mma8452_get_odr_index(data);
+	int i, j;
+
+	i = mma8452_get_odr_index(data);
+	j = mma8452_get_power_mode(data);
+	if (j < 0)
+		return j;
 
-	return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i],
-		ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2);
+	return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[j][i],
+		ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]), val, val2);
 }
 
 static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
 {
-	int i, ret;
+	int j, i, ret;
 
 	ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF);
 	if (ret < 0)
 		return ret;
 
 	i = mma8452_get_odr_index(data);
+	j = mma8452_get_power_mode(data);
+	if (j < 0)
+		return j;
+
 	ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
-	*hz = mma8452_hp_filter_cutoff[i][ret][0];
-	*uHz = mma8452_hp_filter_cutoff[i][ret][1];
+	*hz = mma8452_hp_filter_cutoff[j][i][ret][0];
+	*uHz = mma8452_hp_filter_cutoff[j][i][ret][1];
 
 	return 0;
 }
@@ -357,7 +487,8 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
 		return IIO_VAL_INT_PLUS_MICRO;
 	case IIO_CHAN_INFO_CALIBBIAS:
 		ret = i2c_smbus_read_byte_data(data->client,
-					      MMA8452_OFF_X + chan->scan_index);
+					       MMA8452_OFF_X +
+					       chan->scan_index);
 		if (ret < 0)
 			return ret;
 
@@ -375,6 +506,15 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
 		}
 
 		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		ret = mma8452_get_power_mode(data);
+		if (ret < 0)
+			return ret;
+
+		i = mma8452_get_odr_index(data);
+
+		*val = mma8452_os_ratio[ret][i];
+		return IIO_VAL_INT;
 	}
 
 	return -EINVAL;
@@ -392,24 +532,47 @@ static int mma8452_active(struct mma8452_data *data)
 					 data->ctrl_reg1);
 }
 
+/* returns >0 if active, 0 if in standby and <0 on error */
+static int mma8452_is_active(struct mma8452_data *data)
+{
+	int reg;
+
+	reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG1);
+	if (reg < 0)
+		return reg;
+
+	return reg & MMA8452_CTRL_ACTIVE;
+}
+
 static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
 {
 	int ret;
+	int is_active;
 
 	mutex_lock(&data->lock);
 
-	/* config can only be changed when in standby */
-	ret = mma8452_standby(data);
-	if (ret < 0)
+	is_active = mma8452_is_active(data);
+	if (is_active < 0) {
+		ret = is_active;
 		goto fail;
+	}
+
+	/* config can only be changed when in standby */
+	if (is_active > 0) {
+		ret = mma8452_standby(data);
+		if (ret < 0)
+			goto fail;
+	}
 
 	ret = i2c_smbus_write_byte_data(data->client, reg, val);
 	if (ret < 0)
 		goto fail;
 
-	ret = mma8452_active(data);
-	if (ret < 0)
-		goto fail;
+	if (is_active > 0) {
+		ret = mma8452_active(data);
+		if (ret < 0)
+			goto fail;
+	}
 
 	ret = 0;
 fail:
@@ -418,7 +581,22 @@ fail:
 	return ret;
 }
 
-/* returns >0 if in freefall mode, 0 if not or <0 if an error occured */
+static int mma8452_set_power_mode(struct mma8452_data *data, u8 mode)
+{
+	int reg;
+
+	reg = i2c_smbus_read_byte_data(data->client,
+				       MMA8452_CTRL_REG2);
+	if (reg < 0)
+		return reg;
+
+	reg &= ~MMA8452_CTRL_REG2_MODS_MASK;
+	reg |= mode << MMA8452_CTRL_REG2_MODS_SHIFT;
+
+	return mma8452_change_config(data, MMA8452_CTRL_REG2, reg);
+}
+
+/* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */
 static int mma8452_freefall_mode_enabled(struct mma8452_data *data)
 {
 	int val;
@@ -456,11 +634,7 @@ static int mma8452_set_freefall_mode(struct mma8452_data *data, bool state)
 		val |= MMA8452_FF_MT_CFG_OAE;
 	}
 
-	val = mma8452_change_config(data, chip->ev_cfg, val);
-	if (val)
-		return val;
-
-	return 0;
+	return mma8452_change_config(data, chip->ev_cfg, val);
 }
 
 static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
@@ -535,6 +709,14 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
 		return mma8452_change_config(data, MMA8452_DATA_CFG,
 					     data->data_cfg);
 
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		ret = mma8452_get_odr_index(data);
+
+		for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) {
+			if (mma8452_os_ratio[i][ret] == val)
+				return mma8452_set_power_mode(data, i);
+		}
+
 	default:
 		return -EINVAL;
 	}
@@ -548,7 +730,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
 			       int *val, int *val2)
 {
 	struct mma8452_data *data = iio_priv(indio_dev);
-	int ret, us;
+	int ret, us, power_mode;
 
 	switch (info) {
 	case IIO_EV_INFO_VALUE:
@@ -567,7 +749,11 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
 		if (ret < 0)
 			return ret;
 
-		us = ret * mma8452_transient_time_step_us[
+		power_mode = mma8452_get_power_mode(data);
+		if (power_mode < 0)
+			return power_mode;
+
+		us = ret * mma8452_transient_time_step_us[power_mode][
 				mma8452_get_odr_index(data)];
 		*val = us / USEC_PER_SEC;
 		*val2 = us % USEC_PER_SEC;
@@ -615,8 +801,12 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
 					     val);
 
 	case IIO_EV_INFO_PERIOD:
+		ret = mma8452_get_power_mode(data);
+		if (ret < 0)
+			return ret;
+
 		steps = (val * USEC_PER_SEC + val2) /
-				mma8452_transient_time_step_us[
+				mma8452_transient_time_step_us[ret][
 					mma8452_get_odr_index(data)];
 
 		if (steps < 0 || steps > 0xff)
@@ -668,7 +858,8 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev,
 		if (ret < 0)
 			return ret;
 
-		return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
+		return !!(ret & BIT(chan->scan_index +
+				    chip->ev_cfg_chan_shift));
 	default:
 		return -EINVAL;
 	}
@@ -682,7 +873,11 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
 {
 	struct mma8452_data *data = iio_priv(indio_dev);
 	const struct mma_chip_info *chip = data->chip_info;
-	int val;
+	int val, ret;
+
+	ret = mma8452_set_runtime_pm_state(data->client, state);
+	if (ret)
+		return ret;
 
 	switch (dir) {
 	case IIO_EV_DIR_FALLING:
@@ -718,7 +913,7 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
 static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
 {
 	struct mma8452_data *data = iio_priv(indio_dev);
-	s64 ts = iio_get_time_ns();
+	s64 ts = iio_get_time_ns(indio_dev);
 	int src;
 
 	src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src);
@@ -798,7 +993,7 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p)
 		goto done;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
-					   iio_get_time_ns());
+					   iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -911,7 +1106,8 @@ static struct attribute_group mma8452_event_attribute_group = {
 			      BIT(IIO_CHAN_INFO_CALIBBIAS), \
 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
 			BIT(IIO_CHAN_INFO_SCALE) | \
-			BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
+			BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) | \
+			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
 	.scan_index = idx, \
 	.scan_type = { \
 		.sign = 's', \
@@ -931,7 +1127,8 @@ static struct attribute_group mma8452_event_attribute_group = {
 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
 		BIT(IIO_CHAN_INFO_CALIBBIAS), \
 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
-		BIT(IIO_CHAN_INFO_SCALE), \
+		BIT(IIO_CHAN_INFO_SCALE) | \
+		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
 	.scan_index = idx, \
 	.scan_type = { \
 		.sign = 's', \
@@ -990,6 +1187,7 @@ enum {
 	mma8453,
 	mma8652,
 	mma8653,
+	fxls8471,
 };
 
 static const struct mma_chip_info mma_chip_info_table[] = {
@@ -1003,7 +1201,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
 		 * bit.
 		 * The userspace interface uses m/s^2 and we declare micro units
 		 * So scale factor for 12 bit here is given by:
-		 * 	g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
+		 *	g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
 		 */
 		.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
 		.ev_cfg = MMA8452_TRANSIENT_CFG,
@@ -1081,12 +1279,29 @@ static const struct mma_chip_info mma_chip_info_table[] = {
 		.ev_ths_mask = MMA8452_FF_MT_THS_MASK,
 		.ev_count = MMA8452_FF_MT_COUNT,
 	},
+	[fxls8471] = {
+		.chip_id = FXLS8471_DEVICE_ID,
+		.channels = mma8451_channels,
+		.num_channels = ARRAY_SIZE(mma8451_channels),
+		.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
+		.ev_cfg = MMA8452_TRANSIENT_CFG,
+		.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
+		.ev_cfg_chan_shift = 1,
+		.ev_src = MMA8452_TRANSIENT_SRC,
+		.ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE,
+		.ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE,
+		.ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE,
+		.ev_ths = MMA8452_TRANSIENT_THS,
+		.ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
+		.ev_count = MMA8452_TRANSIENT_COUNT,
+	},
 };
 
 static struct attribute *mma8452_attributes[] = {
 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
 	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
 	&iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr,
+	&iio_dev_attr_in_accel_oversampling_ratio_available.dev_attr.attr,
 	NULL
 };
 
@@ -1114,7 +1329,11 @@ static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig,
 {
 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
 	struct mma8452_data *data = iio_priv(indio_dev);
-	int reg;
+	int reg, ret;
+
+	ret = mma8452_set_runtime_pm_state(data->client, state);
+	if (ret)
+		return ret;
 
 	reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4);
 	if (reg < 0)
@@ -1206,6 +1425,7 @@ static const struct of_device_id mma8452_dt_ids[] = {
 	{ .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] },
 	{ .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] },
 	{ .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] },
+	{ .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
@@ -1243,6 +1463,7 @@ static int mma8452_probe(struct i2c_client *client,
 	case MMA8453_DEVICE_ID:
 	case MMA8652_DEVICE_ID:
 	case MMA8653_DEVICE_ID:
+	case FXLS8471_DEVICE_ID:
 		if (ret == data->chip_info->chip_id)
 			break;
 	default:
@@ -1340,13 +1561,22 @@ static int mma8452_probe(struct i2c_client *client,
 			goto buffer_cleanup;
 	}
 
+	ret = pm_runtime_set_active(&client->dev);
+	if (ret < 0)
+		goto buffer_cleanup;
+
+	pm_runtime_enable(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev,
+					 MMA8452_AUTO_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(&client->dev);
+
 	ret = iio_device_register(indio_dev);
 	if (ret < 0)
 		goto buffer_cleanup;
 
 	ret = mma8452_set_freefall_mode(data, false);
-	if (ret)
-		return ret;
+	if (ret < 0)
+		goto buffer_cleanup;
 
 	return 0;
 
@@ -1364,6 +1594,11 @@ static int mma8452_remove(struct i2c_client *client)
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
 	iio_device_unregister(indio_dev);
+
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+
 	iio_triggered_buffer_cleanup(indio_dev);
 	mma8452_trigger_cleanup(indio_dev);
 	mma8452_standby(iio_priv(indio_dev));
@@ -1371,6 +1606,45 @@ static int mma8452_remove(struct i2c_client *client)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int mma8452_runtime_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma8452_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->lock);
+	ret = mma8452_standby(data);
+	mutex_unlock(&data->lock);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "powering off device failed\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static int mma8452_runtime_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mma8452_data *data = iio_priv(indio_dev);
+	int ret, sleep_val;
+
+	ret = mma8452_active(data);
+	if (ret < 0)
+		return ret;
+
+	ret = mma8452_get_odr_index(data);
+	sleep_val = 1000 / mma8452_samp_freq[ret][0];
+	if (sleep_val < 20)
+		usleep_range(sleep_val * 1000, 20000);
+	else
+		msleep_interruptible(sleep_val);
+
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_PM_SLEEP
 static int mma8452_suspend(struct device *dev)
 {
@@ -1383,18 +1657,21 @@ static int mma8452_resume(struct device *dev)
 	return mma8452_active(iio_priv(i2c_get_clientdata(
 		to_i2c_client(dev))));
 }
-
-static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
-#define MMA8452_PM_OPS (&mma8452_pm_ops)
-#else
-#define MMA8452_PM_OPS NULL
 #endif
 
+static const struct dev_pm_ops mma8452_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mma8452_suspend, mma8452_resume)
+	SET_RUNTIME_PM_OPS(mma8452_runtime_suspend,
+			   mma8452_runtime_resume, NULL)
+};
+
 static const struct i2c_device_id mma8452_id[] = {
+	{ "mma8451", mma8451 },
 	{ "mma8452", mma8452 },
 	{ "mma8453", mma8453 },
 	{ "mma8652", mma8652 },
 	{ "mma8653", mma8653 },
+	{ "fxls8471", fxls8471 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, mma8452_id);
@@ -1403,7 +1680,7 @@ static struct i2c_driver mma8452_driver = {
 	.driver = {
 		.name	= "mma8452",
 		.of_match_table = of_match_ptr(mma8452_dt_ids),
-		.pm	= MMA8452_PM_OPS,
+		.pm	= &mma8452_pm_ops,
 	},
 	.probe = mma8452_probe,
 	.remove = mma8452_remove,
@@ -1412,5 +1689,5 @@ static struct i2c_driver mma8452_driver = {
 module_i2c_driver(mma8452_driver);
 
 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
-MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver");
+MODULE_DESCRIPTION("Freescale / NXP MMA8452 accelerometer driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index d899a4d..bf27044 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -391,7 +391,7 @@ static irqreturn_t mma9551_event_handler(int irq, void *private)
 	iio_push_event(indio_dev,
 		       IIO_MOD_EVENT_CODE(IIO_INCLI, 0, (mma_axis + 1),
 					  IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING),
-		       iio_get_time_ns());
+		       iio_get_time_ns(indio_dev));
 
 out:
 	mutex_unlock(&data->mutex);
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index fa7d362..36bf197 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -17,7 +17,6 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/events.h>
@@ -1002,7 +1001,7 @@ static irqreturn_t mma9553_irq_handler(int irq, void *private)
 	struct iio_dev *indio_dev = private;
 	struct mma9553_data *data = iio_priv(indio_dev);
 
-	data->timestamp = iio_get_time_ns();
+	data->timestamp = iio_get_time_ns(indio_dev);
 	/*
 	 * Since we only configure the interrupt pin when an
 	 * event is enabled, we are sure we have at least
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index e72e218..c23f47a 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -17,7 +17,6 @@
 #include <linux/i2c.h>
 #include <linux/iio/iio.h>
 #include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
 #include <linux/regmap.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/trigger.h>
@@ -380,31 +379,6 @@ static const struct iio_trigger_ops mxc4005_trigger_ops = {
 	.owner = THIS_MODULE,
 };
 
-static int mxc4005_gpio_probe(struct i2c_client *client,
-			      struct mxc4005_data *data)
-{
-	struct device *dev;
-	struct gpio_desc *gpio;
-	int ret;
-
-	if (!client)
-		return -EINVAL;
-
-	dev = &client->dev;
-
-	gpio = devm_gpiod_get_index(dev, "mxc4005_int", 0, GPIOD_IN);
-	if (IS_ERR(gpio)) {
-		dev_err(dev, "failed to get acpi gpio index\n");
-		return PTR_ERR(gpio);
-	}
-
-	ret = gpiod_to_irq(gpio);
-
-	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
-	return ret;
-}
-
 static int mxc4005_chip_init(struct mxc4005_data *data)
 {
 	int ret;
@@ -470,9 +444,6 @@ static int mxc4005_probe(struct i2c_client *client,
 		return ret;
 	}
 
-	if (client->irq < 0)
-		client->irq = mxc4005_gpio_probe(client, data);
-
 	if (client->irq > 0) {
 		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
 							   "%s-dev%d",
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index 5d4a189..f8dfdb6 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/iio/common/st_sensors.h>
 
+#define H3LIS331DL_DRIVER_NAME		"h3lis331dl_accel"
 #define LIS3LV02DL_ACCEL_DEV_NAME	"lis3lv02dl_accel"
 #define LSM303DLHC_ACCEL_DEV_NAME	"lsm303dlhc_accel"
 #define LIS3DH_ACCEL_DEV_NAME		"lis3dh"
@@ -28,6 +29,7 @@
 #define LSM330_ACCEL_DEV_NAME		"lsm330_accel"
 #define LSM303AGR_ACCEL_DEV_NAME	"lsm303agr_accel"
 #define LIS2DH12_ACCEL_DEV_NAME		"lis2dh12_accel"
+#define LIS3L02DQ_ACCEL_DEV_NAME	"lis3l02dq"
 
 /**
 * struct st_sensors_platform_data - default accel platform data
diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c
index a1e642e..7fddc13 100644
--- a/drivers/iio/accel/st_accel_buffer.c
+++ b/drivers/iio/accel/st_accel_buffer.c
@@ -91,7 +91,7 @@ static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = {
 
 int st_accel_allocate_ring(struct iio_dev *indio_dev)
 {
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+	return iio_triggered_buffer_setup(indio_dev, NULL,
 		&st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
 }
 
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index a03a141..da3fb06 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -39,6 +39,9 @@
 #define ST_ACCEL_FS_AVL_6G			6
 #define ST_ACCEL_FS_AVL_8G			8
 #define ST_ACCEL_FS_AVL_16G			16
+#define ST_ACCEL_FS_AVL_100G			100
+#define ST_ACCEL_FS_AVL_200G			200
+#define ST_ACCEL_FS_AVL_400G			400
 
 /* CUSTOM VALUES FOR SENSOR 1 */
 #define ST_ACCEL_1_WAI_EXP			0x33
@@ -96,6 +99,8 @@
 #define ST_ACCEL_2_DRDY_IRQ_INT2_MASK		0x10
 #define ST_ACCEL_2_IHL_IRQ_ADDR			0x22
 #define ST_ACCEL_2_IHL_IRQ_MASK			0x80
+#define ST_ACCEL_2_OD_IRQ_ADDR			0x22
+#define ST_ACCEL_2_OD_IRQ_MASK			0x40
 #define ST_ACCEL_2_MULTIREAD_BIT		true
 
 /* CUSTOM VALUES FOR SENSOR 3 */
@@ -177,10 +182,55 @@
 #define ST_ACCEL_5_DRDY_IRQ_INT2_MASK		0x20
 #define ST_ACCEL_5_IHL_IRQ_ADDR			0x22
 #define ST_ACCEL_5_IHL_IRQ_MASK			0x80
+#define ST_ACCEL_5_OD_IRQ_ADDR			0x22
+#define ST_ACCEL_5_OD_IRQ_MASK			0x40
 #define ST_ACCEL_5_IG1_EN_ADDR			0x21
 #define ST_ACCEL_5_IG1_EN_MASK			0x08
 #define ST_ACCEL_5_MULTIREAD_BIT		false
 
+/* CUSTOM VALUES FOR SENSOR 6 */
+#define ST_ACCEL_6_WAI_EXP			0x32
+#define ST_ACCEL_6_ODR_ADDR			0x20
+#define ST_ACCEL_6_ODR_MASK			0x18
+#define ST_ACCEL_6_ODR_AVL_50HZ_VAL		0x00
+#define ST_ACCEL_6_ODR_AVL_100HZ_VAL		0x01
+#define ST_ACCEL_6_ODR_AVL_400HZ_VAL		0x02
+#define ST_ACCEL_6_ODR_AVL_1000HZ_VAL		0x03
+#define ST_ACCEL_6_PW_ADDR			0x20
+#define ST_ACCEL_6_PW_MASK			0x20
+#define ST_ACCEL_6_FS_ADDR			0x23
+#define ST_ACCEL_6_FS_MASK			0x30
+#define ST_ACCEL_6_FS_AVL_100_VAL		0x00
+#define ST_ACCEL_6_FS_AVL_200_VAL		0x01
+#define ST_ACCEL_6_FS_AVL_400_VAL		0x03
+#define ST_ACCEL_6_FS_AVL_100_GAIN		IIO_G_TO_M_S_2(49000)
+#define ST_ACCEL_6_FS_AVL_200_GAIN		IIO_G_TO_M_S_2(98000)
+#define ST_ACCEL_6_FS_AVL_400_GAIN		IIO_G_TO_M_S_2(195000)
+#define ST_ACCEL_6_BDU_ADDR			0x23
+#define ST_ACCEL_6_BDU_MASK			0x80
+#define ST_ACCEL_6_DRDY_IRQ_ADDR		0x22
+#define ST_ACCEL_6_DRDY_IRQ_INT1_MASK		0x02
+#define ST_ACCEL_6_DRDY_IRQ_INT2_MASK		0x10
+#define ST_ACCEL_6_IHL_IRQ_ADDR			0x22
+#define ST_ACCEL_6_IHL_IRQ_MASK			0x80
+#define ST_ACCEL_6_MULTIREAD_BIT		true
+
+/* CUSTOM VALUES FOR SENSOR 7 */
+#define ST_ACCEL_7_ODR_ADDR			0x20
+#define ST_ACCEL_7_ODR_MASK			0x30
+#define ST_ACCEL_7_ODR_AVL_280HZ_VAL		0x00
+#define ST_ACCEL_7_ODR_AVL_560HZ_VAL		0x01
+#define ST_ACCEL_7_ODR_AVL_1120HZ_VAL		0x02
+#define ST_ACCEL_7_ODR_AVL_4480HZ_VAL		0x03
+#define ST_ACCEL_7_PW_ADDR			0x20
+#define ST_ACCEL_7_PW_MASK			0xc0
+#define ST_ACCEL_7_FS_AVL_2_GAIN		IIO_G_TO_M_S_2(488)
+#define ST_ACCEL_7_BDU_ADDR			0x21
+#define ST_ACCEL_7_BDU_MASK			0x40
+#define ST_ACCEL_7_DRDY_IRQ_ADDR		0x21
+#define ST_ACCEL_7_DRDY_IRQ_INT1_MASK		0x04
+#define ST_ACCEL_7_MULTIREAD_BIT		false
+
 static const struct iio_chan_spec st_accel_8bit_channels[] = {
 	ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
 			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
@@ -302,6 +352,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
 			.mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK,
 			.addr_ihl = ST_ACCEL_1_IHL_IRQ_ADDR,
 			.mask_ihl = ST_ACCEL_1_IHL_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
 		.bootime = 2,
@@ -367,6 +418,9 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
 			.mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK,
 			.addr_ihl = ST_ACCEL_2_IHL_IRQ_ADDR,
 			.mask_ihl = ST_ACCEL_2_IHL_IRQ_MASK,
+			.addr_od = ST_ACCEL_2_OD_IRQ_ADDR,
+			.mask_od = ST_ACCEL_2_OD_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
 		.bootime = 2,
@@ -444,6 +498,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
 			.mask_int2 = ST_ACCEL_3_DRDY_IRQ_INT2_MASK,
 			.addr_ihl = ST_ACCEL_3_IHL_IRQ_ADDR,
 			.mask_ihl = ST_ACCEL_3_IHL_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 			.ig1 = {
 				.en_addr = ST_ACCEL_3_IG1_EN_ADDR,
 				.en_mask = ST_ACCEL_3_IG1_EN_MASK,
@@ -502,6 +557,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
 		.drdy_irq = {
 			.addr = ST_ACCEL_4_DRDY_IRQ_ADDR,
 			.mask_int1 = ST_ACCEL_4_DRDY_IRQ_INT1_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT,
 		.bootime = 2, /* guess */
@@ -553,10 +609,123 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
 			.mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK,
 			.addr_ihl = ST_ACCEL_5_IHL_IRQ_ADDR,
 			.mask_ihl = ST_ACCEL_5_IHL_IRQ_MASK,
+			.addr_od = ST_ACCEL_5_OD_IRQ_ADDR,
+			.mask_od = ST_ACCEL_5_OD_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT,
 		.bootime = 2, /* guess */
 	},
+	{
+		.wai = ST_ACCEL_6_WAI_EXP,
+		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+		.sensors_supported = {
+			[0] = H3LIS331DL_DRIVER_NAME,
+		},
+		.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
+		.odr = {
+			.addr = ST_ACCEL_6_ODR_ADDR,
+			.mask = ST_ACCEL_6_ODR_MASK,
+			.odr_avl = {
+				{ 50, ST_ACCEL_6_ODR_AVL_50HZ_VAL },
+				{ 100, ST_ACCEL_6_ODR_AVL_100HZ_VAL, },
+				{ 400, ST_ACCEL_6_ODR_AVL_400HZ_VAL, },
+				{ 1000, ST_ACCEL_6_ODR_AVL_1000HZ_VAL, },
+			},
+		},
+		.pw = {
+			.addr = ST_ACCEL_6_PW_ADDR,
+			.mask = ST_ACCEL_6_PW_MASK,
+			.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
+			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+		},
+		.enable_axis = {
+			.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+		},
+		.fs = {
+			.addr = ST_ACCEL_6_FS_ADDR,
+			.mask = ST_ACCEL_6_FS_MASK,
+			.fs_avl = {
+				[0] = {
+					.num = ST_ACCEL_FS_AVL_100G,
+					.value = ST_ACCEL_6_FS_AVL_100_VAL,
+					.gain = ST_ACCEL_6_FS_AVL_100_GAIN,
+				},
+				[1] = {
+					.num = ST_ACCEL_FS_AVL_200G,
+					.value = ST_ACCEL_6_FS_AVL_200_VAL,
+					.gain = ST_ACCEL_6_FS_AVL_200_GAIN,
+				},
+				[2] = {
+					.num = ST_ACCEL_FS_AVL_400G,
+					.value = ST_ACCEL_6_FS_AVL_400_VAL,
+					.gain = ST_ACCEL_6_FS_AVL_400_GAIN,
+				},
+			},
+		},
+		.bdu = {
+			.addr = ST_ACCEL_6_BDU_ADDR,
+			.mask = ST_ACCEL_6_BDU_MASK,
+		},
+		.drdy_irq = {
+			.addr = ST_ACCEL_6_DRDY_IRQ_ADDR,
+			.mask_int1 = ST_ACCEL_6_DRDY_IRQ_INT1_MASK,
+			.mask_int2 = ST_ACCEL_6_DRDY_IRQ_INT2_MASK,
+			.addr_ihl = ST_ACCEL_6_IHL_IRQ_ADDR,
+			.mask_ihl = ST_ACCEL_6_IHL_IRQ_MASK,
+		},
+		.multi_read_bit = ST_ACCEL_6_MULTIREAD_BIT,
+		.bootime = 2,
+	},
+	{
+		/* No WAI register present */
+		.sensors_supported = {
+			[0] = LIS3L02DQ_ACCEL_DEV_NAME,
+		},
+		.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
+		.odr = {
+			.addr = ST_ACCEL_7_ODR_ADDR,
+			.mask = ST_ACCEL_7_ODR_MASK,
+			.odr_avl = {
+				{ 280, ST_ACCEL_7_ODR_AVL_280HZ_VAL, },
+				{ 560, ST_ACCEL_7_ODR_AVL_560HZ_VAL, },
+				{ 1120, ST_ACCEL_7_ODR_AVL_1120HZ_VAL, },
+				{ 4480, ST_ACCEL_7_ODR_AVL_4480HZ_VAL, },
+			},
+		},
+		.pw = {
+			.addr = ST_ACCEL_7_PW_ADDR,
+			.mask = ST_ACCEL_7_PW_MASK,
+			.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
+			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+		},
+		.enable_axis = {
+			.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
+			.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
+		},
+		.fs = {
+			.fs_avl = {
+				[0] = {
+					.num = ST_ACCEL_FS_AVL_2G,
+					.gain = ST_ACCEL_7_FS_AVL_2_GAIN,
+				},
+			},
+		},
+		/*
+		 * The part has a BDU bit but if set the data is never
+		 * updated so don't set it.
+		 */
+		.bdu = {
+		},
+		.drdy_irq = {
+			.addr = ST_ACCEL_7_DRDY_IRQ_ADDR,
+			.mask_int1 = ST_ACCEL_7_DRDY_IRQ_INT1_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
+		},
+		.multi_read_bit = ST_ACCEL_7_MULTIREAD_BIT,
+		.bootime = 2,
+	},
 };
 
 static int st_accel_read_raw(struct iio_dev *indio_dev,
@@ -636,6 +805,7 @@ static const struct iio_info accel_info = {
 static const struct iio_trigger_ops st_accel_trigger_ops = {
 	.owner = THIS_MODULE,
 	.set_trigger_state = ST_ACCEL_TRIGGER_SET_STATE,
+	.validate_device = st_sensors_validate_device,
 };
 #define ST_ACCEL_TRIGGER_OPS (&st_accel_trigger_ops)
 #else
@@ -652,13 +822,15 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
 	indio_dev->info = &accel_info;
 	mutex_init(&adata->tb.buf_lock);
 
-	st_sensors_power_enable(indio_dev);
+	err = st_sensors_power_enable(indio_dev);
+	if (err)
+		return err;
 
 	err = st_sensors_check_device_support(indio_dev,
 					ARRAY_SIZE(st_accel_sensors_settings),
 					st_accel_sensors_settings);
 	if (err < 0)
-		return err;
+		goto st_accel_power_off;
 
 	adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
 	adata->multiread_bit = adata->sensor_settings->multi_read_bit;
@@ -675,11 +847,11 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
 
 	err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
 	if (err < 0)
-		return err;
+		goto st_accel_power_off;
 
 	err = st_accel_allocate_ring(indio_dev);
 	if (err < 0)
-		return err;
+		goto st_accel_power_off;
 
 	if (irq > 0) {
 		err = st_sensors_allocate_trigger(indio_dev,
@@ -702,6 +874,8 @@ st_accel_device_register_error:
 		st_sensors_deallocate_trigger(indio_dev);
 st_accel_probe_trigger_error:
 	st_accel_deallocate_ring(indio_dev);
+st_accel_power_off:
+	st_sensors_power_disable(indio_dev);
 
 	return err;
 }
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 294a32f..e9d427a 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -76,6 +76,14 @@ static const struct of_device_id st_accel_of_match[] = {
 		.compatible = "st,lis2dh12-accel",
 		.data = LIS2DH12_ACCEL_DEV_NAME,
 	},
+	{
+		.compatible = "st,h3lis331dl-accel",
+		.data = H3LIS331DL_DRIVER_NAME,
+	},
+	{
+		.compatible = "st,lis3l02dq",
+		.data = LIS3L02DQ_ACCEL_DEV_NAME,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -126,6 +134,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
 	{ LSM330_ACCEL_DEV_NAME },
 	{ LSM303AGR_ACCEL_DEV_NAME },
 	{ LIS2DH12_ACCEL_DEV_NAME },
+	{ LIS3L02DQ_ACCEL_DEV_NAME },
 	{},
 };
 MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index fcd5847..efd4394 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -59,6 +59,7 @@ static const struct spi_device_id st_accel_id_table[] = {
 	{ LSM330_ACCEL_DEV_NAME },
 	{ LSM303AGR_ACCEL_DEV_NAME },
 	{ LIS2DH12_ACCEL_DEV_NAME },
+	{ LIS3L02DQ_ACCEL_DEV_NAME },
 	{},
 };
 MODULE_DEVICE_TABLE(spi, st_accel_id_table);
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index 85fe7f7..e31023d 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -11,7 +11,6 @@
  */
 
 #include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index 5709d9e..300d955 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -11,7 +11,6 @@
  */
 
 #include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 82c718c..1de31bd 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -153,6 +153,18 @@ config AXP288_ADC
 	  To compile this driver as a module, choose M here: the module will be
 	  called axp288_adc.
 
+config BCM_IPROC_ADC
+	tristate "Broadcom IPROC ADC driver"
+	depends on ARCH_BCM_IPROC || COMPILE_TEST
+	depends on MFD_SYSCON
+	default ARCH_BCM_CYGNUS
+	help
+	  Say Y here if you want to add support for the Broadcom static
+	  ADC driver.
+
+	  Broadcom iProc ADC driver. Broadcom iProc ADC controller has 8
+	  channels. The driver allows the user to read voltage values.
+
 config BERLIN2_ADC
 	tristate "Marvell Berlin2 ADC driver"
 	depends on ARCH_BERLIN
@@ -242,6 +254,16 @@ config LP8788_ADC
 	  To compile this driver as a module, choose M here: the module will be
 	  called lp8788_adc.
 
+config LPC18XX_ADC
+	tristate "NXP LPC18xx ADC driver"
+	depends on ARCH_LPC18XX || COMPILE_TEST
+	depends on OF && HAS_IOMEM
+	help
+	  Say yes here to build support for NXP LPC18XX ADC.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called lpc18xx_adc.
+
 config MAX1027
 	tristate "Maxim max1027 ADC driver"
 	depends on SPI
@@ -375,11 +397,11 @@ config ROCKCHIP_SARADC
 	  module will be called rockchip_saradc.
 
 config TI_ADC081C
-	tristate "Texas Instruments ADC081C021/027"
+	tristate "Texas Instruments ADC081C/ADC101C/ADC121C family"
 	depends on I2C
 	help
-	  If you say yes here you get support for Texas Instruments ADC081C021
-	  and ADC081C027 ADC chips.
+	  If you say yes here you get support for Texas Instruments ADC081C,
+	  ADC101C and ADC121C ADC chips.
 
 	  This driver can also be built as a module. If so, the module will be
 	  called ti-adc081c.
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 0cb7921..0ba0d50 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_AD799X) += ad799x.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
 obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
 obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
+obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
 obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
 obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
 obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_HI8435) += hi8435.o
 obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
 obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
+obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
 obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index 2123f0a..c0f6a98 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -154,12 +154,11 @@ static int ad7266_read_raw(struct iio_dev *indio_dev,
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		if (iio_buffer_enabled(indio_dev))
-			return -EBUSY;
-
-		ret = ad7266_read_single(st, val, chan->address);
+		ret = iio_device_claim_direct_mode(indio_dev);
 		if (ret)
 			return ret;
+		ret = ad7266_read_single(st, val, chan->address);
+		iio_device_release_direct_mode(indio_dev);
 
 		*val = (*val >> 2) & 0xfff;
 		if (chan->scan_type.sign == 's')
@@ -441,6 +440,7 @@ static int ad7266_probe(struct spi_device *spi)
 	st->spi = spi;
 
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &ad7266_info;
diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c
index c0eabf1..1d90b02 100644
--- a/drivers/iio/adc/ad7291.c
+++ b/drivers/iio/adc/ad7291.c
@@ -115,7 +115,7 @@ static irqreturn_t ad7291_event_handler(int irq, void *private)
 	u16 t_status, v_status;
 	u16 command;
 	int i;
-	s64 timestamp = iio_get_time_ns();
+	s64 timestamp = iio_get_time_ns(indio_dev);
 
 	if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status))
 		return IRQ_HANDLED;
@@ -505,6 +505,7 @@ static int ad7291_probe(struct i2c_client *client,
 	indio_dev->num_channels = ARRAY_SIZE(ad7291_channels);
 
 	indio_dev->dev.parent = &client->dev;
+	indio_dev->dev.of_node = client->dev.of_node;
 	indio_dev->info = &ad7291_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
index 62bb8f7..10ec8fc 100644
--- a/drivers/iio/adc/ad7298.c
+++ b/drivers/iio/adc/ad7298.c
@@ -163,7 +163,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
 		goto done;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
-		iio_get_time_ns());
+		iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -315,6 +315,7 @@ static int ad7298_probe(struct spi_device *spi)
 
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = ad7298_channels;
 	indio_dev->num_channels = ARRAY_SIZE(ad7298_channels);
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index be85c2a..b7ecf9a 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -70,7 +70,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void  *p)
 		goto done;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, st->data,
-		iio_get_time_ns());
+		iio_get_time_ns(indio_dev));
 done:
 	iio_trigger_notify_done(indio_dev->trig);
 
@@ -106,12 +106,11 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		if (iio_buffer_enabled(indio_dev))
-			ret = -EBUSY;
-		else
-			ret = ad7476_scan_direct(st);
-		mutex_unlock(&indio_dev->mlock);
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret)
+			return ret;
+		ret = ad7476_scan_direct(st);
+		iio_device_release_direct_mode(indio_dev);
 
 		if (ret < 0)
 			return ret;
@@ -228,6 +227,7 @@ static int ad7476_probe(struct spi_device *spi)
 
 	/* Establish that the iio_dev is a child of the spi device */
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = st->chip_info->channel;
diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c
index cf172d5..1817ebf 100644
--- a/drivers/iio/adc/ad7791.c
+++ b/drivers/iio/adc/ad7791.c
@@ -272,30 +272,22 @@ static ssize_t ad7791_write_frequency(struct device *dev,
 	struct ad7791_state *st = iio_priv(indio_dev);
 	int i, ret;
 
-	mutex_lock(&indio_dev->mlock);
-	if (iio_buffer_enabled(indio_dev)) {
-		mutex_unlock(&indio_dev->mlock);
-		return -EBUSY;
-	}
-	mutex_unlock(&indio_dev->mlock);
-
-	ret = -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) {
-		if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) {
-
-			mutex_lock(&indio_dev->mlock);
-			st->filter &= ~AD7791_FILTER_RATE_MASK;
-			st->filter |= i;
-			ad_sd_write_reg(&st->sd, AD7791_REG_FILTER,
-					 sizeof(st->filter), st->filter);
-			mutex_unlock(&indio_dev->mlock);
-			ret = 0;
+	for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++)
+		if (sysfs_streq(ad7791_sample_freq_avail[i], buf))
 			break;
-		}
-	}
+	if (i == ARRAY_SIZE(ad7791_sample_freq_avail))
+		return -EINVAL;
+
+	ret = iio_device_claim_direct_mode(indio_dev);
+	if (ret)
+		return ret;
+	st->filter &= ~AD7791_FILTER_RATE_MASK;
+	st->filter |= i;
+	ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, sizeof(st->filter),
+			st->filter);
+	iio_device_release_direct_mode(indio_dev);
 
-	return ret ? ret : len;
+	return len;
 }
 
 static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
@@ -383,6 +375,7 @@ static int ad7791_probe(struct spi_device *spi)
 	spi_set_drvdata(spi, indio_dev);
 
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = st->info->channels;
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
index 7b07bb6..847789b 100644
--- a/drivers/iio/adc/ad7793.c
+++ b/drivers/iio/adc/ad7793.c
@@ -369,13 +369,6 @@ static ssize_t ad7793_write_frequency(struct device *dev,
 	long lval;
 	int i, ret;
 
-	mutex_lock(&indio_dev->mlock);
-	if (iio_buffer_enabled(indio_dev)) {
-		mutex_unlock(&indio_dev->mlock);
-		return -EBUSY;
-	}
-	mutex_unlock(&indio_dev->mlock);
-
 	ret = kstrtol(buf, 10, &lval);
 	if (ret)
 		return ret;
@@ -383,20 +376,21 @@ static ssize_t ad7793_write_frequency(struct device *dev,
 	if (lval == 0)
 		return -EINVAL;
 
-	ret = -EINVAL;
-
 	for (i = 0; i < 16; i++)
-		if (lval == st->chip_info->sample_freq_avail[i]) {
-			mutex_lock(&indio_dev->mlock);
-			st->mode &= ~AD7793_MODE_RATE(-1);
-			st->mode |= AD7793_MODE_RATE(i);
-			ad_sd_write_reg(&st->sd, AD7793_REG_MODE,
-					 sizeof(st->mode), st->mode);
-			mutex_unlock(&indio_dev->mlock);
-			ret = 0;
-		}
+		if (lval == st->chip_info->sample_freq_avail[i])
+			break;
+	if (i == 16)
+		return -EINVAL;
 
-	return ret ? ret : len;
+	ret = iio_device_claim_direct_mode(indio_dev);
+	if (ret)
+		return ret;
+	st->mode &= ~AD7793_MODE_RATE(-1);
+	st->mode |= AD7793_MODE_RATE(i);
+	ad_sd_write_reg(&st->sd, AD7793_REG_MODE, sizeof(st->mode), st->mode);
+	iio_device_release_direct_mode(indio_dev);
+
+	return len;
 }
 
 static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
@@ -790,6 +784,7 @@ static int ad7793_probe(struct spi_device *spi)
 	spi_set_drvdata(spi, indio_dev);
 
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = st->chip_info->channels;
diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c
index 2d3c397..7a483bf 100644
--- a/drivers/iio/adc/ad7887.c
+++ b/drivers/iio/adc/ad7887.c
@@ -122,7 +122,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
 		goto done;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, st->data,
-		iio_get_time_ns());
+		iio_get_time_ns(indio_dev));
 done:
 	iio_trigger_notify_done(indio_dev->trig);
 
@@ -156,12 +156,11 @@ static int ad7887_read_raw(struct iio_dev *indio_dev,
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		if (iio_buffer_enabled(indio_dev))
-			ret = -EBUSY;
-		else
-			ret = ad7887_scan_direct(st, chan->address);
-		mutex_unlock(&indio_dev->mlock);
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret)
+			return ret;
+		ret = ad7887_scan_direct(st, chan->address);
+		iio_device_release_direct_mode(indio_dev);
 
 		if (ret < 0)
 			return ret;
@@ -265,6 +264,7 @@ static int ad7887_probe(struct spi_device *spi)
 
 	/* Estabilish that the iio_dev is a child of the spi device */
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->info = &ad7887_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c
index 45e29cc..77a675e 100644
--- a/drivers/iio/adc/ad7923.c
+++ b/drivers/iio/adc/ad7923.c
@@ -181,7 +181,7 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p)
 		goto done;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
-		iio_get_time_ns());
+		iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -233,12 +233,11 @@ static int ad7923_read_raw(struct iio_dev *indio_dev,
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		if (iio_buffer_enabled(indio_dev))
-			ret = -EBUSY;
-		else
-			ret = ad7923_scan_direct(st, chan->address);
-		mutex_unlock(&indio_dev->mlock);
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret)
+			return ret;
+		ret = ad7923_scan_direct(st, chan->address);
+		iio_device_release_direct_mode(indio_dev);
 
 		if (ret < 0)
 			return ret;
@@ -289,6 +288,7 @@ static int ad7923_probe(struct spi_device *spi)
 
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = info->channels;
 	indio_dev->num_channels = info->num_channels;
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 01d7158..b616376 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -212,7 +212,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
 		goto out;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
-			iio_get_time_ns());
+			iio_get_time_ns(indio_dev));
 out:
 	iio_trigger_notify_done(indio_dev->trig);
 
@@ -282,12 +282,11 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		if (iio_buffer_enabled(indio_dev))
-			ret = -EBUSY;
-		else
-			ret = ad799x_scan_direct(st, chan->scan_index);
-		mutex_unlock(&indio_dev->mlock);
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret)
+			return ret;
+		ret = ad799x_scan_direct(st, chan->scan_index);
+		iio_device_release_direct_mode(indio_dev);
 
 		if (ret < 0)
 			return ret;
@@ -395,11 +394,9 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
 	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;
-	}
+	ret = iio_device_claim_direct_mode(indio_dev);
+	if (ret)
+		return ret;
 
 	if (state)
 		st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
@@ -412,10 +409,7 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
 		st->config &= ~AD7998_ALERT_EN;
 
 	ret = ad799x_write_config(st, st->config);
-
-done:
-	mutex_unlock(&indio_dev->mlock);
-
+	iio_device_release_direct_mode(indio_dev);
 	return ret;
 }
 
@@ -477,7 +471,7 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev,
 	if (ret < 0)
 		return ret;
 	*val = (ret >> chan->scan_type.shift) &
-		GENMASK(chan->scan_type.realbits - 1 , 0);
+		GENMASK(chan->scan_type.realbits - 1, 0);
 
 	return IIO_VAL_INT;
 }
@@ -508,7 +502,7 @@ static irqreturn_t ad799x_event_handler(int irq, void *private)
 							    (i >> 1),
 							    IIO_EV_TYPE_THRESH,
 							    IIO_EV_DIR_FALLING),
-				       iio_get_time_ns());
+				       iio_get_time_ns(indio_dev));
 	}
 
 done:
@@ -812,6 +806,7 @@ static int ad799x_probe(struct i2c_client *client,
 	st->client = client;
 
 	indio_dev->dev.parent = &client->dev;
+	indio_dev->dev.of_node = client->dev.of_node;
 	indio_dev->name = id->name;
 	indio_dev->info = st->chip_config->info;
 
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 2e154cb..e10dca3 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -66,8 +66,10 @@
 #define	AT91_SAMA5D2_MR_PRESCAL(v)	((v) << AT91_SAMA5D2_MR_PRESCAL_OFFSET)
 #define	AT91_SAMA5D2_MR_PRESCAL_OFFSET	8
 #define	AT91_SAMA5D2_MR_PRESCAL_MAX	0xff
+#define AT91_SAMA5D2_MR_PRESCAL_MASK	GENMASK(15, 8)
 /* Startup Time */
 #define	AT91_SAMA5D2_MR_STARTUP(v)	((v) << 16)
+#define AT91_SAMA5D2_MR_STARTUP_MASK	GENMASK(19, 16)
 /* Analog Change */
 #define	AT91_SAMA5D2_MR_ANACH		BIT(23)
 /* Tracking Time */
@@ -92,13 +94,13 @@
 /* Last Converted Data Register */
 #define AT91_SAMA5D2_LCDR	0x20
 /* Interrupt Enable Register */
-#define AT91_SAMA5D2_IER		0x24
+#define AT91_SAMA5D2_IER	0x24
 /* Interrupt Disable Register */
-#define AT91_SAMA5D2_IDR		0x28
+#define AT91_SAMA5D2_IDR	0x28
 /* Interrupt Mask Register */
-#define AT91_SAMA5D2_IMR		0x2c
+#define AT91_SAMA5D2_IMR	0x2c
 /* Interrupt Status Register */
-#define AT91_SAMA5D2_ISR		0x30
+#define AT91_SAMA5D2_ISR	0x30
 /* Last Channel Trigger Mode Register */
 #define AT91_SAMA5D2_LCTMR	0x34
 /* Last Channel Compare Window Register */
@@ -106,17 +108,20 @@
 /* Overrun Status Register */
 #define AT91_SAMA5D2_OVER	0x3c
 /* Extended Mode Register */
-#define AT91_SAMA5D2_EMR		0x40
+#define AT91_SAMA5D2_EMR	0x40
 /* Compare Window Register */
-#define AT91_SAMA5D2_CWR		0x44
+#define AT91_SAMA5D2_CWR	0x44
 /* Channel Gain Register */
-#define AT91_SAMA5D2_CGR		0x48
+#define AT91_SAMA5D2_CGR	0x48
+
 /* Channel Offset Register */
-#define AT91_SAMA5D2_COR		0x4c
+#define AT91_SAMA5D2_COR	0x4c
+#define AT91_SAMA5D2_COR_DIFF_OFFSET	16
+
 /* Channel Data Register 0 */
 #define AT91_SAMA5D2_CDR0	0x50
 /* Analog Control Register */
-#define AT91_SAMA5D2_ACR		0x94
+#define AT91_SAMA5D2_ACR	0x94
 /* Touchscreen Mode Register */
 #define AT91_SAMA5D2_TSMR	0xb0
 /* Touchscreen X Position Register */
@@ -130,7 +135,7 @@
 /* Correction Select Register */
 #define AT91_SAMA5D2_COSR	0xd0
 /* Correction Value Register */
-#define AT91_SAMA5D2_CVR		0xd4
+#define AT91_SAMA5D2_CVR	0xd4
 /* Channel Error Correction Register */
 #define AT91_SAMA5D2_CECR	0xd8
 /* Write Protection Mode Register */
@@ -140,7 +145,7 @@
 /* Version Register */
 #define AT91_SAMA5D2_VERSION	0xfc
 
-#define AT91_AT91_SAMA5D2_CHAN(num, addr)				\
+#define AT91_SAMA5D2_CHAN_SINGLE(num, addr)				\
 	{								\
 		.type = IIO_VOLTAGE,					\
 		.channel = num,						\
@@ -156,6 +161,24 @@
 		.indexed = 1,						\
 	}
 
+#define AT91_SAMA5D2_CHAN_DIFF(num, num2, addr)				\
+	{								\
+		.type = IIO_VOLTAGE,					\
+		.differential = 1,					\
+		.channel = num,						\
+		.channel2 = num2,					\
+		.address = addr,					\
+		.scan_type = {						\
+			.sign = 's',					\
+			.realbits = 12,					\
+		},							\
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+		.datasheet_name = "CH"#num"-CH"#num2,			\
+		.indexed = 1,						\
+	}
+
 #define at91_adc_readl(st, reg)		readl_relaxed(st->base + reg)
 #define at91_adc_writel(st, reg, val)	writel_relaxed(val, st->base + reg)
 
@@ -185,18 +208,24 @@ struct at91_adc_state {
 };
 
 static const struct iio_chan_spec at91_adc_channels[] = {
-	AT91_AT91_SAMA5D2_CHAN(0, 0x50),
-	AT91_AT91_SAMA5D2_CHAN(1, 0x54),
-	AT91_AT91_SAMA5D2_CHAN(2, 0x58),
-	AT91_AT91_SAMA5D2_CHAN(3, 0x5c),
-	AT91_AT91_SAMA5D2_CHAN(4, 0x60),
-	AT91_AT91_SAMA5D2_CHAN(5, 0x64),
-	AT91_AT91_SAMA5D2_CHAN(6, 0x68),
-	AT91_AT91_SAMA5D2_CHAN(7, 0x6c),
-	AT91_AT91_SAMA5D2_CHAN(8, 0x70),
-	AT91_AT91_SAMA5D2_CHAN(9, 0x74),
-	AT91_AT91_SAMA5D2_CHAN(10, 0x78),
-	AT91_AT91_SAMA5D2_CHAN(11, 0x7c),
+	AT91_SAMA5D2_CHAN_SINGLE(0, 0x50),
+	AT91_SAMA5D2_CHAN_SINGLE(1, 0x54),
+	AT91_SAMA5D2_CHAN_SINGLE(2, 0x58),
+	AT91_SAMA5D2_CHAN_SINGLE(3, 0x5c),
+	AT91_SAMA5D2_CHAN_SINGLE(4, 0x60),
+	AT91_SAMA5D2_CHAN_SINGLE(5, 0x64),
+	AT91_SAMA5D2_CHAN_SINGLE(6, 0x68),
+	AT91_SAMA5D2_CHAN_SINGLE(7, 0x6c),
+	AT91_SAMA5D2_CHAN_SINGLE(8, 0x70),
+	AT91_SAMA5D2_CHAN_SINGLE(9, 0x74),
+	AT91_SAMA5D2_CHAN_SINGLE(10, 0x78),
+	AT91_SAMA5D2_CHAN_SINGLE(11, 0x7c),
+	AT91_SAMA5D2_CHAN_DIFF(0, 1, 0x50),
+	AT91_SAMA5D2_CHAN_DIFF(2, 3, 0x58),
+	AT91_SAMA5D2_CHAN_DIFF(4, 5, 0x60),
+	AT91_SAMA5D2_CHAN_DIFF(6, 7, 0x68),
+	AT91_SAMA5D2_CHAN_DIFF(8, 9, 0x70),
+	AT91_SAMA5D2_CHAN_DIFF(10, 11, 0x78),
 };
 
 static unsigned at91_adc_startup_time(unsigned startup_time_min,
@@ -226,7 +255,7 @@ static unsigned at91_adc_startup_time(unsigned startup_time_min,
 static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
 {
 	struct iio_dev *indio_dev = iio_priv_to_dev(st);
-	unsigned f_per, prescal, startup;
+	unsigned f_per, prescal, startup, mr;
 
 	f_per = clk_get_rate(st->per_clk);
 	prescal = (f_per / (2 * freq)) - 1;
@@ -234,10 +263,11 @@ static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
 	startup = at91_adc_startup_time(st->soc_info.startup_time,
 					freq / 1000);
 
-	at91_adc_writel(st, AT91_SAMA5D2_MR,
-			AT91_SAMA5D2_MR_TRANSFER(2)
-			| AT91_SAMA5D2_MR_STARTUP(startup)
-			| AT91_SAMA5D2_MR_PRESCAL(prescal));
+	mr = at91_adc_readl(st, AT91_SAMA5D2_MR);
+	mr &= ~(AT91_SAMA5D2_MR_STARTUP_MASK | AT91_SAMA5D2_MR_PRESCAL_MASK);
+	mr |= AT91_SAMA5D2_MR_STARTUP(startup);
+	mr |= AT91_SAMA5D2_MR_PRESCAL(prescal);
+	at91_adc_writel(st, AT91_SAMA5D2_MR, mr);
 
 	dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n",
 		freq, startup, prescal);
@@ -278,6 +308,7 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
 			     int *val, int *val2, long mask)
 {
 	struct at91_adc_state *st = iio_priv(indio_dev);
+	u32 cor = 0;
 	int ret;
 
 	switch (mask) {
@@ -286,6 +317,11 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
 
 		st->chan = chan;
 
+		if (chan->differential)
+			cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
+			      AT91_SAMA5D2_COR_DIFF_OFFSET;
+
+		at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
 		at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
 		at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
 		at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
@@ -298,6 +334,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
 
 		if (ret > 0) {
 			*val = st->conversion_value;
+			if (chan->scan_type.sign == 's')
+				*val = sign_extend32(*val, 11);
 			ret = IIO_VAL_INT;
 			st->conversion_done = false;
 		}
@@ -310,6 +348,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
 
 	case IIO_CHAN_INFO_SCALE:
 		*val = st->vref_uv / 1000;
+		if (chan->differential)
+			*val *= 2;
 		*val2 = chan->scan_type.realbits;
 		return IIO_VAL_FRACTIONAL_LOG2;
 
@@ -444,6 +484,12 @@ static int at91_adc_probe(struct platform_device *pdev)
 
 	at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
 	at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
+	/*
+	 * Transfer field must be set to 2 according to the datasheet and
+	 * allows different analog settings for each channel.
+	 */
+	at91_adc_writel(st, AT91_SAMA5D2_MR,
+			AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
 
 	at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
 
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f284cd6..52430ba 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -797,8 +797,8 @@ static u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz)
 	 * Startup Time = <lookup_table_value> / ADC Clock
 	 */
 	const int startup_lookup[] = {
-		0  , 8  , 16 , 24 ,
-		64 , 80 , 96 , 112,
+		0,   8,   16,  24,
+		64,  80,  96,  112,
 		512, 576, 640, 704,
 		768, 832, 896, 960
 		};
@@ -924,14 +924,14 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
 			ret = -EINVAL;
 			goto error_ret;
 		}
-	        trig->name = name;
+		trig->name = name;
 
 		if (of_property_read_u32(trig_node, "trigger-value", &prop)) {
 			dev_err(&idev->dev, "Missing trigger-value property in the DT.\n");
 			ret = -EINVAL;
 			goto error_ret;
 		}
-	        trig->value = prop;
+		trig->value = prop;
 		trig->is_external = of_property_read_bool(trig_node, "trigger-external");
 		i++;
 	}
diff --git b/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c
new file mode 100644
index 0000000..21d38c8
--- /dev/null
+++ b/drivers/iio/adc/bcm_iproc_adc.c
@@ -0,0 +1,644 @@
+/*
+ * Copyright 2016 Broadcom
+ *
+ * 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 (the "GPL").
+ *
+ * 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 version 2 (GPLv2) for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 (GPLv2) along with this source code.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <linux/iio/iio.h>
+
+/* Below Register's are common to IPROC ADC and Touchscreen IP */
+#define IPROC_REGCTL1			0x00
+#define IPROC_REGCTL2			0x04
+#define IPROC_INTERRUPT_THRES		0x08
+#define IPROC_INTERRUPT_MASK		0x0c
+#define IPROC_INTERRUPT_STATUS		0x10
+#define IPROC_ANALOG_CONTROL		0x1c
+#define IPROC_CONTROLLER_STATUS		0x14
+#define IPROC_AUX_DATA			0x20
+#define IPROC_SOFT_BYPASS_CONTROL	0x38
+#define IPROC_SOFT_BYPASS_DATA		0x3C
+
+/* IPROC ADC Channel register offsets */
+#define IPROC_ADC_CHANNEL_REGCTL1		0x800
+#define IPROC_ADC_CHANNEL_REGCTL2		0x804
+#define IPROC_ADC_CHANNEL_STATUS		0x808
+#define IPROC_ADC_CHANNEL_INTERRUPT_STATUS	0x80c
+#define IPROC_ADC_CHANNEL_INTERRUPT_MASK	0x810
+#define IPROC_ADC_CHANNEL_DATA			0x814
+#define IPROC_ADC_CHANNEL_OFFSET		0x20
+
+/* Bit definitions for IPROC_REGCTL2 */
+#define IPROC_ADC_AUXIN_SCAN_ENA	BIT(0)
+#define IPROC_ADC_PWR_LDO		BIT(5)
+#define IPROC_ADC_PWR_ADC		BIT(4)
+#define IPROC_ADC_PWR_BG		BIT(3)
+#define IPROC_ADC_CONTROLLER_EN		BIT(17)
+
+/* Bit definitions for IPROC_INTERRUPT_MASK and IPROC_INTERRUPT_STATUS */
+#define IPROC_ADC_AUXDATA_RDY_INTR	BIT(3)
+#define IPROC_ADC_INTR			9
+#define IPROC_ADC_INTR_MASK		(0xFF << IPROC_ADC_INTR)
+
+/* Bit definitions for IPROC_ANALOG_CONTROL */
+#define IPROC_ADC_CHANNEL_SEL		11
+#define IPROC_ADC_CHANNEL_SEL_MASK	(0x7 << IPROC_ADC_CHANNEL_SEL)
+
+/* Bit definitions for IPROC_ADC_CHANNEL_REGCTL1 */
+#define IPROC_ADC_CHANNEL_ROUNDS	0x2
+#define IPROC_ADC_CHANNEL_ROUNDS_MASK	(0x3F << IPROC_ADC_CHANNEL_ROUNDS)
+#define IPROC_ADC_CHANNEL_MODE		0x1
+#define IPROC_ADC_CHANNEL_MODE_MASK	(0x1 << IPROC_ADC_CHANNEL_MODE)
+#define IPROC_ADC_CHANNEL_MODE_TDM	0x1
+#define IPROC_ADC_CHANNEL_MODE_SNAPSHOT 0x0
+#define IPROC_ADC_CHANNEL_ENABLE	0x0
+#define IPROC_ADC_CHANNEL_ENABLE_MASK	0x1
+
+/* Bit definitions for IPROC_ADC_CHANNEL_REGCTL2 */
+#define IPROC_ADC_CHANNEL_WATERMARK	0x0
+#define IPROC_ADC_CHANNEL_WATERMARK_MASK \
+		(0x3F << IPROC_ADC_CHANNEL_WATERMARK)
+
+#define IPROC_ADC_WATER_MARK_LEVEL	0x1
+
+/* Bit definitions for IPROC_ADC_CHANNEL_STATUS */
+#define IPROC_ADC_CHANNEL_DATA_LOST		0x0
+#define IPROC_ADC_CHANNEL_DATA_LOST_MASK	\
+		(0x0 << IPROC_ADC_CHANNEL_DATA_LOST)
+#define IPROC_ADC_CHANNEL_VALID_ENTERIES	0x1
+#define IPROC_ADC_CHANNEL_VALID_ENTERIES_MASK	\
+		(0xFF << IPROC_ADC_CHANNEL_VALID_ENTERIES)
+#define IPROC_ADC_CHANNEL_TOTAL_ENTERIES	0x9
+#define IPROC_ADC_CHANNEL_TOTAL_ENTERIES_MASK	\
+		(0xFF << IPROC_ADC_CHANNEL_TOTAL_ENTERIES)
+
+/* Bit definitions for IPROC_ADC_CHANNEL_INTERRUPT_MASK */
+#define IPROC_ADC_CHANNEL_WTRMRK_INTR			0x0
+#define IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK		\
+		(0x1 << IPROC_ADC_CHANNEL_WTRMRK_INTR)
+#define IPROC_ADC_CHANNEL_FULL_INTR			0x1
+#define IPROC_ADC_CHANNEL_FULL_INTR_MASK		\
+		(0x1 << IPROC_ADC_IPROC_ADC_CHANNEL_FULL_INTR)
+#define IPROC_ADC_CHANNEL_EMPTY_INTR			0x2
+#define IPROC_ADC_CHANNEL_EMPTY_INTR_MASK		\
+		(0x1 << IPROC_ADC_CHANNEL_EMPTY_INTR)
+
+#define IPROC_ADC_WATER_MARK_INTR_ENABLE		0x1
+
+/* Number of time to retry a set of the interrupt mask reg */
+#define IPROC_ADC_INTMASK_RETRY_ATTEMPTS		10
+
+#define IPROC_ADC_READ_TIMEOUT        (HZ*2)
+
+#define iproc_adc_dbg_reg(dev, priv, reg) \
+do { \
+	u32 val; \
+	regmap_read(priv->regmap, reg, &val); \
+	dev_dbg(dev, "%20s= 0x%08x\n", #reg, val); \
+} while (0)
+
+struct iproc_adc_priv {
+	struct regmap *regmap;
+	struct clk *adc_clk;
+	struct mutex mutex;
+	int  irqno;
+	int chan_val;
+	int chan_id;
+	struct completion completion;
+};
+
+static void iproc_adc_reg_dump(struct iio_dev *indio_dev)
+{
+	struct device *dev = &indio_dev->dev;
+	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
+
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_REGCTL1);
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_REGCTL2);
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_THRES);
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_MASK);
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_STATUS);
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_CONTROLLER_STATUS);
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_ANALOG_CONTROL);
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_AUX_DATA);
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_SOFT_BYPASS_CONTROL);
+	iproc_adc_dbg_reg(dev, adc_priv, IPROC_SOFT_BYPASS_DATA);
+}
+
+static irqreturn_t iproc_adc_interrupt_handler(int irq, void *data)
+{
+	u32 channel_intr_status;
+	u32 intr_status;
+	u32 intr_mask;
+	struct iio_dev *indio_dev = data;
+	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
+
+	/*
+	 * This interrupt is shared with the touchscreen driver.
+	 * Make sure this interrupt is intended for us.
+	 * Handle only ADC channel specific interrupts.
+	 */
+	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_STATUS, &intr_status);
+	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &intr_mask);
+	intr_status = intr_status & intr_mask;
+	channel_intr_status = (intr_status & IPROC_ADC_INTR_MASK) >>
+				IPROC_ADC_INTR;
+	if (channel_intr_status)
+		return IRQ_WAKE_THREAD;
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t iproc_adc_interrupt_thread(int irq, void *data)
+{
+	irqreturn_t retval = IRQ_NONE;
+	struct iproc_adc_priv *adc_priv;
+	struct iio_dev *indio_dev = data;
+	unsigned int valid_entries;
+	u32 intr_status;
+	u32 intr_channels;
+	u32 channel_status;
+	u32 ch_intr_status;
+
+	adc_priv = iio_priv(indio_dev);
+
+	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_STATUS, &intr_status);
+	dev_dbg(&indio_dev->dev, "iproc_adc_interrupt_thread(),INTRPT_STS:%x\n",
+			intr_status);
+
+	intr_channels = (intr_status & IPROC_ADC_INTR_MASK) >> IPROC_ADC_INTR;
+	if (intr_channels) {
+		regmap_read(adc_priv->regmap,
+			    IPROC_ADC_CHANNEL_INTERRUPT_STATUS +
+			    IPROC_ADC_CHANNEL_OFFSET * adc_priv->chan_id,
+			    &ch_intr_status);
+
+		if (ch_intr_status & IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK) {
+			regmap_read(adc_priv->regmap,
+					IPROC_ADC_CHANNEL_STATUS +
+					IPROC_ADC_CHANNEL_OFFSET *
+					adc_priv->chan_id,
+					&channel_status);
+
+			valid_entries = ((channel_status &
+				IPROC_ADC_CHANNEL_VALID_ENTERIES_MASK) >>
+				IPROC_ADC_CHANNEL_VALID_ENTERIES);
+			if (valid_entries >= 1) {
+				regmap_read(adc_priv->regmap,
+					IPROC_ADC_CHANNEL_DATA +
+					IPROC_ADC_CHANNEL_OFFSET *
+					adc_priv->chan_id,
+					&adc_priv->chan_val);
+				complete(&adc_priv->completion);
+			} else {
+				dev_err(&indio_dev->dev,
+					"No data rcvd on channel %d\n",
+					adc_priv->chan_id);
+			}
+			regmap_write(adc_priv->regmap,
+					IPROC_ADC_CHANNEL_INTERRUPT_MASK +
+					IPROC_ADC_CHANNEL_OFFSET *
+					adc_priv->chan_id,
+					(ch_intr_status &
+					~(IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK)));
+		}
+		regmap_write(adc_priv->regmap,
+				IPROC_ADC_CHANNEL_INTERRUPT_STATUS +
+				IPROC_ADC_CHANNEL_OFFSET * adc_priv->chan_id,
+				ch_intr_status);
+		regmap_write(adc_priv->regmap, IPROC_INTERRUPT_STATUS,
+				intr_channels);
+		retval = IRQ_HANDLED;
+	}
+
+	return retval;
+}
+
+static int iproc_adc_do_read(struct iio_dev *indio_dev,
+			   int channel,
+			   u16 *p_adc_data)
+{
+	int read_len = 0;
+	u32 val;
+	u32 mask;
+	u32 val_check;
+	int failed_cnt = 0;
+	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
+
+	mutex_lock(&adc_priv->mutex);
+
+	/*
+	 * After a read is complete the ADC interrupts will be disabled so
+	 * we can assume this section of code is safe from interrupts.
+	 */
+	adc_priv->chan_val = -1;
+	adc_priv->chan_id = channel;
+
+	reinit_completion(&adc_priv->completion);
+	/* Clear any pending interrupt */
+	regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_STATUS,
+			IPROC_ADC_INTR_MASK | IPROC_ADC_AUXDATA_RDY_INTR,
+			((0x0 << channel) << IPROC_ADC_INTR) |
+			IPROC_ADC_AUXDATA_RDY_INTR);
+
+	/* Configure channel for snapshot mode and enable  */
+	val = (BIT(IPROC_ADC_CHANNEL_ROUNDS) |
+		(IPROC_ADC_CHANNEL_MODE_SNAPSHOT << IPROC_ADC_CHANNEL_MODE) |
+		(0x1 << IPROC_ADC_CHANNEL_ENABLE));
+
+	mask = IPROC_ADC_CHANNEL_ROUNDS_MASK | IPROC_ADC_CHANNEL_MODE_MASK |
+		IPROC_ADC_CHANNEL_ENABLE_MASK;
+	regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_REGCTL1 +
+				IPROC_ADC_CHANNEL_OFFSET * channel),
+				mask, val);
+
+	/* Set the Watermark for a channel */
+	regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_REGCTL2 +
+					IPROC_ADC_CHANNEL_OFFSET * channel),
+					IPROC_ADC_CHANNEL_WATERMARK_MASK,
+					0x1);
+
+	/* Enable water mark interrupt */
+	regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_INTERRUPT_MASK +
+					IPROC_ADC_CHANNEL_OFFSET *
+					channel),
+					IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK,
+					IPROC_ADC_WATER_MARK_INTR_ENABLE);
+	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val);
+
+	/* Enable ADC interrupt for a channel */
+	val |= (BIT(channel) << IPROC_ADC_INTR);
+	regmap_write(adc_priv->regmap, IPROC_INTERRUPT_MASK, val);
+
+	/*
+	 * There seems to be a very rare issue where writing to this register
+	 * does not take effect.  To work around the issue we will try multiple
+	 * writes.  In total we will spend about 10*10 = 100 us attempting this.
+	 * Testing has shown that this may loop a few time, but we have never
+	 * hit the full count.
+	 */
+	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);
+	while (val_check != val) {
+		failed_cnt++;
+
+		if (failed_cnt > IPROC_ADC_INTMASK_RETRY_ATTEMPTS)
+			break;
+
+		udelay(10);
+		regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_MASK,
+				IPROC_ADC_INTR_MASK,
+				((0x1 << channel) <<
+				IPROC_ADC_INTR));
+
+		regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);
+	}
+
+	if (failed_cnt) {
+		dev_dbg(&indio_dev->dev,
+			"IntMask failed (%d times)", failed_cnt);
+		if (failed_cnt > IPROC_ADC_INTMASK_RETRY_ATTEMPTS) {
+			dev_err(&indio_dev->dev,
+				"IntMask set failed. Read will likely fail.");
+			read_len = -EIO;
+			goto adc_err;
+		};
+	}
+	regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);
+
+	if (wait_for_completion_timeout(&adc_priv->completion,
+		IPROC_ADC_READ_TIMEOUT) > 0) {
+
+		/* Only the lower 16 bits are relevant */
+		*p_adc_data = adc_priv->chan_val & 0xFFFF;
+		read_len = sizeof(*p_adc_data);
+
+	} else {
+		/*
+		 * We never got the interrupt, something went wrong.
+		 * Perhaps the interrupt may still be coming, we do not want
+		 * that now.  Lets disable the ADC interrupt, and clear the
+		 * status to put it back in to normal state.
+		 */
+		read_len = -ETIMEDOUT;
+		goto adc_err;
+	}
+	mutex_unlock(&adc_priv->mutex);
+
+	return read_len;
+
+adc_err:
+	regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_MASK,
+			   IPROC_ADC_INTR_MASK,
+			   ((0x0 << channel) << IPROC_ADC_INTR));
+
+	regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_STATUS,
+			   IPROC_ADC_INTR_MASK,
+			   ((0x0 << channel) << IPROC_ADC_INTR));
+
+	dev_err(&indio_dev->dev, "Timed out waiting for ADC data!\n");
+	iproc_adc_reg_dump(indio_dev);
+	mutex_unlock(&adc_priv->mutex);
+
+	return read_len;
+}
+
+static int iproc_adc_enable(struct iio_dev *indio_dev)
+{
+	u32 val;
+	u32 channel_id;
+	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
+	int ret;
+
+	/* Set i_amux = 3b'000, select channel 0 */
+	ret = regmap_update_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL,
+				IPROC_ADC_CHANNEL_SEL_MASK, 0);
+	if (ret) {
+		dev_err(&indio_dev->dev,
+			"failed to write IPROC_ANALOG_CONTROL %d\n", ret);
+		return ret;
+	}
+	adc_priv->chan_val = -1;
+
+	/*
+	 * PWR up LDO, ADC, and Band Gap (0 to enable)
+	 * Also enable ADC controller (set high)
+	 */
+	ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val);
+	if (ret) {
+		dev_err(&indio_dev->dev,
+			"failed to read IPROC_REGCTL2 %d\n", ret);
+		return ret;
+	}
+
+	val &= ~(IPROC_ADC_PWR_LDO | IPROC_ADC_PWR_ADC | IPROC_ADC_PWR_BG);
+
+	ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val);
+	if (ret) {
+		dev_err(&indio_dev->dev,
+			"failed to write IPROC_REGCTL2 %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val);
+	if (ret) {
+		dev_err(&indio_dev->dev,
+			"failed to read IPROC_REGCTL2 %d\n", ret);
+		return ret;
+	}
+
+	val |= IPROC_ADC_CONTROLLER_EN;
+	ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val);
+	if (ret) {
+		dev_err(&indio_dev->dev,
+			"failed to write IPROC_REGCTL2 %d\n", ret);
+		return ret;
+	}
+
+	for (channel_id = 0; channel_id < indio_dev->num_channels;
+		channel_id++) {
+		ret = regmap_write(adc_priv->regmap,
+				IPROC_ADC_CHANNEL_INTERRUPT_MASK +
+				IPROC_ADC_CHANNEL_OFFSET * channel_id, 0);
+		if (ret) {
+			dev_err(&indio_dev->dev,
+			    "failed to write ADC_CHANNEL_INTERRUPT_MASK %d\n",
+			    ret);
+			return ret;
+		}
+
+		ret = regmap_write(adc_priv->regmap,
+				IPROC_ADC_CHANNEL_INTERRUPT_STATUS +
+				IPROC_ADC_CHANNEL_OFFSET * channel_id, 0);
+		if (ret) {
+			dev_err(&indio_dev->dev,
+			    "failed to write ADC_CHANNEL_INTERRUPT_STATUS %d\n",
+			    ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void iproc_adc_disable(struct iio_dev *indio_dev)
+{
+	u32 val;
+	int ret;
+	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
+
+	ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val);
+	if (ret) {
+		dev_err(&indio_dev->dev,
+			"failed to read IPROC_REGCTL2 %d\n", ret);
+		return;
+	}
+
+	val &= ~IPROC_ADC_CONTROLLER_EN;
+	ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val);
+	if (ret) {
+		dev_err(&indio_dev->dev,
+			"failed to write IPROC_REGCTL2 %d\n", ret);
+		return;
+	}
+}
+
+static int iproc_adc_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan,
+			  int *val,
+			  int *val2,
+			  long mask)
+{
+	u16 adc_data;
+	int err;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		err =  iproc_adc_do_read(indio_dev, chan->channel, &adc_data);
+		if (err < 0)
+			return err;
+		*val = adc_data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_VOLTAGE:
+			*val = 1800;
+			*val2 = 10;
+			return IIO_VAL_FRACTIONAL_LOG2;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info iproc_adc_iio_info = {
+	.read_raw = &iproc_adc_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+#define IPROC_ADC_CHANNEL(_index, _id) {                \
+	.type = IIO_VOLTAGE,                            \
+	.indexed = 1,                                   \
+	.channel = _index,                              \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+	.datasheet_name = _id,                          \
+}
+
+static const struct iio_chan_spec iproc_adc_iio_channels[] = {
+	IPROC_ADC_CHANNEL(0, "adc0"),
+	IPROC_ADC_CHANNEL(1, "adc1"),
+	IPROC_ADC_CHANNEL(2, "adc2"),
+	IPROC_ADC_CHANNEL(3, "adc3"),
+	IPROC_ADC_CHANNEL(4, "adc4"),
+	IPROC_ADC_CHANNEL(5, "adc5"),
+	IPROC_ADC_CHANNEL(6, "adc6"),
+	IPROC_ADC_CHANNEL(7, "adc7"),
+};
+
+static int iproc_adc_probe(struct platform_device *pdev)
+{
+	struct iproc_adc_priv *adc_priv;
+	struct iio_dev *indio_dev = NULL;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev,
+					sizeof(*adc_priv));
+	if (!indio_dev) {
+		dev_err(&pdev->dev, "failed to allocate iio device\n");
+		return -ENOMEM;
+	}
+
+	adc_priv = iio_priv(indio_dev);
+	platform_set_drvdata(pdev, indio_dev);
+
+	mutex_init(&adc_priv->mutex);
+
+	init_completion(&adc_priv->completion);
+
+	adc_priv->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+			   "adc-syscon");
+	if (IS_ERR(adc_priv->regmap)) {
+		dev_err(&pdev->dev, "failed to get handle for tsc syscon\n");
+		ret = PTR_ERR(adc_priv->regmap);
+		return ret;
+	}
+
+	adc_priv->adc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
+	if (IS_ERR(adc_priv->adc_clk)) {
+		dev_err(&pdev->dev,
+			"failed getting clock tsc_clk\n");
+		ret = PTR_ERR(adc_priv->adc_clk);
+		return ret;
+	}
+
+	adc_priv->irqno = platform_get_irq(pdev, 0);
+	if (adc_priv->irqno <= 0) {
+		dev_err(&pdev->dev, "platform_get_irq failed\n");
+		ret = -ENODEV;
+		return ret;
+	}
+
+	ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2,
+				IPROC_ADC_AUXIN_SCAN_ENA, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to write IPROC_REGCTL2 %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, adc_priv->irqno,
+				iproc_adc_interrupt_thread,
+				iproc_adc_interrupt_handler,
+				IRQF_SHARED, "iproc-adc", indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request_irq error %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(adc_priv->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"clk_prepare_enable failed %d\n", ret);
+		return ret;
+	}
+
+	ret = iproc_adc_enable(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable adc %d\n", ret);
+		goto err_adc_enable;
+	}
+
+	indio_dev->name = "iproc-static-adc";
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->dev.of_node = pdev->dev.of_node;
+	indio_dev->info = &iproc_adc_iio_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = iproc_adc_iio_channels;
+	indio_dev->num_channels = ARRAY_SIZE(iproc_adc_iio_channels);
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "iio_device_register failed:err %d\n", ret);
+		goto err_clk;
+	}
+
+	return 0;
+
+err_clk:
+	iproc_adc_disable(indio_dev);
+err_adc_enable:
+	clk_disable_unprepare(adc_priv->adc_clk);
+
+	return ret;
+}
+
+static int iproc_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	iproc_adc_disable(indio_dev);
+	clk_disable_unprepare(adc_priv->adc_clk);
+
+	return 0;
+}
+
+static const struct of_device_id iproc_adc_of_match[] = {
+	{.compatible = "brcm,iproc-static-adc", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, iproc_adc_of_match);
+
+static struct platform_driver iproc_adc_driver = {
+	.probe  = iproc_adc_probe,
+	.remove	= iproc_adc_remove,
+	.driver	= {
+		.name	= "iproc-static-adc",
+		.of_match_table = of_match_ptr(iproc_adc_of_match),
+	},
+};
+module_platform_driver(iproc_adc_driver);
+
+MODULE_DESCRIPTION("Broadcom iProc ADC controller driver");
+MODULE_AUTHOR("Raveendra Padasalagi <raveendra.padasalagi@broadcom.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c
index 8254f52..91636c0 100644
--- a/drivers/iio/adc/cc10001_adc.c
+++ b/drivers/iio/adc/cc10001_adc.c
@@ -186,7 +186,7 @@ done:
 
 	if (!sample_invalid)
 		iio_push_to_buffers_with_timestamp(indio_dev, data,
-						   iio_get_time_ns());
+						   iio_get_time_ns(indio_dev));
 	iio_trigger_notify_done(indio_dev->trig);
 
 	return IRQ_HANDLED;
diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c
index c73c6c6..678e8c7 100644
--- a/drivers/iio/adc/hi8435.c
+++ b/drivers/iio/adc/hi8435.c
@@ -400,7 +400,7 @@ static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val)
 			iio_push_event(idev,
 				       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
 						    IIO_EV_TYPE_THRESH, dir),
-				       iio_get_time_ns());
+				       iio_get_time_ns(idev));
 		}
 	}
 
@@ -455,6 +455,7 @@ static int hi8435_probe(struct spi_device *spi)
 	mutex_init(&priv->lock);
 
 	idev->dev.parent	= &spi->dev;
+	idev->dev.of_node	= spi->dev.of_node;
 	idev->name		= spi_get_device_id(spi)->name;
 	idev->modes		= INDIO_DIRECT_MODE;
 	idev->info		= &hi8435_info;
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index 65909d5..955f3fd 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -185,9 +185,9 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_SCALE:
 		switch (chan->address) {
 		case INA2XX_SHUNT_VOLTAGE:
-			/* processed (mV) = raw*1000/shunt_div */
+			/* processed (mV) = raw/shunt_div */
 			*val2 = chip->config->shunt_div;
-			*val = 1000;
+			*val = 1;
 			return IIO_VAL_FRACTIONAL;
 
 		case INA2XX_BUS_VOLTAGE:
@@ -350,6 +350,23 @@ static ssize_t ina2xx_allow_async_readout_store(struct device *dev,
 	return len;
 }
 
+/*
+ * Set current LSB to 1mA, shunt is in uOhms
+ * (equation 13 in datasheet). We hardcode a Current_LSB
+ * of 1.0 x10-6. The only remaining parameter is RShunt.
+ * There is no need to expose the CALIBRATION register
+ * to the user for now. But we need to reset this register
+ * if the user updates RShunt after driver init, e.g upon
+ * reading an EEPROM/Probe-type value.
+ */
+static int ina2xx_set_calibration(struct ina2xx_chip_info *chip)
+{
+	u16 regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
+				   chip->shunt_resistor);
+
+	return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
+}
+
 static int set_shunt_resistor(struct ina2xx_chip_info *chip, unsigned int val)
 {
 	if (val <= 0 || val > chip->config->calibration_factor)
@@ -385,6 +402,11 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
 	if (ret)
 		return ret;
 
+	/* Update the Calibration register */
+	ret = ina2xx_set_calibration(chip);
+	if (ret)
+		return ret;
+
 	return len;
 }
 
@@ -443,7 +465,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
 	s64 time_a, time_b;
 	unsigned int alert;
 
-	time_a = iio_get_time_ns();
+	time_a = iio_get_time_ns(indio_dev);
 
 	/*
 	 * Because the timer thread and the chip conversion clock
@@ -482,7 +504,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
 		data[i++] = val;
 	}
 
-	time_b = iio_get_time_ns();
+	time_b = iio_get_time_ns(indio_dev);
 
 	iio_push_to_buffers_with_timestamp(indio_dev,
 					   (unsigned int *)data, time_a);
@@ -532,7 +554,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
 	dev_dbg(&indio_dev->dev, "Async readout mode: %d\n",
 		chip->allow_async_readout);
 
-	chip->prev_ns = iio_get_time_ns();
+	chip->prev_ns = iio_get_time_ns(indio_dev);
 
 	chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev,
 				 "%s:%d-%uus", indio_dev->name, indio_dev->id,
@@ -602,24 +624,11 @@ static const struct iio_info ina2xx_info = {
 /* Initialize the configuration and calibration registers. */
 static int ina2xx_init(struct ina2xx_chip_info *chip, unsigned int config)
 {
-	u16 regval;
-	int ret;
-
-	ret = regmap_write(chip->regmap, INA2XX_CONFIG, config);
+	int ret = regmap_write(chip->regmap, INA2XX_CONFIG, config);
 	if (ret)
 		return ret;
 
-	/*
-	 * Set current LSB to 1mA, shunt is in uOhms
-	 * (equation 13 in datasheet). We hardcode a Current_LSB
-	 * of 1.0 x10-6. The only remaining parameter is RShunt.
-	 * There is no need to expose the CALIBRATION register
-	 * to the user for now.
-	 */
-	regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
-				   chip->shunt_resistor);
-
-	return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
+	return ina2xx_set_calibration(chip);
 }
 
 static int ina2xx_probe(struct i2c_client *client,
@@ -682,6 +691,7 @@ static int ina2xx_probe(struct i2c_client *client,
 
 	indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
 	indio_dev->dev.parent = &client->dev;
+	indio_dev->dev.of_node = client->dev.of_node;
 	indio_dev->channels = ina2xx_channels;
 	indio_dev->num_channels = ARRAY_SIZE(ina2xx_channels);
 	indio_dev->name = id->name;
diff --git b/drivers/iio/adc/lpc18xx_adc.c b/drivers/iio/adc/lpc18xx_adc.c
new file mode 100644
index 0000000..3ef18f4
--- /dev/null
+++ b/drivers/iio/adc/lpc18xx_adc.c
@@ -0,0 +1,231 @@
+/*
+ * IIO ADC driver for NXP LPC18xx ADC
+ *
+ * Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com>
+ *
+ * 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.
+ *
+ * UNSUPPORTED hardware features:
+ *  - Hardware triggers
+ *  - Burst mode
+ *  - Interrupts
+ *  - DMA
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+/* LPC18XX ADC registers and bits */
+#define LPC18XX_ADC_CR			0x000
+#define  LPC18XX_ADC_CR_CLKDIV_SHIFT	8
+#define  LPC18XX_ADC_CR_PDN		BIT(21)
+#define  LPC18XX_ADC_CR_START_NOW	(0x1 << 24)
+#define LPC18XX_ADC_GDR			0x004
+
+/* Data register bits */
+#define LPC18XX_ADC_SAMPLE_SHIFT	6
+#define LPC18XX_ADC_SAMPLE_MASK		0x3ff
+#define LPC18XX_ADC_CONV_DONE		BIT(31)
+
+/* Clock should be 4.5 MHz or less */
+#define LPC18XX_ADC_CLK_TARGET		4500000
+
+struct lpc18xx_adc {
+	struct regulator *vref;
+	void __iomem *base;
+	struct device *dev;
+	struct mutex lock;
+	struct clk *clk;
+	u32 cr_reg;
+};
+
+#define LPC18XX_ADC_CHAN(_idx) {				\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.channel = _idx,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+static const struct iio_chan_spec lpc18xx_adc_iio_channels[] = {
+	LPC18XX_ADC_CHAN(0),
+	LPC18XX_ADC_CHAN(1),
+	LPC18XX_ADC_CHAN(2),
+	LPC18XX_ADC_CHAN(3),
+	LPC18XX_ADC_CHAN(4),
+	LPC18XX_ADC_CHAN(5),
+	LPC18XX_ADC_CHAN(6),
+	LPC18XX_ADC_CHAN(7),
+};
+
+static int lpc18xx_adc_read_chan(struct lpc18xx_adc *adc, unsigned int ch)
+{
+	int ret;
+	u32 reg;
+
+	reg = adc->cr_reg | BIT(ch) | LPC18XX_ADC_CR_START_NOW;
+	writel(reg, adc->base + LPC18XX_ADC_CR);
+
+	ret = readl_poll_timeout(adc->base + LPC18XX_ADC_GDR, reg,
+				 reg & LPC18XX_ADC_CONV_DONE, 3, 9);
+	if (ret) {
+		dev_warn(adc->dev, "adc read timed out\n");
+		return ret;
+	}
+
+	return (reg >> LPC18XX_ADC_SAMPLE_SHIFT) & LPC18XX_ADC_SAMPLE_MASK;
+}
+
+static int lpc18xx_adc_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct lpc18xx_adc *adc = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&adc->lock);
+		*val = lpc18xx_adc_read_chan(adc, chan->channel);
+		mutex_unlock(&adc->lock);
+		if (*val < 0)
+			return *val;
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		*val = regulator_get_voltage(adc->vref) / 1000;
+		*val2 = 10;
+
+		return IIO_VAL_FRACTIONAL_LOG2;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info lpc18xx_adc_info = {
+	.read_raw = lpc18xx_adc_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int lpc18xx_adc_probe(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev;
+	struct lpc18xx_adc *adc;
+	struct resource *res;
+	unsigned int clkdiv;
+	unsigned long rate;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, indio_dev);
+	adc = iio_priv(indio_dev);
+	adc->dev = &pdev->dev;
+	mutex_init(&adc->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	adc->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(adc->base))
+		return PTR_ERR(adc->base);
+
+	adc->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(adc->clk)) {
+		dev_err(&pdev->dev, "error getting clock\n");
+		return PTR_ERR(adc->clk);
+	}
+
+	rate = clk_get_rate(adc->clk);
+	clkdiv = DIV_ROUND_UP(rate, LPC18XX_ADC_CLK_TARGET);
+
+	adc->vref = devm_regulator_get(&pdev->dev, "vref");
+	if (IS_ERR(adc->vref)) {
+		dev_err(&pdev->dev, "error getting regulator\n");
+		return PTR_ERR(adc->vref);
+	}
+
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &lpc18xx_adc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = lpc18xx_adc_iio_channels;
+	indio_dev->num_channels = ARRAY_SIZE(lpc18xx_adc_iio_channels);
+
+	ret = regulator_enable(adc->vref);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to enable regulator\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(adc->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to enable clock\n");
+		goto dis_reg;
+	}
+
+	adc->cr_reg = (clkdiv << LPC18XX_ADC_CR_CLKDIV_SHIFT) |
+			LPC18XX_ADC_CR_PDN;
+	writel(adc->cr_reg, adc->base + LPC18XX_ADC_CR);
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register device\n");
+		goto dis_clk;
+	}
+
+	return 0;
+
+dis_clk:
+	writel(0, adc->base + LPC18XX_ADC_CR);
+	clk_disable_unprepare(adc->clk);
+dis_reg:
+	regulator_disable(adc->vref);
+	return ret;
+}
+
+static int lpc18xx_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct lpc18xx_adc *adc = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	writel(0, adc->base + LPC18XX_ADC_CR);
+	clk_disable_unprepare(adc->clk);
+	regulator_disable(adc->vref);
+
+	return 0;
+}
+
+static const struct of_device_id lpc18xx_adc_match[] = {
+	{ .compatible = "nxp,lpc1850-adc" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, lpc18xx_adc_match);
+
+static struct platform_driver lpc18xx_adc_driver = {
+	.probe	= lpc18xx_adc_probe,
+	.remove	= lpc18xx_adc_remove,
+	.driver	= {
+		.name = "lpc18xx-adc",
+		.of_match_table = lpc18xx_adc_match,
+	},
+};
+module_platform_driver(lpc18xx_adc_driver);
+
+MODULE_DESCRIPTION("LPC18xx ADC driver");
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c
index 41d495c..712fbd2 100644
--- a/drivers/iio/adc/max1027.c
+++ b/drivers/iio/adc/max1027.c
@@ -426,6 +426,7 @@ static int max1027_probe(struct spi_device *spi)
 
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->info = &max1027_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = st->info->channels;
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 998dc3c..841a13c 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -25,6 +25,8 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -788,7 +790,7 @@ static irqreturn_t max1363_event_handler(int irq, void *private)
 {
 	struct iio_dev *indio_dev = private;
 	struct max1363_state *st = iio_priv(indio_dev);
-	s64 timestamp = iio_get_time_ns();
+	s64 timestamp = iio_get_time_ns(indio_dev);
 	unsigned long mask, loc;
 	u8 rx;
 	u8 tx[2] = { st->setupbyte,
@@ -1506,7 +1508,8 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
 	if (b_sent < 0)
 		goto done_free;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, iio_get_time_ns());
+	iio_push_to_buffers_with_timestamp(indio_dev, rxbuf,
+					   iio_get_time_ns(indio_dev));
 
 done_free:
 	kfree(rxbuf);
@@ -1516,6 +1519,56 @@ done:
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_OF
+
+#define MAX1363_COMPATIBLE(of_compatible, cfg) {		\
+			.compatible = of_compatible,		\
+			.data = &max1363_chip_info_tbl[cfg],	\
+}
+
+static const struct of_device_id max1363_of_match[] = {
+	MAX1363_COMPATIBLE("maxim,max1361", max1361),
+	MAX1363_COMPATIBLE("maxim,max1362", max1362),
+	MAX1363_COMPATIBLE("maxim,max1363", max1363),
+	MAX1363_COMPATIBLE("maxim,max1364", max1364),
+	MAX1363_COMPATIBLE("maxim,max1036", max1036),
+	MAX1363_COMPATIBLE("maxim,max1037", max1037),
+	MAX1363_COMPATIBLE("maxim,max1038", max1038),
+	MAX1363_COMPATIBLE("maxim,max1039", max1039),
+	MAX1363_COMPATIBLE("maxim,max1136", max1136),
+	MAX1363_COMPATIBLE("maxim,max1137", max1137),
+	MAX1363_COMPATIBLE("maxim,max1138", max1138),
+	MAX1363_COMPATIBLE("maxim,max1139", max1139),
+	MAX1363_COMPATIBLE("maxim,max1236", max1236),
+	MAX1363_COMPATIBLE("maxim,max1237", max1237),
+	MAX1363_COMPATIBLE("maxim,max1238", max1238),
+	MAX1363_COMPATIBLE("maxim,max1239", max1239),
+	MAX1363_COMPATIBLE("maxim,max11600", max11600),
+	MAX1363_COMPATIBLE("maxim,max11601", max11601),
+	MAX1363_COMPATIBLE("maxim,max11602", max11602),
+	MAX1363_COMPATIBLE("maxim,max11603", max11603),
+	MAX1363_COMPATIBLE("maxim,max11604", max11604),
+	MAX1363_COMPATIBLE("maxim,max11605", max11605),
+	MAX1363_COMPATIBLE("maxim,max11606", max11606),
+	MAX1363_COMPATIBLE("maxim,max11607", max11607),
+	MAX1363_COMPATIBLE("maxim,max11608", max11608),
+	MAX1363_COMPATIBLE("maxim,max11609", max11609),
+	MAX1363_COMPATIBLE("maxim,max11610", max11610),
+	MAX1363_COMPATIBLE("maxim,max11611", max11611),
+	MAX1363_COMPATIBLE("maxim,max11612", max11612),
+	MAX1363_COMPATIBLE("maxim,max11613", max11613),
+	MAX1363_COMPATIBLE("maxim,max11614", max11614),
+	MAX1363_COMPATIBLE("maxim,max11615", max11615),
+	MAX1363_COMPATIBLE("maxim,max11616", max11616),
+	MAX1363_COMPATIBLE("maxim,max11617", max11617),
+	MAX1363_COMPATIBLE("maxim,max11644", max11644),
+	MAX1363_COMPATIBLE("maxim,max11645", max11645),
+	MAX1363_COMPATIBLE("maxim,max11646", max11646),
+	MAX1363_COMPATIBLE("maxim,max11647", max11647),
+	{ /* sentinel */ }
+};
+#endif
+
 static int max1363_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
@@ -1523,6 +1576,7 @@ static int max1363_probe(struct i2c_client *client,
 	struct max1363_state *st;
 	struct iio_dev *indio_dev;
 	struct regulator *vref;
+	const struct of_device_id *match;
 
 	indio_dev = devm_iio_device_alloc(&client->dev,
 					  sizeof(struct max1363_state));
@@ -1549,7 +1603,12 @@ static int max1363_probe(struct i2c_client *client,
 	/* this is only used for device removal purposes */
 	i2c_set_clientdata(client, indio_dev);
 
-	st->chip_info = &max1363_chip_info_tbl[id->driver_data];
+	match = of_match_device(of_match_ptr(max1363_of_match),
+				&client->dev);
+	if (match)
+		st->chip_info = of_device_get_match_data(&client->dev);
+	else
+		st->chip_info = &max1363_chip_info_tbl[id->driver_data];
 	st->client = client;
 
 	st->vref_uv = st->chip_info->int_vref_mv * 1000;
@@ -1587,6 +1646,7 @@ static int max1363_probe(struct i2c_client *client,
 
 	/* Establish that the iio_dev is a child of the i2c device */
 	indio_dev->dev.parent = &client->dev;
+	indio_dev->dev.of_node = client->dev.of_node;
 	indio_dev->name = id->name;
 	indio_dev->channels = st->chip_info->channels;
 	indio_dev->num_channels = st->chip_info->num_channels;
@@ -1692,6 +1752,7 @@ MODULE_DEVICE_TABLE(i2c, max1363_id);
 static struct i2c_driver max1363_driver = {
 	.driver = {
 		.name = "max1363",
+		.of_match_table = of_match_ptr(max1363_of_match),
 	},
 	.probe = max1363_probe,
 	.remove = max1363_remove,
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index a850ca7..634717a 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -308,6 +308,7 @@ static int mcp320x_probe(struct spi_device *spi)
 	adc->spi = spi;
 
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &mcp320x_info;
diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c
index d7b36ef..254135e 100644
--- a/drivers/iio/adc/mcp3422.c
+++ b/drivers/iio/adc/mcp3422.c
@@ -61,9 +61,9 @@
 
 static const int mcp3422_scales[4][4] = {
 	{ 1000000, 500000, 250000, 125000 },
-	{ 250000 , 125000, 62500 , 31250  },
-	{ 62500  , 31250 , 15625 , 7812   },
-	{ 15625  , 7812  , 3906  , 1953   } };
+	{ 250000,  125000, 62500,  31250  },
+	{ 62500,   31250,  15625,  7812   },
+	{ 15625,   7812,   3906,   1953   } };
 
 /* Constant msleep times for data acquisitions */
 static const int mcp3422_read_times[4] = {
@@ -352,6 +352,7 @@ static int mcp3422_probe(struct i2c_client *client,
 	mutex_init(&adc->lock);
 
 	indio_dev->dev.parent = &client->dev;
+	indio_dev->dev.of_node = client->dev.of_node;
 	indio_dev->name = dev_name(&client->dev);
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &mcp3422_info;
diff --git a/drivers/iio/adc/mxs-lradc.c b/drivers/iio/adc/mxs-lradc.c
index 33051b8..b84d37c 100644
--- a/drivers/iio/adc/mxs-lradc.c
+++ b/drivers/iio/adc/mxs-lradc.c
@@ -373,13 +373,6 @@ static u32 mxs_lradc_plate_mask(struct mxs_lradc *lradc)
 	return LRADC_CTRL0_MX28_PLATE_MASK;
 }
 
-static u32 mxs_lradc_irq_en_mask(struct mxs_lradc *lradc)
-{
-	if (lradc->soc == IMX23_LRADC)
-		return LRADC_CTRL1_MX23_LRADC_IRQ_EN_MASK;
-	return LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK;
-}
-
 static u32 mxs_lradc_irq_mask(struct mxs_lradc *lradc)
 {
 	if (lradc->soc == IMX23_LRADC)
@@ -686,6 +679,17 @@ static void mxs_lradc_prepare_pressure(struct mxs_lradc *lradc)
 
 static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
 {
+	/* Configure the touchscreen type */
+	if (lradc->soc == IMX28_LRADC) {
+		mxs_lradc_reg_clear(lradc, LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
+				    LRADC_CTRL0);
+
+		if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE)
+			mxs_lradc_reg_set(lradc,
+					  LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
+					  LRADC_CTRL0);
+	}
+
 	mxs_lradc_setup_touch_detection(lradc);
 
 	lradc->cur_plate = LRADC_TOUCH;
@@ -1109,24 +1113,23 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc)
 {
 	struct input_dev *input;
 	struct device *dev = lradc->dev;
-	int ret;
 
 	if (!lradc->use_touchscreen)
 		return 0;
 
-	input = input_allocate_device();
+	input = devm_input_allocate_device(dev);
 	if (!input)
 		return -ENOMEM;
 
 	input->name = DRIVER_NAME;
 	input->id.bustype = BUS_HOST;
-	input->dev.parent = dev;
 	input->open = mxs_lradc_ts_open;
 	input->close = mxs_lradc_ts_close;
 
 	__set_bit(EV_ABS, input->evbit);
 	__set_bit(EV_KEY, input->evbit);
 	__set_bit(BTN_TOUCH, input->keybit);
+	__set_bit(INPUT_PROP_DIRECT, input->propbit);
 	input_set_abs_params(input, ABS_X, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
 	input_set_abs_params(input, ABS_Y, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
 	input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_SINGLE_SAMPLE_MASK,
@@ -1134,20 +1137,8 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc)
 
 	lradc->ts_input = input;
 	input_set_drvdata(input, lradc);
-	ret = input_register_device(input);
-	if (ret)
-		input_free_device(lradc->ts_input);
-
-	return ret;
-}
-
-static void mxs_lradc_ts_unregister(struct mxs_lradc *lradc)
-{
-	if (!lradc->use_touchscreen)
-		return;
 
-	mxs_lradc_disable_ts(lradc);
-	input_unregister_device(lradc->ts_input);
+	return input_register_device(input);
 }
 
 /*
@@ -1475,18 +1466,13 @@ static const struct iio_chan_spec mx28_lradc_chan_spec[] = {
 	MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
 };
 
-static int mxs_lradc_hw_init(struct mxs_lradc *lradc)
+static void mxs_lradc_hw_init(struct mxs_lradc *lradc)
 {
 	/* The ADC always uses DELAY CHANNEL 0. */
 	const u32 adc_cfg =
 		(1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + 0)) |
 		(LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET);
 
-	int ret = stmp_reset_block(lradc->base);
-
-	if (ret)
-		return ret;
-
 	/* Configure DELAY CHANNEL 0 for generic ADC sampling. */
 	mxs_lradc_reg_wrt(lradc, adc_cfg, LRADC_DELAY(0));
 
@@ -1495,27 +1481,17 @@ static int mxs_lradc_hw_init(struct mxs_lradc *lradc)
 	mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
 	mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
 
-	/* Configure the touchscreen type */
-	if (lradc->soc == IMX28_LRADC) {
-		mxs_lradc_reg_clear(lradc, LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
-				    LRADC_CTRL0);
-
-	if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE)
-		mxs_lradc_reg_set(lradc, LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
-				  LRADC_CTRL0);
-	}
-
 	/* Start internal temperature sensing. */
 	mxs_lradc_reg_wrt(lradc, 0, LRADC_CTRL2);
-
-	return 0;
 }
 
 static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
 {
 	int i;
 
-	mxs_lradc_reg_clear(lradc, mxs_lradc_irq_en_mask(lradc), LRADC_CTRL1);
+	mxs_lradc_reg_clear(lradc,
+		lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+		LRADC_CTRL1);
 
 	for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
 		mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(i));
@@ -1708,11 +1684,13 @@ static int mxs_lradc_probe(struct platform_device *pdev)
 		}
 	}
 
-	/* Configure the hardware. */
-	ret = mxs_lradc_hw_init(lradc);
+	ret = stmp_reset_block(lradc->base);
 	if (ret)
 		goto err_dev;
 
+	/* Configure the hardware. */
+	mxs_lradc_hw_init(lradc);
+
 	/* Register the touchscreen input device. */
 	if (touch_ret == 0) {
 		ret = mxs_lradc_ts_register(lradc);
@@ -1724,13 +1702,11 @@ static int mxs_lradc_probe(struct platform_device *pdev)
 	ret = iio_device_register(iio);
 	if (ret) {
 		dev_err(dev, "Failed to register IIO device\n");
-		goto err_ts;
+		return ret;
 	}
 
 	return 0;
 
-err_ts:
-	mxs_lradc_ts_unregister(lradc);
 err_ts_register:
 	mxs_lradc_hw_stop(lradc);
 err_dev:
@@ -1748,7 +1724,6 @@ static int mxs_lradc_remove(struct platform_device *pdev)
 	struct mxs_lradc *lradc = iio_priv(iio);
 
 	iio_device_unregister(iio);
-	mxs_lradc_ts_unregister(lradc);
 	mxs_lradc_hw_stop(lradc);
 	mxs_lradc_trigger_remove(iio);
 	iio_triggered_buffer_cleanup(iio);
diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c
index e525aa6..db9b829 100644
--- a/drivers/iio/adc/nau7802.c
+++ b/drivers/iio/adc/nau7802.c
@@ -79,10 +79,29 @@ static const struct iio_chan_spec nau7802_chan_array[] = {
 static const u16 nau7802_sample_freq_avail[] = {10, 20, 40, 80,
 						10, 10, 10, 320};
 
+static ssize_t nau7802_show_scales(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct nau7802_state *st = iio_priv(dev_to_iio_dev(dev));
+	int i, len = 0;
+
+	for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%09d ",
+				 st->scale_avail[i]);
+
+	buf[len-1] = '\n';
+
+	return len;
+}
+
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 40 80 320");
 
+static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, nau7802_show_scales,
+		       NULL, 0);
+
 static struct attribute *nau7802_attributes[] = {
 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
 	NULL
 };
 
@@ -414,6 +433,7 @@ static int nau7802_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, indio_dev);
 
 	indio_dev->dev.parent = &client->dev;
+	indio_dev->dev.of_node = client->dev.of_node;
 	indio_dev->name = dev_name(&client->dev);
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &nau7802_info;
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 9c311c1..f9ad6c2 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -159,6 +159,22 @@ static const struct rockchip_saradc_data rk3066_tsadc_data = {
 	.clk_rate = 50000,
 };
 
+static const struct iio_chan_spec rockchip_rk3399_saradc_iio_channels[] = {
+	ADC_CHANNEL(0, "adc0"),
+	ADC_CHANNEL(1, "adc1"),
+	ADC_CHANNEL(2, "adc2"),
+	ADC_CHANNEL(3, "adc3"),
+	ADC_CHANNEL(4, "adc4"),
+	ADC_CHANNEL(5, "adc5"),
+};
+
+static const struct rockchip_saradc_data rk3399_saradc_data = {
+	.num_bits = 10,
+	.channels = rockchip_rk3399_saradc_iio_channels,
+	.num_channels = ARRAY_SIZE(rockchip_rk3399_saradc_iio_channels),
+	.clk_rate = 1000000,
+};
+
 static const struct of_device_id rockchip_saradc_match[] = {
 	{
 		.compatible = "rockchip,saradc",
@@ -166,6 +182,9 @@ static const struct of_device_id rockchip_saradc_match[] = {
 	}, {
 		.compatible = "rockchip,rk3066-tsadc",
 		.data = &rk3066_tsadc_data,
+	}, {
+		.compatible = "rockchip,rk3399-saradc",
+		.data = &rk3399_saradc_data,
 	},
 	{},
 };
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index ecbc121..319172c 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -1,22 +1,41 @@
 /*
+ * TI ADC081C/ADC101C/ADC121C 8/10/12-bit ADC driver
+ *
  * Copyright (C) 2012 Avionic Design GmbH
+ * Copyright (C) 2016 Intel
  *
  * 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.
+ *
+ * Datasheets:
+ *	http://www.ti.com/lit/ds/symlink/adc081c021.pdf
+ *	http://www.ti.com/lit/ds/symlink/adc101c021.pdf
+ *	http://www.ti.com/lit/ds/symlink/adc121c021.pdf
+ *
+ * The devices have a very similar interface and differ mostly in the number of
+ * bits handled. For the 8-bit and 10-bit models the least-significant 4 or 2
+ * bits of value registers are reserved.
  */
 
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/acpi.h>
 
 #include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 #include <linux/regulator/consumer.h>
 
 struct adc081c {
 	struct i2c_client *i2c;
 	struct regulator *ref;
+
+	/* 8, 10 or 12 */
+	int bits;
 };
 
 #define REG_CONV_RES 0x00
@@ -34,7 +53,7 @@ static int adc081c_read_raw(struct iio_dev *iio,
 		if (err < 0)
 			return err;
 
-		*value = (err >> 4) & 0xff;
+		*value = (err & 0xFFF) >> (12 - adc->bits);
 		return IIO_VAL_INT;
 
 	case IIO_CHAN_INFO_SCALE:
@@ -43,7 +62,7 @@ static int adc081c_read_raw(struct iio_dev *iio,
 			return err;
 
 		*value = err / 1000;
-		*shift = 8;
+		*shift = adc->bits;
 
 		return IIO_VAL_FRACTIONAL_LOG2;
 
@@ -54,10 +73,53 @@ static int adc081c_read_raw(struct iio_dev *iio,
 	return -EINVAL;
 }
 
-static const struct iio_chan_spec adc081c_channel = {
-	.type = IIO_VOLTAGE,
-	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
-	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+#define ADCxx1C_CHAN(_bits) {					\
+	.type = IIO_VOLTAGE,					\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.scan_type = {						\
+		.sign = 'u',					\
+		.realbits = (_bits),				\
+		.storagebits = 16,				\
+		.shift = 12 - (_bits),				\
+		.endianness = IIO_CPU,				\
+	},							\
+}
+
+#define DEFINE_ADCxx1C_CHANNELS(_name, _bits)				\
+	static const struct iio_chan_spec _name ## _channels[] = {	\
+		ADCxx1C_CHAN((_bits)),					\
+		IIO_CHAN_SOFT_TIMESTAMP(1),				\
+	};								\
+
+#define ADC081C_NUM_CHANNELS 2
+
+struct adcxx1c_model {
+	const struct iio_chan_spec* channels;
+	int bits;
+};
+
+#define ADCxx1C_MODEL(_name, _bits)					\
+	{								\
+		.channels = _name ## _channels,				\
+		.bits = (_bits),					\
+	}
+
+DEFINE_ADCxx1C_CHANNELS(adc081c,  8);
+DEFINE_ADCxx1C_CHANNELS(adc101c, 10);
+DEFINE_ADCxx1C_CHANNELS(adc121c, 12);
+
+/* Model ids are indexes in _models array */
+enum adcxx1c_model_id {
+	ADC081C = 0,
+	ADC101C = 1,
+	ADC121C = 2,
+};
+
+static struct adcxx1c_model adcxx1c_models[] = {
+	ADCxx1C_MODEL(adc081c,  8),
+	ADCxx1C_MODEL(adc101c, 10),
+	ADCxx1C_MODEL(adc121c, 12),
 };
 
 static const struct iio_info adc081c_info = {
@@ -65,22 +127,55 @@ static const struct iio_info adc081c_info = {
 	.driver_module = THIS_MODULE,
 };
 
+static irqreturn_t adc081c_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct adc081c *data = iio_priv(indio_dev);
+	u16 buf[8]; /* 2 bytes data + 6 bytes padding + 8 bytes timestamp */
+	int ret;
+
+	ret = i2c_smbus_read_word_swapped(data->i2c, REG_CONV_RES);
+	if (ret < 0)
+		goto out;
+	buf[0] = ret;
+	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+					   iio_get_time_ns(indio_dev));
+out:
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+}
+
 static int adc081c_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
 	struct iio_dev *iio;
 	struct adc081c *adc;
+	struct adcxx1c_model *model;
 	int err;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
 		return -EOPNOTSUPP;
 
+	if (ACPI_COMPANION(&client->dev)) {
+		const struct acpi_device_id *ad_id;
+
+		ad_id = acpi_match_device(client->dev.driver->acpi_match_table,
+					  &client->dev);
+		if (!ad_id)
+			return -ENODEV;
+		model = &adcxx1c_models[ad_id->driver_data];
+	} else {
+		model = &adcxx1c_models[id->driver_data];
+	}
+
 	iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
 	if (!iio)
 		return -ENOMEM;
 
 	adc = iio_priv(iio);
 	adc->i2c = client;
+	adc->bits = model->bits;
 
 	adc->ref = devm_regulator_get(&client->dev, "vref");
 	if (IS_ERR(adc->ref))
@@ -91,22 +186,31 @@ static int adc081c_probe(struct i2c_client *client,
 		return err;
 
 	iio->dev.parent = &client->dev;
+	iio->dev.of_node = client->dev.of_node;
 	iio->name = dev_name(&client->dev);
 	iio->modes = INDIO_DIRECT_MODE;
 	iio->info = &adc081c_info;
 
-	iio->channels = &adc081c_channel;
-	iio->num_channels = 1;
+	iio->channels = model->channels;
+	iio->num_channels = ADC081C_NUM_CHANNELS;
+
+	err = iio_triggered_buffer_setup(iio, NULL, adc081c_trigger_handler, NULL);
+	if (err < 0) {
+		dev_err(&client->dev, "iio triggered buffer setup failed\n");
+		goto err_regulator_disable;
+	}
 
 	err = iio_device_register(iio);
 	if (err < 0)
-		goto regulator_disable;
+		goto err_buffer_cleanup;
 
 	i2c_set_clientdata(client, iio);
 
 	return 0;
 
-regulator_disable:
+err_buffer_cleanup:
+	iio_triggered_buffer_cleanup(iio);
+err_regulator_disable:
 	regulator_disable(adc->ref);
 
 	return err;
@@ -118,13 +222,16 @@ static int adc081c_remove(struct i2c_client *client)
 	struct adc081c *adc = iio_priv(iio);
 
 	iio_device_unregister(iio);
+	iio_triggered_buffer_cleanup(iio);
 	regulator_disable(adc->ref);
 
 	return 0;
 }
 
 static const struct i2c_device_id adc081c_id[] = {
-	{ "adc081c", 0 },
+	{ "adc081c", ADC081C },
+	{ "adc101c", ADC101C },
+	{ "adc121c", ADC121C },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adc081c_id);
@@ -132,15 +239,28 @@ MODULE_DEVICE_TABLE(i2c, adc081c_id);
 #ifdef CONFIG_OF
 static const struct of_device_id adc081c_of_match[] = {
 	{ .compatible = "ti,adc081c" },
+	{ .compatible = "ti,adc101c" },
+	{ .compatible = "ti,adc121c" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, adc081c_of_match);
 #endif
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id adc081c_acpi_match[] = {
+	{ "ADC081C", ADC081C },
+	{ "ADC101C", ADC101C },
+	{ "ADC121C", ADC121C },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, adc081c_acpi_match);
+#endif
+
 static struct i2c_driver adc081c_driver = {
 	.driver = {
 		.name = "adc081c",
 		.of_match_table = of_match_ptr(adc081c_of_match),
+		.acpi_match_table = ACPI_PTR(adc081c_acpi_match),
 	},
 	.probe = adc081c_probe,
 	.remove = adc081c_remove,
@@ -149,5 +269,5 @@ static struct i2c_driver adc081c_driver = {
 module_i2c_driver(adc081c_driver);
 
 MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
-MODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver");
+MODULE_DESCRIPTION("Texas Instruments ADC081C/ADC101C/ADC121C driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c
index 0afeac0..f4ba23e 100644
--- a/drivers/iio/adc/ti-adc0832.c
+++ b/drivers/iio/adc/ti-adc0832.c
@@ -194,6 +194,7 @@ static int adc0832_probe(struct spi_device *spi)
 
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->info = &adc0832_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index bc58867..89dfbd3 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -150,6 +150,7 @@ static int adc128_probe(struct spi_device *spi)
 	spi_set_drvdata(spi, indio_dev);
 
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &adc128_info;
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 73cbf0b..1ef3987 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -55,6 +55,11 @@
 #define ADS1015_DEFAULT_DATA_RATE	4
 #define ADS1015_DEFAULT_CHAN		0
 
+enum {
+	ADS1015,
+	ADS1115,
+};
+
 enum ads1015_channels {
 	ADS1015_AIN0_AIN1 = 0,
 	ADS1015_AIN0_AIN3,
@@ -71,6 +76,10 @@ static const unsigned int ads1015_data_rate[] = {
 	128, 250, 490, 920, 1600, 2400, 3300, 3300
 };
 
+static const unsigned int ads1115_data_rate[] = {
+	8, 16, 32, 64, 128, 250, 475, 860
+};
+
 static const struct {
 	int scale;
 	int uscale;
@@ -101,6 +110,7 @@ static const struct {
 		.shift = 4,					\
 		.endianness = IIO_CPU,				\
 	},							\
+	.datasheet_name = "AIN"#_chan,				\
 }
 
 #define ADS1015_V_DIFF_CHAN(_chan, _chan2, _addr) {		\
@@ -121,6 +131,45 @@ static const struct {
 		.shift = 4,					\
 		.endianness = IIO_CPU,				\
 	},							\
+	.datasheet_name = "AIN"#_chan"-AIN"#_chan2,		\
+}
+
+#define ADS1115_V_CHAN(_chan, _addr) {				\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.address = _addr,					\
+	.channel = _chan,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
+				BIT(IIO_CHAN_INFO_SCALE) |	\
+				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
+	.scan_index = _addr,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+		.endianness = IIO_CPU,				\
+	},							\
+	.datasheet_name = "AIN"#_chan,				\
+}
+
+#define ADS1115_V_DIFF_CHAN(_chan, _chan2, _addr) {		\
+	.type = IIO_VOLTAGE,					\
+	.differential = 1,					\
+	.indexed = 1,						\
+	.address = _addr,					\
+	.channel = _chan,					\
+	.channel2 = _chan2,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
+				BIT(IIO_CHAN_INFO_SCALE) |	\
+				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
+	.scan_index = _addr,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+		.endianness = IIO_CPU,				\
+	},							\
+	.datasheet_name = "AIN"#_chan"-AIN"#_chan2,		\
 }
 
 struct ads1015_data {
@@ -131,6 +180,8 @@ struct ads1015_data {
 	 */
 	struct mutex lock;
 	struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
+
+	unsigned int *data_rate;
 };
 
 static bool ads1015_is_writeable_reg(struct device *dev, unsigned int reg)
@@ -157,6 +208,18 @@ static const struct iio_chan_spec ads1015_channels[] = {
 	IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
 };
 
+static const struct iio_chan_spec ads1115_channels[] = {
+	ADS1115_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1),
+	ADS1115_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3),
+	ADS1115_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3),
+	ADS1115_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3),
+	ADS1115_V_CHAN(0, ADS1015_AIN0),
+	ADS1115_V_CHAN(1, ADS1015_AIN1),
+	ADS1115_V_CHAN(2, ADS1015_AIN2),
+	ADS1115_V_CHAN(3, ADS1015_AIN3),
+	IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
+};
+
 static int ads1015_set_power_state(struct ads1015_data *data, bool on)
 {
 	int ret;
@@ -196,7 +259,7 @@ int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
 		return ret;
 
 	if (change) {
-		conv_time = DIV_ROUND_UP(USEC_PER_SEC, ads1015_data_rate[dr]);
+		conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]);
 		usleep_range(conv_time, conv_time + 1);
 	}
 
@@ -225,7 +288,8 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
 	buf[0] = res;
 	mutex_unlock(&data->lock);
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
+	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+					   iio_get_time_ns(indio_dev));
 
 err:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -263,7 +327,7 @@ static int ads1015_set_data_rate(struct ads1015_data *data, int chan, int rate)
 	int i, ret, rindex = -1;
 
 	for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++)
-		if (ads1015_data_rate[i] == rate) {
+		if (data->data_rate[i] == rate) {
 			rindex = i;
 			break;
 		}
@@ -291,7 +355,9 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
 	mutex_lock(&indio_dev->mlock);
 	mutex_lock(&data->lock);
 	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_RAW: {
+		int shift = chan->scan_type.shift;
+
 		if (iio_buffer_enabled(indio_dev)) {
 			ret = -EBUSY;
 			break;
@@ -307,8 +373,7 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
 			break;
 		}
 
-		/* 12 bit res, D0 is bit 4 in conversion register */
-		*val = sign_extend32(*val >> 4, 11);
+		*val = sign_extend32(*val >> shift, 15 - shift);
 
 		ret = ads1015_set_power_state(data, false);
 		if (ret < 0)
@@ -316,6 +381,7 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
 
 		ret = IIO_VAL_INT;
 		break;
+	}
 	case IIO_CHAN_INFO_SCALE:
 		idx = data->channel_data[chan->address].pga;
 		*val = ads1015_scale[idx].scale;
@@ -324,7 +390,7 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
 		break;
 	case IIO_CHAN_INFO_SAMP_FREQ:
 		idx = data->channel_data[chan->address].data_rate;
-		*val = ads1015_data_rate[idx];
+		*val = data->data_rate[idx];
 		ret = IIO_VAL_INT;
 		break;
 	default:
@@ -380,12 +446,15 @@ static const struct iio_buffer_setup_ops ads1015_buffer_setup_ops = {
 };
 
 static IIO_CONST_ATTR(scale_available, "3 2 1 0.5 0.25 0.125");
-static IIO_CONST_ATTR(sampling_frequency_available,
-		      "128 250 490 920 1600 2400 3300");
+
+static IIO_CONST_ATTR_NAMED(ads1015_sampling_frequency_available,
+	sampling_frequency_available, "128 250 490 920 1600 2400 3300");
+static IIO_CONST_ATTR_NAMED(ads1115_sampling_frequency_available,
+	sampling_frequency_available, "8 16 32 64 128 250 475 860");
 
 static struct attribute *ads1015_attributes[] = {
 	&iio_const_attr_scale_available.dev_attr.attr,
-	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_const_attr_ads1015_sampling_frequency_available.dev_attr.attr,
 	NULL,
 };
 
@@ -393,11 +462,28 @@ static const struct attribute_group ads1015_attribute_group = {
 	.attrs = ads1015_attributes,
 };
 
-static const struct iio_info ads1015_info = {
+static struct attribute *ads1115_attributes[] = {
+	&iio_const_attr_scale_available.dev_attr.attr,
+	&iio_const_attr_ads1115_sampling_frequency_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ads1115_attribute_group = {
+	.attrs = ads1115_attributes,
+};
+
+static struct iio_info ads1015_info = {
+	.driver_module	= THIS_MODULE,
+	.read_raw	= ads1015_read_raw,
+	.write_raw	= ads1015_write_raw,
+	.attrs          = &ads1015_attribute_group,
+};
+
+static struct iio_info ads1115_info = {
 	.driver_module	= THIS_MODULE,
 	.read_raw	= ads1015_read_raw,
 	.write_raw	= ads1015_write_raw,
-	.attrs		= &ads1015_attribute_group,
+	.attrs          = &ads1115_attribute_group,
 };
 
 #ifdef CONFIG_OF
@@ -500,12 +586,25 @@ static int ads1015_probe(struct i2c_client *client,
 	mutex_init(&data->lock);
 
 	indio_dev->dev.parent = &client->dev;
-	indio_dev->info = &ads1015_info;
+	indio_dev->dev.of_node = client->dev.of_node;
 	indio_dev->name = ADS1015_DRV_NAME;
-	indio_dev->channels = ads1015_channels;
-	indio_dev->num_channels = ARRAY_SIZE(ads1015_channels);
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
+	switch (id->driver_data) {
+	case ADS1015:
+		indio_dev->channels = ads1015_channels;
+		indio_dev->num_channels = ARRAY_SIZE(ads1015_channels);
+		indio_dev->info = &ads1015_info;
+		data->data_rate = (unsigned int *) &ads1015_data_rate;
+		break;
+	case ADS1115:
+		indio_dev->channels = ads1115_channels;
+		indio_dev->num_channels = ARRAY_SIZE(ads1115_channels);
+		indio_dev->info = &ads1115_info;
+		data->data_rate = (unsigned int *) &ads1115_data_rate;
+		break;
+	}
+
 	/* we need to keep this ABI the same as used by hwmon ADS1015 driver */
 	ads1015_get_channels_config(client);
 
@@ -590,7 +689,8 @@ static const struct dev_pm_ops ads1015_pm_ops = {
 };
 
 static const struct i2c_device_id ads1015_id[] = {
-	{"ads1015", 0},
+	{"ads1015", ADS1015},
+	{"ads1115", ADS1115},
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, ads1015_id);
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
index 03e9070..c400439 100644
--- a/drivers/iio/adc/ti-ads8688.c
+++ b/drivers/iio/adc/ti-ads8688.c
@@ -421,6 +421,7 @@ static int ads8688_probe(struct spi_device *spi)
 
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->dev.parent = &spi->dev;
+	indio_dev->dev.of_node = spi->dev.of_node;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = st->chip_info->channels;
 	indio_dev->num_channels = st->chip_info->num_channels;
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index c1e0553..8a36875 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -326,8 +326,7 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
 	int i;
 
 	indio_dev->num_channels = channels;
-	chan_array = kcalloc(channels,
-			sizeof(struct iio_chan_spec), GFP_KERNEL);
+	chan_array = kcalloc(channels, sizeof(*chan_array), GFP_KERNEL);
 	if (chan_array == NULL)
 		return -ENOMEM;
 
@@ -467,8 +466,7 @@ static int tiadc_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	indio_dev = devm_iio_device_alloc(&pdev->dev,
-					  sizeof(struct tiadc_device));
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*indio_dev));
 	if (indio_dev == NULL) {
 		dev_err(&pdev->dev, "failed to allocate iio device\n");
 		return -ENOMEM;
@@ -531,8 +529,7 @@ static int tiadc_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int tiadc_suspend(struct device *dev)
+static int __maybe_unused tiadc_suspend(struct device *dev)
 {
 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct tiadc_device *adc_dev = iio_priv(indio_dev);
@@ -550,7 +547,7 @@ static int tiadc_suspend(struct device *dev)
 	return 0;
 }
 
-static int tiadc_resume(struct device *dev)
+static int __maybe_unused tiadc_resume(struct device *dev)
 {
 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct tiadc_device *adc_dev = iio_priv(indio_dev);
@@ -567,14 +564,7 @@ static int tiadc_resume(struct device *dev)
 	return 0;
 }
 
-static const struct dev_pm_ops tiadc_pm_ops = {
-	.suspend = tiadc_suspend,
-	.resume = tiadc_resume,
-};
-#define TIADC_PM_OPS (&tiadc_pm_ops)
-#else
-#define TIADC_PM_OPS NULL
-#endif
+static SIMPLE_DEV_PM_OPS(tiadc_pm_ops, tiadc_suspend, tiadc_resume);
 
 static const struct of_device_id ti_adc_dt_ids[] = {
 	{ .compatible = "ti,am3359-adc", },
@@ -585,7 +575,7 @@ MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
 static struct platform_driver tiadc_driver = {
 	.driver = {
 		.name   = "TI-am335x-adc",
-		.pm	= TIADC_PM_OPS,
+		.pm	= &tiadc_pm_ops,
 		.of_match_table = ti_adc_dt_ids,
 	},
 	.probe	= tiadc_probe,
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index b10f629..228a003 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -594,7 +594,8 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
 		if (iio_buffer_enabled(indio_dev)) {
 			info->buffer[0] = info->value;
 			iio_push_to_buffers_with_timestamp(indio_dev,
-					info->buffer, iio_get_time_ns());
+					info->buffer,
+					iio_get_time_ns(indio_dev));
 			iio_trigger_notify_done(indio_dev->trig);
 		} else
 			complete(&info->completion);
@@ -714,19 +715,19 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
 	int i;
 
 	switch (mask) {
-		case IIO_CHAN_INFO_SAMP_FREQ:
-			for (i = 0;
-				i < ARRAY_SIZE(info->sample_freq_avail);
-				i++)
-				if (val == info->sample_freq_avail[i]) {
-					info->adc_feature.sample_rate = i;
-					vf610_adc_sample_set(info);
-					return 0;
-				}
-			break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		for (i = 0;
+			i < ARRAY_SIZE(info->sample_freq_avail);
+			i++)
+			if (val == info->sample_freq_avail[i]) {
+				info->adc_feature.sample_rate = i;
+				vf610_adc_sample_set(info);
+				return 0;
+			}
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return -EINVAL;
diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c
index edcf3aa..6d5c2a6 100644
--- a/drivers/iio/adc/xilinx-xadc-events.c
+++ b/drivers/iio/adc/xilinx-xadc-events.c
@@ -46,7 +46,7 @@ static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
 		iio_push_event(indio_dev,
 			IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
 				IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
-			iio_get_time_ns());
+			iio_get_time_ns(indio_dev));
 	} else {
 		/*
 		 * For other channels we don't know whether it is a upper or
@@ -56,7 +56,7 @@ static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
 		iio_push_event(indio_dev,
 			IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
 				IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
-			iio_get_time_ns());
+			iio_get_time_ns(indio_dev));
 	}
 }
 
diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c
index 212cbed..dd99d27 100644
--- a/drivers/iio/buffer/industrialio-buffer-dma.c
+++ b/drivers/iio/buffer/industrialio-buffer-dma.c
@@ -305,7 +305,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer)
 	queue->fileio.active_block = NULL;
 
 	spin_lock_irq(&queue->list_lock);
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
 		block = queue->fileio.blocks[i];
 
 		/* If we can't re-use it free it */
@@ -323,7 +323,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer)
 
 	INIT_LIST_HEAD(&queue->incoming);
 
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
 		if (queue->fileio.blocks[i]) {
 			block = queue->fileio.blocks[i];
 			if (block->state == IIO_BLOCK_STATE_DEAD) {
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index f73290f..4bcc025 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -5,15 +5,17 @@
 menu "Chemical Sensors"
 
 config ATLAS_PH_SENSOR
-	tristate "Atlas Scientific OEM pH-SM sensor"
+	tristate "Atlas Scientific OEM SM sensors"
 	depends on I2C
 	select REGMAP_I2C
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	select IRQ_WORK
 	help
-	 Say Y here to build I2C interface support for the Atlas
-	 Scientific OEM pH-SM sensor.
+	 Say Y here to build I2C interface support for the following
+	 Atlas Scientific OEM SM sensors:
+	    * pH SM sensor
+	    * EC SM sensor
 
 	 To compile this driver as module, choose M here: the
 	 module will be called atlas-ph-sensor.
diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c
index 62b37cd..ae038a5 100644
--- a/drivers/iio/chemical/atlas-ph-sensor.c
+++ b/drivers/iio/chemical/atlas-ph-sensor.c
@@ -24,6 +24,7 @@
 #include <linux/irq_work.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
+#include <linux/of_device.h>
 #include <linux/regmap.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
@@ -43,29 +44,50 @@
 
 #define ATLAS_REG_PWR_CONTROL		0x06
 
-#define ATLAS_REG_CALIB_STATUS		0x0d
-#define ATLAS_REG_CALIB_STATUS_MASK	0x07
-#define ATLAS_REG_CALIB_STATUS_LOW	BIT(0)
-#define ATLAS_REG_CALIB_STATUS_MID	BIT(1)
-#define ATLAS_REG_CALIB_STATUS_HIGH	BIT(2)
+#define ATLAS_REG_PH_CALIB_STATUS	0x0d
+#define ATLAS_REG_PH_CALIB_STATUS_MASK	0x07
+#define ATLAS_REG_PH_CALIB_STATUS_LOW	BIT(0)
+#define ATLAS_REG_PH_CALIB_STATUS_MID	BIT(1)
+#define ATLAS_REG_PH_CALIB_STATUS_HIGH	BIT(2)
 
-#define ATLAS_REG_TEMP_DATA		0x0e
+#define ATLAS_REG_EC_CALIB_STATUS		0x0f
+#define ATLAS_REG_EC_CALIB_STATUS_MASK		0x0f
+#define ATLAS_REG_EC_CALIB_STATUS_DRY		BIT(0)
+#define ATLAS_REG_EC_CALIB_STATUS_SINGLE	BIT(1)
+#define ATLAS_REG_EC_CALIB_STATUS_LOW		BIT(2)
+#define ATLAS_REG_EC_CALIB_STATUS_HIGH		BIT(3)
+
+#define ATLAS_REG_PH_TEMP_DATA		0x0e
 #define ATLAS_REG_PH_DATA		0x16
 
+#define ATLAS_REG_EC_PROBE		0x08
+#define ATLAS_REG_EC_TEMP_DATA		0x10
+#define ATLAS_REG_EC_DATA		0x18
+#define ATLAS_REG_TDS_DATA		0x1c
+#define ATLAS_REG_PSS_DATA		0x20
+
 #define ATLAS_PH_INT_TIME_IN_US		450000
+#define ATLAS_EC_INT_TIME_IN_US		650000
+
+enum {
+	ATLAS_PH_SM,
+	ATLAS_EC_SM,
+};
 
 struct atlas_data {
 	struct i2c_client *client;
 	struct iio_trigger *trig;
+	struct atlas_device *chip;
 	struct regmap *regmap;
 	struct irq_work work;
 
-	__be32 buffer[4]; /* 32-bit pH data + 32-bit pad + 64-bit timestamp */
+	__be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */
 };
 
 static const struct regmap_range atlas_volatile_ranges[] = {
 	regmap_reg_range(ATLAS_REG_INT_CONTROL, ATLAS_REG_INT_CONTROL),
 	regmap_reg_range(ATLAS_REG_PH_DATA, ATLAS_REG_PH_DATA + 4),
+	regmap_reg_range(ATLAS_REG_EC_DATA, ATLAS_REG_PSS_DATA + 4),
 };
 
 static const struct regmap_access_table atlas_volatile_table = {
@@ -80,13 +102,14 @@ static const struct regmap_config atlas_regmap_config = {
 	.val_bits = 8,
 
 	.volatile_table = &atlas_volatile_table,
-	.max_register = ATLAS_REG_PH_DATA + 4,
+	.max_register = ATLAS_REG_PSS_DATA + 4,
 	.cache_type = REGCACHE_RBTREE,
 };
 
-static const struct iio_chan_spec atlas_channels[] = {
+static const struct iio_chan_spec atlas_ph_channels[] = {
 	{
 		.type = IIO_PH,
+		.address = ATLAS_REG_PH_DATA,
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
 		.scan_index = 0,
@@ -100,7 +123,7 @@ static const struct iio_chan_spec atlas_channels[] = {
 	IIO_CHAN_SOFT_TIMESTAMP(1),
 	{
 		.type = IIO_TEMP,
-		.address = ATLAS_REG_TEMP_DATA,
+		.address = ATLAS_REG_PH_TEMP_DATA,
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
 		.output = 1,
@@ -108,6 +131,142 @@ static const struct iio_chan_spec atlas_channels[] = {
 	},
 };
 
+#define ATLAS_EC_CHANNEL(_idx, _addr) \
+	{\
+		.type = IIO_CONCENTRATION, \
+		.indexed = 1, \
+		.channel = _idx, \
+		.address = _addr, \
+		.info_mask_separate = \
+			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
+		.scan_index = _idx + 1, \
+		.scan_type = { \
+			.sign = 'u', \
+			.realbits = 32, \
+			.storagebits = 32, \
+			.endianness = IIO_BE, \
+		}, \
+	}
+
+static const struct iio_chan_spec atlas_ec_channels[] = {
+	{
+		.type = IIO_ELECTRICALCONDUCTIVITY,
+		.address = ATLAS_REG_EC_DATA,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 32,
+			.storagebits = 32,
+			.endianness = IIO_BE,
+		},
+	},
+	ATLAS_EC_CHANNEL(0, ATLAS_REG_TDS_DATA),
+	ATLAS_EC_CHANNEL(1, ATLAS_REG_PSS_DATA),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+	{
+		.type = IIO_TEMP,
+		.address = ATLAS_REG_EC_TEMP_DATA,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+		.output = 1,
+		.scan_index = -1
+	},
+};
+
+static int atlas_check_ph_calibration(struct atlas_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int ret;
+	unsigned int val;
+
+	ret = regmap_read(data->regmap, ATLAS_REG_PH_CALIB_STATUS, &val);
+	if (ret)
+		return ret;
+
+	if (!(val & ATLAS_REG_PH_CALIB_STATUS_MASK)) {
+		dev_warn(dev, "device has not been calibrated\n");
+		return 0;
+	}
+
+	if (!(val & ATLAS_REG_PH_CALIB_STATUS_LOW))
+		dev_warn(dev, "device missing low point calibration\n");
+
+	if (!(val & ATLAS_REG_PH_CALIB_STATUS_MID))
+		dev_warn(dev, "device missing mid point calibration\n");
+
+	if (!(val & ATLAS_REG_PH_CALIB_STATUS_HIGH))
+		dev_warn(dev, "device missing high point calibration\n");
+
+	return 0;
+}
+
+static int atlas_check_ec_calibration(struct atlas_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int ret;
+	unsigned int val;
+
+	ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &val, 2);
+	if (ret)
+		return ret;
+
+	dev_info(dev, "probe set to K = %d.%.2d", be16_to_cpu(val) / 100,
+						 be16_to_cpu(val) % 100);
+
+	ret = regmap_read(data->regmap, ATLAS_REG_EC_CALIB_STATUS, &val);
+	if (ret)
+		return ret;
+
+	if (!(val & ATLAS_REG_EC_CALIB_STATUS_MASK)) {
+		dev_warn(dev, "device has not been calibrated\n");
+		return 0;
+	}
+
+	if (!(val & ATLAS_REG_EC_CALIB_STATUS_DRY))
+		dev_warn(dev, "device missing dry point calibration\n");
+
+	if (val & ATLAS_REG_EC_CALIB_STATUS_SINGLE) {
+		dev_warn(dev, "device using single point calibration\n");
+	} else {
+		if (!(val & ATLAS_REG_EC_CALIB_STATUS_LOW))
+			dev_warn(dev, "device missing low point calibration\n");
+
+		if (!(val & ATLAS_REG_EC_CALIB_STATUS_HIGH))
+			dev_warn(dev, "device missing high point calibration\n");
+	}
+
+	return 0;
+}
+
+struct atlas_device {
+	const struct iio_chan_spec *channels;
+	int num_channels;
+	int data_reg;
+
+	int (*calibration)(struct atlas_data *data);
+	int delay;
+};
+
+static struct atlas_device atlas_devices[] = {
+	[ATLAS_PH_SM] = {
+				.channels = atlas_ph_channels,
+				.num_channels = 3,
+				.data_reg = ATLAS_REG_PH_DATA,
+				.calibration = &atlas_check_ph_calibration,
+				.delay = ATLAS_PH_INT_TIME_IN_US,
+	},
+	[ATLAS_EC_SM] = {
+				.channels = atlas_ec_channels,
+				.num_channels = 5,
+				.data_reg = ATLAS_REG_EC_DATA,
+				.calibration = &atlas_check_ec_calibration,
+				.delay = ATLAS_EC_INT_TIME_IN_US,
+	},
+
+};
+
 static int atlas_set_powermode(struct atlas_data *data, int on)
 {
 	return regmap_write(data->regmap, ATLAS_REG_PWR_CONTROL, on);
@@ -178,12 +337,13 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private)
 	struct atlas_data *data = iio_priv(indio_dev);
 	int ret;
 
-	ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA,
-			      (u8 *) &data->buffer, sizeof(data->buffer[0]));
+	ret = regmap_bulk_read(data->regmap, data->chip->data_reg,
+			      (u8 *) &data->buffer,
+			      sizeof(__be32) * (data->chip->num_channels - 2));
 
 	if (!ret)
 		iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
-				iio_get_time_ns());
+				iio_get_time_ns(indio_dev));
 
 	iio_trigger_notify_done(indio_dev->trig);
 
@@ -200,7 +360,7 @@ static irqreturn_t atlas_interrupt_handler(int irq, void *private)
 	return IRQ_HANDLED;
 }
 
-static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val)
+static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val)
 {
 	struct device *dev = &data->client->dev;
 	int suspended = pm_runtime_suspended(dev);
@@ -213,11 +373,9 @@ static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val)
 	}
 
 	if (suspended)
-		usleep_range(ATLAS_PH_INT_TIME_IN_US,
-			     ATLAS_PH_INT_TIME_IN_US + 100000);
+		usleep_range(data->chip->delay, data->chip->delay + 100000);
 
-	ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA,
-			      (u8 *) val, sizeof(*val));
+	ret = regmap_bulk_read(data->regmap, reg, (u8 *) val, sizeof(*val));
 
 	pm_runtime_mark_last_busy(dev);
 	pm_runtime_put_autosuspend(dev);
@@ -242,12 +400,15 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
 					      (u8 *) &reg, sizeof(reg));
 			break;
 		case IIO_PH:
+		case IIO_CONCENTRATION:
+		case IIO_ELECTRICALCONDUCTIVITY:
 			mutex_lock(&indio_dev->mlock);
 
 			if (iio_buffer_enabled(indio_dev))
 				ret = -EBUSY;
 			else
-				ret = atlas_read_ph_measurement(data, &reg);
+				ret = atlas_read_measurement(data,
+							chan->address, &reg);
 
 			mutex_unlock(&indio_dev->mlock);
 			break;
@@ -271,6 +432,14 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
 			*val = 1; /* 0.001 */
 			*val2 = 1000;
 			break;
+		case IIO_ELECTRICALCONDUCTIVITY:
+			*val = 1; /* 0.00001 */
+			*val = 100000;
+			break;
+		case IIO_CONCENTRATION:
+			*val = 0; /* 0.000000001 */
+			*val2 = 1000;
+			return IIO_VAL_INT_PLUS_NANO;
 		default:
 			return -EINVAL;
 		}
@@ -303,37 +472,26 @@ static const struct iio_info atlas_info = {
 	.write_raw = atlas_write_raw,
 };
 
-static int atlas_check_calibration(struct atlas_data *data)
-{
-	struct device *dev = &data->client->dev;
-	int ret;
-	unsigned int val;
-
-	ret = regmap_read(data->regmap, ATLAS_REG_CALIB_STATUS, &val);
-	if (ret)
-		return ret;
-
-	if (!(val & ATLAS_REG_CALIB_STATUS_MASK)) {
-		dev_warn(dev, "device has not been calibrated\n");
-		return 0;
-	}
-
-	if (!(val & ATLAS_REG_CALIB_STATUS_LOW))
-		dev_warn(dev, "device missing low point calibration\n");
-
-	if (!(val & ATLAS_REG_CALIB_STATUS_MID))
-		dev_warn(dev, "device missing mid point calibration\n");
-
-	if (!(val & ATLAS_REG_CALIB_STATUS_HIGH))
-		dev_warn(dev, "device missing high point calibration\n");
+static const struct i2c_device_id atlas_id[] = {
+	{ "atlas-ph-sm", ATLAS_PH_SM},
+	{ "atlas-ec-sm", ATLAS_EC_SM},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, atlas_id);
 
-	return 0;
+static const struct of_device_id atlas_dt_ids[] = {
+	{ .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
+	{ .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
+	{ }
 };
+MODULE_DEVICE_TABLE(of, atlas_dt_ids);
 
 static int atlas_probe(struct i2c_client *client,
 		       const struct i2c_device_id *id)
 {
 	struct atlas_data *data;
+	struct atlas_device *chip;
+	const struct of_device_id *of_id;
 	struct iio_trigger *trig;
 	struct iio_dev *indio_dev;
 	int ret;
@@ -342,10 +500,16 @@ static int atlas_probe(struct i2c_client *client,
 	if (!indio_dev)
 		return -ENOMEM;
 
+	of_id = of_match_device(atlas_dt_ids, &client->dev);
+	if (!of_id)
+		chip = &atlas_devices[id->driver_data];
+	else
+		chip = &atlas_devices[(unsigned long)of_id->data];
+
 	indio_dev->info = &atlas_info;
 	indio_dev->name = ATLAS_DRV_NAME;
-	indio_dev->channels = atlas_channels;
-	indio_dev->num_channels = ARRAY_SIZE(atlas_channels);
+	indio_dev->channels = chip->channels;
+	indio_dev->num_channels = chip->num_channels;
 	indio_dev->modes = INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE;
 	indio_dev->dev.parent = &client->dev;
 
@@ -358,6 +522,7 @@ static int atlas_probe(struct i2c_client *client,
 	data = iio_priv(indio_dev);
 	data->client = client;
 	data->trig = trig;
+	data->chip = chip;
 	trig->dev.parent = indio_dev->dev.parent;
 	trig->ops = &atlas_interrupt_trigger_ops;
 	iio_trigger_set_drvdata(trig, indio_dev);
@@ -379,7 +544,7 @@ static int atlas_probe(struct i2c_client *client,
 		return -EINVAL;
 	}
 
-	ret = atlas_check_calibration(data);
+	ret = chip->calibration(data);
 	if (ret)
 		return ret;
 
@@ -480,18 +645,6 @@ static const struct dev_pm_ops atlas_pm_ops = {
 			   atlas_runtime_resume, NULL)
 };
 
-static const struct i2c_device_id atlas_id[] = {
-	{ "atlas-ph-sm", 0 },
-	{}
-};
-MODULE_DEVICE_TABLE(i2c, atlas_id);
-
-static const struct of_device_id atlas_dt_ids[] = {
-	{ .compatible = "atlas,ph-sm" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, atlas_dt_ids);
-
 static struct i2c_driver atlas_driver = {
 	.driver = {
 		.name	= ATLAS_DRV_NAME,
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 5955110..5b41f9d 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -115,7 +115,7 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
 		return ret;
 	}
 
- 	return 0;
+	return 0;
 #else
 	atomic_set(&st->user_requested_state, state);
 	return _hid_sensor_power_state(st, state);
diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
index 669dc7c..ecf7721 100644
--- a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
+++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
@@ -106,7 +106,7 @@ int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
 				unsigned int delay, u32 *adc)
 {
 	int ret;
-        __be32 buf = 0;
+	__be32 buf = 0;
 	struct i2c_client *client = (struct i2c_client *)cli;
 
 	/* Trigger conversion */
diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c
index e18bc67..d06e728 100644
--- a/drivers/iio/common/st_sensors/st_sensors_buffer.c
+++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c
@@ -22,85 +22,32 @@
 #include <linux/iio/common/st_sensors.h>
 
 
-int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
+static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
 {
-	u8 *addr;
-	int i, n = 0, len;
+	int i;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 	unsigned int num_data_channels = sdata->num_data_channels;
-	unsigned int byte_for_channel =
-			indio_dev->channels[0].scan_type.storagebits >> 3;
 
-	addr = kmalloc(num_data_channels, GFP_KERNEL);
-	if (!addr) {
-		len = -ENOMEM;
-		goto st_sensors_get_buffer_element_error;
-	}
-
-	for (i = 0; i < num_data_channels; i++) {
-		if (test_bit(i, indio_dev->active_scan_mask)) {
-			addr[n] = indio_dev->channels[i].address;
-			n++;
-		}
-	}
-	switch (n) {
-	case 1:
-		len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
-			addr[0], byte_for_channel, buf, sdata->multiread_bit);
-		break;
-	case 2:
-		if ((addr[1] - addr[0]) == byte_for_channel) {
-			len = sdata->tf->read_multiple_byte(&sdata->tb,
-				sdata->dev, addr[0], byte_for_channel * n,
-				buf, sdata->multiread_bit);
-		} else {
-			u8 *rx_array;
-			rx_array = kmalloc(byte_for_channel * num_data_channels,
-					   GFP_KERNEL);
-			if (!rx_array) {
-				len = -ENOMEM;
-				goto st_sensors_free_memory;
-			}
+	for_each_set_bit(i, indio_dev->active_scan_mask, num_data_channels) {
+		const struct iio_chan_spec *channel = &indio_dev->channels[i];
+		unsigned int bytes_to_read = channel->scan_type.realbits >> 3;
+		unsigned int storage_bytes =
+			channel->scan_type.storagebits >> 3;
 
-			len = sdata->tf->read_multiple_byte(&sdata->tb,
-				sdata->dev, addr[0],
-				byte_for_channel * num_data_channels,
-				rx_array, sdata->multiread_bit);
-			if (len < 0) {
-				kfree(rx_array);
-				goto st_sensors_free_memory;
-			}
+		buf = PTR_ALIGN(buf, storage_bytes);
+		if (sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
+						  channel->address,
+						  bytes_to_read, buf,
+						  sdata->multiread_bit) <
+		    bytes_to_read)
+			return -EIO;
 
-			for (i = 0; i < n * byte_for_channel; i++) {
-				if (i < n)
-					buf[i] = rx_array[i];
-				else
-					buf[i] = rx_array[n + i];
-			}
-			kfree(rx_array);
-			len = byte_for_channel * n;
-		}
-		break;
-	case 3:
-		len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
-			addr[0], byte_for_channel * num_data_channels,
-			buf, sdata->multiread_bit);
-		break;
-	default:
-		len = -EINVAL;
-		goto st_sensors_free_memory;
-	}
-	if (len != byte_for_channel * n) {
-		len = -EIO;
-		goto st_sensors_free_memory;
+		/* Advance the buffer pointer */
+		buf += storage_bytes;
 	}
 
-st_sensors_free_memory:
-	kfree(addr);
-st_sensors_get_buffer_element_error:
-	return len;
+	return 0;
 }
-EXPORT_SYMBOL(st_sensors_get_buffer_element);
 
 irqreturn_t st_sensors_trigger_handler(int irq, void *p)
 {
@@ -108,13 +55,25 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
+	s64 timestamp;
+
+	/*
+	 * If we do timetamping here, do it before reading the values, because
+	 * once we've read the values, new interrupts can occur (when using
+	 * the hardware trigger) and the hw_timestamp may get updated.
+	 * By storing it in a local variable first, we are safe.
+	 */
+	if (sdata->hw_irq_trigger)
+		timestamp = sdata->hw_timestamp;
+	else
+		timestamp = iio_get_time_ns(indio_dev);
 
 	len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
 	if (len < 0)
 		goto st_sensors_get_buffer_element_error;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, sdata->buffer_data,
-		pf->timestamp);
+					   timestamp);
 
 st_sensors_get_buffer_element_error:
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index f5a2d44..2d5282e 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -228,7 +228,7 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
 }
 EXPORT_SYMBOL(st_sensors_set_axis_enable);
 
-void st_sensors_power_enable(struct iio_dev *indio_dev)
+int st_sensors_power_enable(struct iio_dev *indio_dev)
 {
 	struct st_sensor_data *pdata = iio_priv(indio_dev);
 	int err;
@@ -237,18 +237,37 @@ void st_sensors_power_enable(struct iio_dev *indio_dev)
 	pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd");
 	if (!IS_ERR(pdata->vdd)) {
 		err = regulator_enable(pdata->vdd);
-		if (err != 0)
+		if (err != 0) {
 			dev_warn(&indio_dev->dev,
 				 "Failed to enable specified Vdd supply\n");
+			return err;
+		}
+	} else {
+		err = PTR_ERR(pdata->vdd);
+		if (err != -ENODEV)
+			return err;
 	}
 
 	pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio");
 	if (!IS_ERR(pdata->vdd_io)) {
 		err = regulator_enable(pdata->vdd_io);
-		if (err != 0)
+		if (err != 0) {
 			dev_warn(&indio_dev->dev,
 				 "Failed to enable specified Vdd_IO supply\n");
+			goto st_sensors_disable_vdd;
+		}
+	} else {
+		err = PTR_ERR(pdata->vdd_io);
+		if (err != -ENODEV)
+			goto st_sensors_disable_vdd;
 	}
+
+	return 0;
+
+st_sensors_disable_vdd:
+	if (!IS_ERR_OR_NULL(pdata->vdd))
+		regulator_disable(pdata->vdd);
+	return err;
 }
 EXPORT_SYMBOL(st_sensors_power_enable);
 
@@ -256,10 +275,10 @@ void st_sensors_power_disable(struct iio_dev *indio_dev)
 {
 	struct st_sensor_data *pdata = iio_priv(indio_dev);
 
-	if (!IS_ERR(pdata->vdd))
+	if (!IS_ERR_OR_NULL(pdata->vdd))
 		regulator_disable(pdata->vdd);
 
-	if (!IS_ERR(pdata->vdd_io))
+	if (!IS_ERR_OR_NULL(pdata->vdd_io))
 		regulator_disable(pdata->vdd_io);
 }
 EXPORT_SYMBOL(st_sensors_power_disable);
@@ -301,6 +320,14 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
 		return -EINVAL;
 	}
 
+	if (pdata->open_drain) {
+		if (!sdata->sensor_settings->drdy_irq.addr_od)
+			dev_err(&indio_dev->dev,
+				"open drain requested but unsupported.\n");
+		else
+			sdata->int_pin_open_drain = true;
+	}
+
 	return 0;
 }
 
@@ -321,6 +348,8 @@ static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
 	else
 		pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0;
 
+	pdata->open_drain = of_property_read_bool(np, "drive-open-drain");
+
 	return pdata;
 }
 #else
@@ -353,6 +382,11 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
 	if (err < 0)
 		return err;
 
+	/* Disable DRDY, this might be still be enabled after reboot. */
+	err = st_sensors_set_dataready_irq(indio_dev, false);
+	if (err < 0)
+		return err;
+
 	if (sdata->current_fullscale) {
 		err = st_sensors_set_fullscale(indio_dev,
 						sdata->current_fullscale->num);
@@ -374,6 +408,16 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
 			return err;
 	}
 
+	if (sdata->int_pin_open_drain) {
+		dev_info(&indio_dev->dev,
+			 "set interrupt line to open drain mode\n");
+		err = st_sensors_write_data_with_mask(indio_dev,
+				sdata->sensor_settings->drdy_irq.addr_od,
+				sdata->sensor_settings->drdy_irq.mask_od, 1);
+		if (err < 0)
+			return err;
+	}
+
 	err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
 
 	return err;
@@ -404,6 +448,9 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
 	else
 		drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2;
 
+	/* Flag to the poll function that the hardware trigger is in use */
+	sdata->hw_irq_trigger = enable;
+
 	/* Enable/Disable the interrupt generator for data ready. */
 	err = st_sensors_write_data_with_mask(indio_dev,
 					sdata->sensor_settings->drdy_irq.addr,
@@ -443,7 +490,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
 	int err;
 	u8 *outdata;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
-	unsigned int byte_for_channel = ch->scan_type.storagebits >> 3;
+	unsigned int byte_for_channel = ch->scan_type.realbits >> 3;
 
 	outdata = kmalloc(byte_for_channel, GFP_KERNEL);
 	if (!outdata)
@@ -503,7 +550,7 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
 			int num_sensors_list,
 			const struct st_sensor_settings *sensor_settings)
 {
-	int i, n, err;
+	int i, n, err = 0;
 	u8 wai;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
@@ -523,17 +570,21 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
 		return -ENODEV;
 	}
 
-	err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-					sensor_settings[i].wai_addr, &wai);
-	if (err < 0) {
-		dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
-		return err;
-	}
+	if (sensor_settings[i].wai_addr) {
+		err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
+					   sensor_settings[i].wai_addr, &wai);
+		if (err < 0) {
+			dev_err(&indio_dev->dev,
+				"failed to read Who-Am-I register.\n");
+			return err;
+		}
 
-	if (sensor_settings[i].wai != wai) {
-		dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n",
-						indio_dev->name, wai);
-		return -EINVAL;
+		if (sensor_settings[i].wai != wai) {
+			dev_err(&indio_dev->dev,
+				"%s: WhoAmI mismatch (0x%x).\n",
+				indio_dev->name, wai);
+			return -EINVAL;
+		}
 	}
 
 	sdata->sensor_settings =
diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c
index 98cfee2..b43aa36 100644
--- a/drivers/iio/common/st_sensors/st_sensors_i2c.c
+++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c
@@ -48,8 +48,8 @@ static int st_sensors_i2c_read_multiple_byte(
 	if (multiread_bit)
 		reg_addr |= ST_SENSORS_I2C_MULTIREAD;
 
-	return i2c_smbus_read_i2c_block_data(to_i2c_client(dev),
-							reg_addr, len, data);
+	return i2c_smbus_read_i2c_block_data_or_emulated(to_i2c_client(dev),
+							 reg_addr, len, data);
 }
 
 static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,
diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
index 6a8c983..e66f12e 100644
--- a/drivers/iio/common/st_sensors/st_sensors_trigger.c
+++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
@@ -17,6 +17,116 @@
 #include <linux/iio/common/st_sensors.h>
 #include "st_sensors_core.h"
 
+/**
+ * st_sensors_new_samples_available() - check if more samples came in
+ * returns:
+ * 0 - no new samples available
+ * 1 - new samples available
+ * negative - error or unknown
+ */
+static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
+					    struct st_sensor_data *sdata)
+{
+	u8 status;
+	int ret;
+
+	/* How would I know if I can't check it? */
+	if (!sdata->sensor_settings->drdy_irq.addr_stat_drdy)
+		return -EINVAL;
+
+	/* No scan mask, no interrupt */
+	if (!indio_dev->active_scan_mask)
+		return 0;
+
+	ret = sdata->tf->read_byte(&sdata->tb, sdata->dev,
+			sdata->sensor_settings->drdy_irq.addr_stat_drdy,
+			&status);
+	if (ret < 0) {
+		dev_err(sdata->dev,
+			"error checking samples available\n");
+		return ret;
+	}
+	/*
+	 * the lower bits of .active_scan_mask[0] is directly mapped
+	 * to the channels on the sensor: either bit 0 for
+	 * one-dimensional sensors, or e.g. x,y,z for accelerometers,
+	 * gyroscopes or magnetometers. No sensor use more than 3
+	 * channels, so cut the other status bits here.
+	 */
+	status &= 0x07;
+
+	if (status & (u8)indio_dev->active_scan_mask[0])
+		return 1;
+
+	return 0;
+}
+
+/**
+ * st_sensors_irq_handler() - top half of the IRQ-based triggers
+ * @irq: irq number
+ * @p: private handler data
+ */
+irqreturn_t st_sensors_irq_handler(int irq, void *p)
+{
+	struct iio_trigger *trig = p;
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+	/* Get the time stamp as close in time as possible */
+	sdata->hw_timestamp = iio_get_time_ns(indio_dev);
+	return IRQ_WAKE_THREAD;
+}
+
+/**
+ * st_sensors_irq_thread() - bottom half of the IRQ-based triggers
+ * @irq: irq number
+ * @p: private handler data
+ */
+irqreturn_t st_sensors_irq_thread(int irq, void *p)
+{
+	struct iio_trigger *trig = p;
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct st_sensor_data *sdata = iio_priv(indio_dev);
+
+	/*
+	 * If this trigger is backed by a hardware interrupt and we have a
+	 * status register, check if this IRQ came from us. Notice that
+	 * we will process also if st_sensors_new_samples_available()
+	 * returns negative: if we can't check status, then poll
+	 * unconditionally.
+	 */
+	if (sdata->hw_irq_trigger &&
+	    st_sensors_new_samples_available(indio_dev, sdata)) {
+		iio_trigger_poll_chained(p);
+	} else {
+		dev_dbg(sdata->dev, "spurious IRQ\n");
+		return IRQ_NONE;
+	}
+
+	/*
+	 * If we have proper level IRQs the handler will be re-entered if
+	 * the line is still active, so return here and come back in through
+	 * the top half if need be.
+	 */
+	if (!sdata->edge_irq)
+		return IRQ_HANDLED;
+
+	/*
+	 * If we are using egde IRQs, new samples arrived while processing
+	 * the IRQ and those may be missed unless we pick them here, so poll
+	 * again. If the sensor delivery frequency is very high, this thread
+	 * turns into a polled loop handler.
+	 */
+	while (sdata->hw_irq_trigger &&
+	       st_sensors_new_samples_available(indio_dev, sdata)) {
+		dev_dbg(sdata->dev, "more samples came in during polling\n");
+		sdata->hw_timestamp = iio_get_time_ns(indio_dev);
+		iio_trigger_poll_chained(p);
+	}
+
+	return IRQ_HANDLED;
+}
+
 int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 				const struct iio_trigger_ops *trigger_ops)
 {
@@ -30,19 +140,28 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 		return -ENOMEM;
 	}
 
+	iio_trigger_set_drvdata(sdata->trig, indio_dev);
+	sdata->trig->ops = trigger_ops;
+	sdata->trig->dev.parent = sdata->dev;
+
 	irq = sdata->get_irq_data_ready(indio_dev);
 	irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
 	/*
 	 * If the IRQ is triggered on falling edge, we need to mark the
 	 * interrupt as active low, if the hardware supports this.
 	 */
-	if (irq_trig == IRQF_TRIGGER_FALLING) {
+	switch(irq_trig) {
+	case IRQF_TRIGGER_FALLING:
+	case IRQF_TRIGGER_LOW:
 		if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
 			dev_err(&indio_dev->dev,
-				"falling edge specified for IRQ but hardware "
-				"only support rising edge, will request "
-				"rising edge\n");
-			irq_trig = IRQF_TRIGGER_RISING;
+				"falling/low specified for IRQ "
+				"but hardware only support rising/high: "
+				"will request rising/high\n");
+			if (irq_trig == IRQF_TRIGGER_FALLING)
+				irq_trig = IRQF_TRIGGER_RISING;
+			if (irq_trig == IRQF_TRIGGER_LOW)
+				irq_trig = IRQF_TRIGGER_HIGH;
 		} else {
 			/* Set up INT active low i.e. falling edge */
 			err = st_sensors_write_data_with_mask(indio_dev,
@@ -51,22 +170,54 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 			if (err < 0)
 				goto iio_trigger_free;
 			dev_info(&indio_dev->dev,
-				 "interrupts on the falling edge\n");
+				 "interrupts on the falling edge or "
+				 "active low level\n");
 		}
-	} else if (irq_trig == IRQF_TRIGGER_RISING) {
+		break;
+	case IRQF_TRIGGER_RISING:
 		dev_info(&indio_dev->dev,
 			 "interrupts on the rising edge\n");
-
-	} else {
+		break;
+	case IRQF_TRIGGER_HIGH:
+		dev_info(&indio_dev->dev,
+			 "interrupts active high level\n");
+		break;
+	default:
+		/* This is the most preferred mode, if possible */
 		dev_err(&indio_dev->dev,
-		"unsupported IRQ trigger specified (%lx), only "
-			"rising and falling edges supported, enforce "
+			"unsupported IRQ trigger specified (%lx), enforce "
 			"rising edge\n", irq_trig);
 		irq_trig = IRQF_TRIGGER_RISING;
 	}
-	err = request_threaded_irq(irq,
-			iio_trigger_generic_data_rdy_poll,
-			NULL,
+
+	/* Tell the interrupt handler that we're dealing with edges */
+	if (irq_trig == IRQF_TRIGGER_FALLING ||
+	    irq_trig == IRQF_TRIGGER_RISING)
+		sdata->edge_irq = true;
+	else
+		/*
+		 * If we're not using edges (i.e. level interrupts) we
+		 * just mask off the IRQ, handle one interrupt, then
+		 * if the line is still low, we return to the
+		 * interrupt handler top half again and start over.
+		 */
+		irq_trig |= IRQF_ONESHOT;
+
+	/*
+	 * If the interrupt pin is Open Drain, by definition this
+	 * means that the interrupt line may be shared with other
+	 * peripherals. But to do this we also need to have a status
+	 * register and mask to figure out if this sensor was firing
+	 * the IRQ or not, so we can tell the interrupt handle that
+	 * it was "our" interrupt.
+	 */
+	if (sdata->int_pin_open_drain &&
+	    sdata->sensor_settings->drdy_irq.addr_stat_drdy)
+		irq_trig |= IRQF_SHARED;
+
+	err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
+			st_sensors_irq_handler,
+			st_sensors_irq_thread,
 			irq_trig,
 			sdata->trig->name,
 			sdata->trig);
@@ -75,10 +226,6 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 		goto iio_trigger_free;
 	}
 
-	iio_trigger_set_drvdata(sdata->trig, indio_dev);
-	sdata->trig->ops = trigger_ops;
-	sdata->trig->dev.parent = sdata->dev;
-
 	err = iio_trigger_register(sdata->trig);
 	if (err < 0) {
 		dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
@@ -106,6 +253,18 @@ void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
 }
 EXPORT_SYMBOL(st_sensors_deallocate_trigger);
 
+int st_sensors_validate_device(struct iio_trigger *trig,
+			       struct iio_dev *indio_dev)
+{
+	struct iio_dev *indio = iio_trigger_get_drvdata(trig);
+
+	if (indio != indio_dev)
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(st_sensors_validate_device);
+
 MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
 MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index a995139..ca81447 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -74,6 +74,33 @@ config AD5449
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad5449.
 
+config AD5592R_BASE
+	tristate
+
+config AD5592R
+	tristate "Analog Devices AD5592R ADC/DAC driver"
+	depends on SPI_MASTER
+	select GPIOLIB
+	select AD5592R_BASE
+	help
+	  Say yes here to build support for Analog Devices AD5592R
+	  Digital to Analog / Analog to Digital Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5592r.
+
+config AD5593R
+	tristate "Analog Devices AD5593R ADC/DAC driver"
+	depends on I2C
+	select GPIOLIB
+	select AD5592R_BASE
+	help
+	  Say yes here to build support for Analog Devices AD5593R
+	  Digital to Analog / Analog to Digital Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5593r.
+
 config AD5504
 	tristate "Analog Devices AD5504/AD5501 DAC SPI driver"
 	depends on SPI
@@ -154,6 +181,16 @@ config AD7303
 	  To compile this driver as module choose M here: the module will be called
 	  ad7303.
 
+config LPC18XX_DAC
+	tristate "NXP LPC18xx DAC driver"
+	depends on ARCH_LPC18XX || COMPILE_TEST
+	depends on OF && HAS_IOMEM
+	help
+	  Say yes here to build support for NXP LPC18XX DAC.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called lpc18xx_dac.
+
 config M62332
 	tristate "Mitsubishi M62332 DAC driver"
 	depends on I2C
@@ -210,12 +247,13 @@ config MCP4922
 
 config STX104
 	tristate "Apex Embedded Systems STX104 DAC driver"
-	depends on ISA
+	depends on X86 && ISA_BUS_API
+	select GPIOLIB
 	help
-	  Say yes here to build support for the 2-channel DAC on the Apex
-	  Embedded Systems STX104 integrated analog PC/104 card. The base port
-	  addresses for the devices may be configured via the "base" module
-	  parameter array.
+	  Say yes here to build support for the 2-channel DAC and GPIO on the
+	  Apex Embedded Systems STX104 integrated analog PC/104 card. The base
+	  port addresses for the devices may be configured via the base array
+	  module parameter.
 
 config VF610_DAC
 	tristate "Vybrid vf610 DAC driver"
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 67b4842..8b78d5c 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -11,12 +11,16 @@ obj-$(CONFIG_AD5064) += ad5064.o
 obj-$(CONFIG_AD5504) += ad5504.o
 obj-$(CONFIG_AD5446) += ad5446.o
 obj-$(CONFIG_AD5449) += ad5449.o
+obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
+obj-$(CONFIG_AD5592R) += ad5592r.o
+obj-$(CONFIG_AD5593R) += ad5593r.o
 obj-$(CONFIG_AD5755) += ad5755.o
 obj-$(CONFIG_AD5761) += ad5761.o
 obj-$(CONFIG_AD5764) += ad5764.o
 obj-$(CONFIG_AD5791) += ad5791.o
 obj-$(CONFIG_AD5686) += ad5686.o
 obj-$(CONFIG_AD7303) += ad7303.o
+obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
 obj-$(CONFIG_M62332) += m62332.o
 obj-$(CONFIG_MAX517) += max517.o
 obj-$(CONFIG_MAX5821) += max5821.o
diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c
index 968712b..559061a 100644
--- a/drivers/iio/dac/ad5421.c
+++ b/drivers/iio/dac/ad5421.c
@@ -242,7 +242,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data)
 					0,
 					IIO_EV_TYPE_THRESH,
 					IIO_EV_DIR_RISING),
-			iio_get_time_ns());
+			iio_get_time_ns(indio_dev));
 		}
 
 		if (events & AD5421_FAULT_UNDER_CURRENT) {
@@ -251,7 +251,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data)
 					0,
 					IIO_EV_TYPE_THRESH,
 					IIO_EV_DIR_FALLING),
-				iio_get_time_ns());
+				iio_get_time_ns(indio_dev));
 		}
 
 		if (events & AD5421_FAULT_TEMP_OVER_140) {
@@ -260,7 +260,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data)
 					0,
 					IIO_EV_TYPE_MAG,
 					IIO_EV_DIR_RISING),
-				iio_get_time_ns());
+				iio_get_time_ns(indio_dev));
 		}
 
 		old_fault = fault;
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index 4e4c20d..788b3d6 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -223,7 +223,7 @@ static irqreturn_t ad5504_event_handler(int irq, void *private)
 					    0,
 					    IIO_EV_TYPE_THRESH,
 					    IIO_EV_DIR_RISING),
-		       iio_get_time_ns());
+		       iio_get_time_ns((struct iio_dev *)private));
 
 	return IRQ_HANDLED;
 }
diff --git b/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c
new file mode 100644
index 0000000..69bde59
--- /dev/null
+++ b/drivers/iio/dac/ad5592r-base.c
@@ -0,0 +1,691 @@
+/*
+ * AD5592R Digital <-> Analog converters driver
+ *
+ * Copyright 2014-2016 Analog Devices Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio.h>
+#include <linux/property.h>
+
+#include <dt-bindings/iio/adi,ad5592r.h>
+
+#include "ad5592r-base.h"
+
+static int ad5592r_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct ad5592r_state *st = gpiochip_get_data(chip);
+	int ret = 0;
+	u8 val;
+
+	mutex_lock(&st->gpio_lock);
+
+	if (st->gpio_out & BIT(offset))
+		val = st->gpio_val;
+	else
+		ret = st->ops->gpio_read(st, &val);
+
+	mutex_unlock(&st->gpio_lock);
+
+	if (ret < 0)
+		return ret;
+
+	return !!(val & BIT(offset));
+}
+
+static void ad5592r_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct ad5592r_state *st = gpiochip_get_data(chip);
+
+	mutex_lock(&st->gpio_lock);
+
+	if (value)
+		st->gpio_val |= BIT(offset);
+	else
+		st->gpio_val &= ~BIT(offset);
+
+	st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
+
+	mutex_unlock(&st->gpio_lock);
+}
+
+static int ad5592r_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct ad5592r_state *st = gpiochip_get_data(chip);
+	int ret;
+
+	mutex_lock(&st->gpio_lock);
+
+	st->gpio_out &= ~BIT(offset);
+	st->gpio_in |= BIT(offset);
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
+	if (ret < 0)
+		goto err_unlock;
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
+
+err_unlock:
+	mutex_unlock(&st->gpio_lock);
+
+	return ret;
+}
+
+static int ad5592r_gpio_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int value)
+{
+	struct ad5592r_state *st = gpiochip_get_data(chip);
+	int ret;
+
+	mutex_lock(&st->gpio_lock);
+
+	if (value)
+		st->gpio_val |= BIT(offset);
+	else
+		st->gpio_val &= ~BIT(offset);
+
+	st->gpio_in &= ~BIT(offset);
+	st->gpio_out |= BIT(offset);
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
+	if (ret < 0)
+		goto err_unlock;
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
+	if (ret < 0)
+		goto err_unlock;
+
+	ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
+
+err_unlock:
+	mutex_unlock(&st->gpio_lock);
+
+	return ret;
+}
+
+static int ad5592r_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct ad5592r_state *st = gpiochip_get_data(chip);
+
+	if (!(st->gpio_map & BIT(offset))) {
+		dev_err(st->dev, "GPIO %d is reserved by alternate function\n",
+			offset);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int ad5592r_gpio_init(struct ad5592r_state *st)
+{
+	if (!st->gpio_map)
+		return 0;
+
+	st->gpiochip.label = dev_name(st->dev);
+	st->gpiochip.base = -1;
+	st->gpiochip.ngpio = 8;
+	st->gpiochip.parent = st->dev;
+	st->gpiochip.can_sleep = true;
+	st->gpiochip.direction_input = ad5592r_gpio_direction_input;
+	st->gpiochip.direction_output = ad5592r_gpio_direction_output;
+	st->gpiochip.get = ad5592r_gpio_get;
+	st->gpiochip.set = ad5592r_gpio_set;
+	st->gpiochip.request = ad5592r_gpio_request;
+	st->gpiochip.owner = THIS_MODULE;
+
+	mutex_init(&st->gpio_lock);
+
+	return gpiochip_add_data(&st->gpiochip, st);
+}
+
+static void ad5592r_gpio_cleanup(struct ad5592r_state *st)
+{
+	if (st->gpio_map)
+		gpiochip_remove(&st->gpiochip);
+}
+
+static int ad5592r_reset(struct ad5592r_state *st)
+{
+	struct gpio_desc *gpio;
+	struct iio_dev *iio_dev = iio_priv_to_dev(st);
+
+	gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(gpio))
+		return PTR_ERR(gpio);
+
+	if (gpio) {
+		udelay(1);
+		gpiod_set_value(gpio, 1);
+	} else {
+		mutex_lock(&iio_dev->mlock);
+		/* Writing this magic value resets the device */
+		st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac);
+		mutex_unlock(&iio_dev->mlock);
+	}
+
+	udelay(250);
+
+	return 0;
+}
+
+static int ad5592r_get_vref(struct ad5592r_state *st)
+{
+	int ret;
+
+	if (st->reg) {
+		ret = regulator_get_voltage(st->reg);
+		if (ret < 0)
+			return ret;
+
+		return ret / 1000;
+	} else {
+		return 2500;
+	}
+}
+
+static int ad5592r_set_channel_modes(struct ad5592r_state *st)
+{
+	const struct ad5592r_rw_ops *ops = st->ops;
+	int ret;
+	unsigned i;
+	struct iio_dev *iio_dev = iio_priv_to_dev(st);
+	u8 pulldown = 0, tristate = 0, dac = 0, adc = 0;
+	u16 read_back;
+
+	for (i = 0; i < st->num_channels; i++) {
+		switch (st->channel_modes[i]) {
+		case CH_MODE_DAC:
+			dac |= BIT(i);
+			break;
+
+		case CH_MODE_ADC:
+			adc |= BIT(i);
+			break;
+
+		case CH_MODE_DAC_AND_ADC:
+			dac |= BIT(i);
+			adc |= BIT(i);
+			break;
+
+		case CH_MODE_GPIO:
+			st->gpio_map |= BIT(i);
+			st->gpio_in |= BIT(i); /* Default to input */
+			break;
+
+		case CH_MODE_UNUSED:
+			/* fall-through */
+		default:
+			switch (st->channel_offstate[i]) {
+			case CH_OFFSTATE_OUT_TRISTATE:
+				tristate |= BIT(i);
+				break;
+
+			case CH_OFFSTATE_OUT_LOW:
+				st->gpio_out |= BIT(i);
+				break;
+
+			case CH_OFFSTATE_OUT_HIGH:
+				st->gpio_out |= BIT(i);
+				st->gpio_val |= BIT(i);
+				break;
+
+			case CH_OFFSTATE_PULLDOWN:
+				/* fall-through */
+			default:
+				pulldown |= BIT(i);
+				break;
+			}
+		}
+	}
+
+	mutex_lock(&iio_dev->mlock);
+
+	/* Pull down unused pins to GND */
+	ret = ops->reg_write(st, AD5592R_REG_PULLDOWN, pulldown);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_TRISTATE, tristate);
+	if (ret)
+		goto err_unlock;
+
+	/* Configure pins that we use */
+	ret = ops->reg_write(st, AD5592R_REG_DAC_EN, dac);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_ADC_EN, adc);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
+	if (ret)
+		goto err_unlock;
+
+	ret = ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
+	if (ret)
+		goto err_unlock;
+
+	/* Verify that we can read back at least one register */
+	ret = ops->reg_read(st, AD5592R_REG_ADC_EN, &read_back);
+	if (!ret && (read_back & 0xff) != adc)
+		ret = -EIO;
+
+err_unlock:
+	mutex_unlock(&iio_dev->mlock);
+	return ret;
+}
+
+static int ad5592r_reset_channel_modes(struct ad5592r_state *st)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(st->channel_modes); i++)
+		st->channel_modes[i] = CH_MODE_UNUSED;
+
+	return ad5592r_set_channel_modes(st);
+}
+
+static int ad5592r_write_raw(struct iio_dev *iio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	struct ad5592r_state *st = iio_priv(iio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+
+		if (val >= (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		if (!chan->output)
+			return -EINVAL;
+
+		mutex_lock(&iio_dev->mlock);
+		ret = st->ops->write_dac(st, chan->channel, val);
+		if (!ret)
+			st->cached_dac[chan->channel] = val;
+		mutex_unlock(&iio_dev->mlock);
+		return ret;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_VOLTAGE) {
+			bool gain;
+
+			if (val == st->scale_avail[0][0] &&
+				val2 == st->scale_avail[0][1])
+				gain = false;
+			else if (val == st->scale_avail[1][0] &&
+				 val2 == st->scale_avail[1][1])
+				gain = true;
+			else
+				return -EINVAL;
+
+			mutex_lock(&iio_dev->mlock);
+
+			ret = st->ops->reg_read(st, AD5592R_REG_CTRL,
+						&st->cached_gp_ctrl);
+			if (ret < 0) {
+				mutex_unlock(&iio_dev->mlock);
+				return ret;
+			}
+
+			if (chan->output) {
+				if (gain)
+					st->cached_gp_ctrl |=
+						AD5592R_REG_CTRL_DAC_RANGE;
+				else
+					st->cached_gp_ctrl &=
+						~AD5592R_REG_CTRL_DAC_RANGE;
+			} else {
+				if (gain)
+					st->cached_gp_ctrl |=
+						AD5592R_REG_CTRL_ADC_RANGE;
+				else
+					st->cached_gp_ctrl &=
+						~AD5592R_REG_CTRL_ADC_RANGE;
+			}
+
+			ret = st->ops->reg_write(st, AD5592R_REG_CTRL,
+						 st->cached_gp_ctrl);
+			mutex_unlock(&iio_dev->mlock);
+
+			return ret;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ad5592r_read_raw(struct iio_dev *iio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long m)
+{
+	struct ad5592r_state *st = iio_priv(iio_dev);
+	u16 read_val;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&iio_dev->mlock);
+
+		if (!chan->output) {
+			ret = st->ops->read_adc(st, chan->channel, &read_val);
+			if (ret)
+				goto unlock;
+
+			if ((read_val >> 12 & 0x7) != (chan->channel & 0x7)) {
+				dev_err(st->dev, "Error while reading channel %u\n",
+						chan->channel);
+				ret = -EIO;
+				goto unlock;
+			}
+
+			read_val &= GENMASK(11, 0);
+
+		} else {
+			read_val = st->cached_dac[chan->channel];
+		}
+
+		dev_dbg(st->dev, "Channel %u read: 0x%04hX\n",
+				chan->channel, read_val);
+
+		*val = (int) read_val;
+		ret = IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		*val = ad5592r_get_vref(st);
+
+		if (chan->type == IIO_TEMP) {
+			s64 tmp = *val * (3767897513LL / 25LL);
+			*val = div_s64_rem(tmp, 1000000000LL, val2);
+
+			ret = IIO_VAL_INT_PLUS_MICRO;
+		} else {
+			int mult;
+
+			mutex_lock(&iio_dev->mlock);
+
+			if (chan->output)
+				mult = !!(st->cached_gp_ctrl &
+					AD5592R_REG_CTRL_DAC_RANGE);
+			else
+				mult = !!(st->cached_gp_ctrl &
+					AD5592R_REG_CTRL_ADC_RANGE);
+
+			*val *= ++mult;
+
+			*val2 = chan->scan_type.realbits;
+			ret = IIO_VAL_FRACTIONAL_LOG2;
+		}
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		ret = ad5592r_get_vref(st);
+
+		mutex_lock(&iio_dev->mlock);
+
+		if (st->cached_gp_ctrl & AD5592R_REG_CTRL_ADC_RANGE)
+			*val = (-34365 * 25) / ret;
+		else
+			*val = (-75365 * 25) / ret;
+		ret =  IIO_VAL_INT;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+unlock:
+	mutex_unlock(&iio_dev->mlock);
+	return ret;
+}
+
+static int ad5592r_write_raw_get_fmt(struct iio_dev *indio_dev,
+				 struct iio_chan_spec const *chan, long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+
+	default:
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ad5592r_info = {
+	.read_raw = ad5592r_read_raw,
+	.write_raw = ad5592r_write_raw,
+	.write_raw_get_fmt = ad5592r_write_raw_get_fmt,
+	.driver_module = THIS_MODULE,
+};
+
+static ssize_t ad5592r_show_scale_available(struct iio_dev *iio_dev,
+					   uintptr_t private,
+					   const struct iio_chan_spec *chan,
+					   char *buf)
+{
+	struct ad5592r_state *st = iio_priv(iio_dev);
+
+	return sprintf(buf, "%d.%09u %d.%09u\n",
+		st->scale_avail[0][0], st->scale_avail[0][1],
+		st->scale_avail[1][0], st->scale_avail[1][1]);
+}
+
+static struct iio_chan_spec_ext_info ad5592r_ext_info[] = {
+	{
+	 .name = "scale_available",
+	 .read = ad5592r_show_scale_available,
+	 .shared = true,
+	 },
+	{},
+};
+
+static void ad5592r_setup_channel(struct iio_dev *iio_dev,
+		struct iio_chan_spec *chan, bool output, unsigned id)
+{
+	chan->type = IIO_VOLTAGE;
+	chan->indexed = 1;
+	chan->output = output;
+	chan->channel = id;
+	chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+	chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+	chan->scan_type.sign = 'u';
+	chan->scan_type.realbits = 12;
+	chan->scan_type.storagebits = 16;
+	chan->ext_info = ad5592r_ext_info;
+}
+
+static int ad5592r_alloc_channels(struct ad5592r_state *st)
+{
+	unsigned i, curr_channel = 0,
+		 num_channels = st->num_channels;
+	struct iio_dev *iio_dev = iio_priv_to_dev(st);
+	struct iio_chan_spec *channels;
+	struct fwnode_handle *child;
+	u32 reg, tmp;
+	int ret;
+
+	device_for_each_child_node(st->dev, child) {
+		ret = fwnode_property_read_u32(child, "reg", &reg);
+		if (ret || reg >= ARRAY_SIZE(st->channel_modes))
+			continue;
+
+		ret = fwnode_property_read_u32(child, "adi,mode", &tmp);
+		if (!ret)
+			st->channel_modes[reg] = tmp;
+
+		fwnode_property_read_u32(child, "adi,off-state", &tmp);
+		if (!ret)
+			st->channel_offstate[reg] = tmp;
+	}
+
+	channels = devm_kzalloc(st->dev,
+			(1 + 2 * num_channels) * sizeof(*channels), GFP_KERNEL);
+	if (!channels)
+		return -ENOMEM;
+
+	for (i = 0; i < num_channels; i++) {
+		switch (st->channel_modes[i]) {
+		case CH_MODE_DAC:
+			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
+					true, i);
+			curr_channel++;
+			break;
+
+		case CH_MODE_ADC:
+			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
+					false, i);
+			curr_channel++;
+			break;
+
+		case CH_MODE_DAC_AND_ADC:
+			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
+					true, i);
+			curr_channel++;
+			ad5592r_setup_channel(iio_dev, &channels[curr_channel],
+					false, i);
+			curr_channel++;
+			break;
+
+		default:
+			continue;
+		}
+	}
+
+	channels[curr_channel].type = IIO_TEMP;
+	channels[curr_channel].channel = 8;
+	channels[curr_channel].info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				   BIT(IIO_CHAN_INFO_SCALE) |
+				   BIT(IIO_CHAN_INFO_OFFSET);
+	curr_channel++;
+
+	iio_dev->num_channels = curr_channel;
+	iio_dev->channels = channels;
+
+	return 0;
+}
+
+static void ad5592r_init_scales(struct ad5592r_state *st, int vref_mV)
+{
+	s64 tmp = (s64)vref_mV * 1000000000LL >> 12;
+
+	st->scale_avail[0][0] =
+		div_s64_rem(tmp, 1000000000LL, &st->scale_avail[0][1]);
+	st->scale_avail[1][0] =
+		div_s64_rem(tmp * 2, 1000000000LL, &st->scale_avail[1][1]);
+}
+
+int ad5592r_probe(struct device *dev, const char *name,
+		const struct ad5592r_rw_ops *ops)
+{
+	struct iio_dev *iio_dev;
+	struct ad5592r_state *st;
+	int ret;
+
+	iio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+	if (!iio_dev)
+		return -ENOMEM;
+
+	st = iio_priv(iio_dev);
+	st->dev = dev;
+	st->ops = ops;
+	st->num_channels = 8;
+	dev_set_drvdata(dev, iio_dev);
+
+	st->reg = devm_regulator_get_optional(dev, "vref");
+	if (IS_ERR(st->reg)) {
+		if ((PTR_ERR(st->reg) != -ENODEV) && dev->of_node)
+			return PTR_ERR(st->reg);
+
+		st->reg = NULL;
+	} else {
+		ret = regulator_enable(st->reg);
+		if (ret)
+			return ret;
+	}
+
+	iio_dev->dev.parent = dev;
+	iio_dev->name = name;
+	iio_dev->info = &ad5592r_info;
+	iio_dev->modes = INDIO_DIRECT_MODE;
+
+	ad5592r_init_scales(st, ad5592r_get_vref(st));
+
+	ret = ad5592r_reset(st);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = ops->reg_write(st, AD5592R_REG_PD,
+		     (st->reg == NULL) ? AD5592R_REG_PD_EN_REF : 0);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = ad5592r_alloc_channels(st);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = ad5592r_set_channel_modes(st);
+	if (ret)
+		goto error_reset_ch_modes;
+
+	ret = iio_device_register(iio_dev);
+	if (ret)
+		goto error_reset_ch_modes;
+
+	ret = ad5592r_gpio_init(st);
+	if (ret)
+		goto error_dev_unregister;
+
+	return 0;
+
+error_dev_unregister:
+	iio_device_unregister(iio_dev);
+
+error_reset_ch_modes:
+	ad5592r_reset_channel_modes(st);
+
+error_disable_reg:
+	if (st->reg)
+		regulator_disable(st->reg);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ad5592r_probe);
+
+int ad5592r_remove(struct device *dev)
+{
+	struct iio_dev *iio_dev = dev_get_drvdata(dev);
+	struct ad5592r_state *st = iio_priv(iio_dev);
+
+	iio_device_unregister(iio_dev);
+	ad5592r_reset_channel_modes(st);
+	ad5592r_gpio_cleanup(st);
+
+	if (st->reg)
+		regulator_disable(st->reg);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ad5592r_remove);
+
+MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/iio/dac/ad5592r-base.h b/drivers/iio/dac/ad5592r-base.h
new file mode 100644
index 0000000..841457e
--- /dev/null
+++ b/drivers/iio/dac/ad5592r-base.h
@@ -0,0 +1,76 @@
+/*
+ * AD5592R / AD5593R Digital <-> Analog converters driver
+ *
+ * Copyright 2015-2016 Analog Devices Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __DRIVERS_IIO_DAC_AD5592R_BASE_H__
+#define __DRIVERS_IIO_DAC_AD5592R_BASE_H__
+
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include <linux/gpio/driver.h>
+
+struct device;
+struct ad5592r_state;
+
+enum ad5592r_registers {
+	AD5592R_REG_NOOP		= 0x0,
+	AD5592R_REG_DAC_READBACK	= 0x1,
+	AD5592R_REG_ADC_SEQ		= 0x2,
+	AD5592R_REG_CTRL		= 0x3,
+	AD5592R_REG_ADC_EN		= 0x4,
+	AD5592R_REG_DAC_EN		= 0x5,
+	AD5592R_REG_PULLDOWN		= 0x6,
+	AD5592R_REG_LDAC		= 0x7,
+	AD5592R_REG_GPIO_OUT_EN		= 0x8,
+	AD5592R_REG_GPIO_SET		= 0x9,
+	AD5592R_REG_GPIO_IN_EN		= 0xA,
+	AD5592R_REG_PD			= 0xB,
+	AD5592R_REG_OPEN_DRAIN		= 0xC,
+	AD5592R_REG_TRISTATE		= 0xD,
+	AD5592R_REG_RESET		= 0xF,
+};
+
+#define AD5592R_REG_PD_EN_REF		BIT(9)
+#define AD5592R_REG_CTRL_ADC_RANGE	BIT(5)
+#define AD5592R_REG_CTRL_DAC_RANGE	BIT(4)
+
+struct ad5592r_rw_ops {
+	int (*write_dac)(struct ad5592r_state *st, unsigned chan, u16 value);
+	int (*read_adc)(struct ad5592r_state *st, unsigned chan, u16 *value);
+	int (*reg_write)(struct ad5592r_state *st, u8 reg, u16 value);
+	int (*reg_read)(struct ad5592r_state *st, u8 reg, u16 *value);
+	int (*gpio_read)(struct ad5592r_state *st, u8 *value);
+};
+
+struct ad5592r_state {
+	struct device *dev;
+	struct regulator *reg;
+	struct gpio_chip gpiochip;
+	struct mutex gpio_lock;	/* Protect cached gpio_out, gpio_val, etc. */
+	unsigned int num_channels;
+	const struct ad5592r_rw_ops *ops;
+	int scale_avail[2][2];
+	u16 cached_dac[8];
+	u16 cached_gp_ctrl;
+	u8 channel_modes[8];
+	u8 channel_offstate[8];
+	u8 gpio_map;
+	u8 gpio_out;
+	u8 gpio_in;
+	u8 gpio_val;
+
+	__be16 spi_msg ____cacheline_aligned;
+	__be16 spi_msg_nop;
+};
+
+int ad5592r_probe(struct device *dev, const char *name,
+		const struct ad5592r_rw_ops *ops);
+int ad5592r_remove(struct device *dev);
+
+#endif /* __DRIVERS_IIO_DAC_AD5592R_BASE_H__ */
diff --git b/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c
new file mode 100644
index 0000000..0b235a2
--- /dev/null
+++ b/drivers/iio/dac/ad5592r.c
@@ -0,0 +1,164 @@
+/*
+ * AD5592R Digital <-> Analog converters driver
+ *
+ * Copyright 2015-2016 Analog Devices Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include "ad5592r-base.h"
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+#define AD5592R_GPIO_READBACK_EN	BIT(10)
+#define AD5592R_LDAC_READBACK_EN	BIT(6)
+
+static int ad5592r_spi_wnop_r16(struct ad5592r_state *st, u16 *buf)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+	struct spi_transfer t = {
+			.tx_buf	= &st->spi_msg_nop,
+			.rx_buf	= buf,
+			.len = 2
+		};
+
+	st->spi_msg_nop = 0; /* NOP */
+
+	return spi_sync_transfer(spi, &t, 1);
+}
+
+static int ad5592r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+
+	st->spi_msg = cpu_to_be16(BIT(15) | (chan << 12) | value);
+
+	return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
+}
+
+static int ad5592r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+	int ret;
+
+	st->spi_msg = cpu_to_be16((AD5592R_REG_ADC_SEQ << 11) | BIT(chan));
+
+	ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
+	if (ret)
+		return ret;
+
+	/*
+	 * Invalid data:
+	 * See Figure 40. Single-Channel ADC Conversion Sequence
+	 */
+	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
+	if (ret)
+		return ret;
+
+	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
+	if (ret)
+		return ret;
+
+	*value = be16_to_cpu(st->spi_msg);
+
+	return 0;
+}
+
+static int ad5592r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+
+	st->spi_msg = cpu_to_be16((reg << 11) | value);
+
+	return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
+}
+
+static int ad5592r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value)
+{
+	struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+	int ret;
+
+	st->spi_msg = cpu_to_be16((AD5592R_REG_LDAC << 11) |
+				   AD5592R_LDAC_READBACK_EN | (reg << 2));
+
+	ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
+	if (ret)
+		return ret;
+
+	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
+	if (ret)
+		return ret;
+
+	*value = be16_to_cpu(st->spi_msg);
+
+	return 0;
+}
+
+static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
+{
+	int ret;
+
+	ret = ad5592r_reg_write(st, AD5592R_REG_GPIO_IN_EN,
+				AD5592R_GPIO_READBACK_EN | st->gpio_in);
+	if (ret)
+		return ret;
+
+	ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
+	if (ret)
+		return ret;
+
+	*value = (u8) be16_to_cpu(st->spi_msg);
+
+	return 0;
+}
+
+static const struct ad5592r_rw_ops ad5592r_rw_ops = {
+	.write_dac = ad5592r_write_dac,
+	.read_adc = ad5592r_read_adc,
+	.reg_write = ad5592r_reg_write,
+	.reg_read = ad5592r_reg_read,
+	.gpio_read = ad5593r_gpio_read,
+};
+
+static int ad5592r_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+
+	return ad5592r_probe(&spi->dev, id->name, &ad5592r_rw_ops);
+}
+
+static int ad5592r_spi_remove(struct spi_device *spi)
+{
+	return ad5592r_remove(&spi->dev);
+}
+
+static const struct spi_device_id ad5592r_spi_ids[] = {
+	{ .name = "ad5592r", },
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5592r_spi_ids);
+
+static const struct of_device_id ad5592r_of_match[] = {
+	{ .compatible = "adi,ad5592r", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ad5592r_of_match);
+
+static struct spi_driver ad5592r_spi_driver = {
+	.driver = {
+		.name = "ad5592r",
+		.of_match_table = of_match_ptr(ad5592r_of_match),
+	},
+	.probe = ad5592r_spi_probe,
+	.remove = ad5592r_spi_remove,
+	.id_table = ad5592r_spi_ids,
+};
+module_spi_driver(ad5592r_spi_driver);
+
+MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c
new file mode 100644
index 0000000..dca158a
--- /dev/null
+++ b/drivers/iio/dac/ad5593r.c
@@ -0,0 +1,131 @@
+/*
+ * AD5593R Digital <-> Analog converters driver
+ *
+ * Copyright 2015-2016 Analog Devices Inc.
+ * Author: Paul Cercueil <paul.cercueil@analog.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include "ad5592r-base.h"
+
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#define AD5593R_MODE_CONF		(0 << 4)
+#define AD5593R_MODE_DAC_WRITE		(1 << 4)
+#define AD5593R_MODE_ADC_READBACK	(4 << 4)
+#define AD5593R_MODE_DAC_READBACK	(5 << 4)
+#define AD5593R_MODE_GPIO_READBACK	(6 << 4)
+#define AD5593R_MODE_REG_READBACK	(7 << 4)
+
+static int ad5593r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+
+	return i2c_smbus_write_word_swapped(i2c,
+			AD5593R_MODE_DAC_WRITE | chan, value);
+}
+
+static int ad5593r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+	s32 val;
+
+	val = i2c_smbus_write_word_swapped(i2c,
+			AD5593R_MODE_CONF | AD5592R_REG_ADC_SEQ, BIT(chan));
+	if (val < 0)
+		return (int) val;
+
+	val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_ADC_READBACK);
+	if (val < 0)
+		return (int) val;
+
+	*value = (u16) val;
+
+	return 0;
+}
+
+static int ad5593r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+
+	return i2c_smbus_write_word_swapped(i2c,
+			AD5593R_MODE_CONF | reg, value);
+}
+
+static int ad5593r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+	s32 val;
+
+	val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_REG_READBACK | reg);
+	if (val < 0)
+		return (int) val;
+
+	*value = (u16) val;
+
+	return 0;
+}
+
+static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
+{
+	struct i2c_client *i2c = to_i2c_client(st->dev);
+	s32 val;
+
+	val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_GPIO_READBACK);
+	if (val < 0)
+		return (int) val;
+
+	*value = (u8) val;
+
+	return 0;
+}
+
+static const struct ad5592r_rw_ops ad5593r_rw_ops = {
+	.write_dac = ad5593r_write_dac,
+	.read_adc = ad5593r_read_adc,
+	.reg_write = ad5593r_reg_write,
+	.reg_read = ad5593r_reg_read,
+	.gpio_read = ad5593r_gpio_read,
+};
+
+static int ad5593r_i2c_probe(struct i2c_client *i2c,
+		const struct i2c_device_id *id)
+{
+	return ad5592r_probe(&i2c->dev, id->name, &ad5593r_rw_ops);
+}
+
+static int ad5593r_i2c_remove(struct i2c_client *i2c)
+{
+	return ad5592r_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id ad5593r_i2c_ids[] = {
+	{ .name = "ad5593r", },
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ad5593r_i2c_ids);
+
+static const struct of_device_id ad5593r_of_match[] = {
+	{ .compatible = "adi,ad5593r", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ad5593r_of_match);
+
+static struct i2c_driver ad5593r_driver = {
+	.driver = {
+		.name = "ad5593r",
+		.of_match_table = of_match_ptr(ad5593r_of_match),
+	},
+	.probe = ad5593r_i2c_probe,
+	.remove = ad5593r_i2c_remove,
+	.id_table = ad5593r_i2c_ids,
+};
+module_i2c_driver(ad5593r_driver);
+
+MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
index bfb350a..0fde593 100644
--- a/drivers/iio/dac/ad5755.c
+++ b/drivers/iio/dac/ad5755.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/platform_data/ad5755.h>
@@ -109,6 +110,51 @@ enum ad5755_type {
 	ID_AD5737,
 };
 
+#ifdef CONFIG_OF
+static const int ad5755_dcdc_freq_table[][2] = {
+	{ 250000, AD5755_DC_DC_FREQ_250kHZ },
+	{ 410000, AD5755_DC_DC_FREQ_410kHZ },
+	{ 650000, AD5755_DC_DC_FREQ_650kHZ }
+};
+
+static const int ad5755_dcdc_maxv_table[][2] = {
+	{ 23000000, AD5755_DC_DC_MAXV_23V },
+	{ 24500000, AD5755_DC_DC_MAXV_24V5 },
+	{ 27000000, AD5755_DC_DC_MAXV_27V },
+	{ 29500000, AD5755_DC_DC_MAXV_29V5 },
+};
+
+static const int ad5755_slew_rate_table[][2] = {
+	{ 64000, AD5755_SLEW_RATE_64k },
+	{ 32000, AD5755_SLEW_RATE_32k },
+	{ 16000, AD5755_SLEW_RATE_16k },
+	{ 8000, AD5755_SLEW_RATE_8k },
+	{ 4000, AD5755_SLEW_RATE_4k },
+	{ 2000, AD5755_SLEW_RATE_2k },
+	{ 1000, AD5755_SLEW_RATE_1k },
+	{ 500, AD5755_SLEW_RATE_500 },
+	{ 250, AD5755_SLEW_RATE_250 },
+	{ 125, AD5755_SLEW_RATE_125 },
+	{ 64, AD5755_SLEW_RATE_64 },
+	{ 32, AD5755_SLEW_RATE_32 },
+	{ 16, AD5755_SLEW_RATE_16 },
+	{ 8, AD5755_SLEW_RATE_8 },
+	{ 4, AD5755_SLEW_RATE_4 },
+	{ 0, AD5755_SLEW_RATE_0_5 },
+};
+
+static const int ad5755_slew_step_table[][2] = {
+	{ 256, AD5755_SLEW_STEP_SIZE_256 },
+	{ 128, AD5755_SLEW_STEP_SIZE_128 },
+	{ 64, AD5755_SLEW_STEP_SIZE_64 },
+	{ 32, AD5755_SLEW_STEP_SIZE_32 },
+	{ 16, AD5755_SLEW_STEP_SIZE_16 },
+	{ 4, AD5755_SLEW_STEP_SIZE_4 },
+	{ 2, AD5755_SLEW_STEP_SIZE_2 },
+	{ 1, AD5755_SLEW_STEP_SIZE_1 },
+};
+#endif
+
 static int ad5755_write_unlocked(struct iio_dev *indio_dev,
 	unsigned int reg, unsigned int val)
 {
@@ -556,6 +602,129 @@ static const struct ad5755_platform_data ad5755_default_pdata = {
 	},
 };
 
+#ifdef CONFIG_OF
+static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *pp;
+	struct ad5755_platform_data *pdata;
+	unsigned int tmp;
+	unsigned int tmparray[3];
+	int devnr, i;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	pdata->ext_dc_dc_compenstation_resistor =
+	    of_property_read_bool(np, "adi,ext-dc-dc-compenstation-resistor");
+
+	if (!of_property_read_u32(np, "adi,dc-dc-phase", &tmp))
+		pdata->dc_dc_phase = tmp;
+	else
+		pdata->dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE;
+
+	pdata->dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ;
+	if (!of_property_read_u32(np, "adi,dc-dc-freq-hz", &tmp)) {
+		for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_freq_table); i++) {
+			if (tmp == ad5755_dcdc_freq_table[i][0]) {
+				pdata->dc_dc_freq = ad5755_dcdc_freq_table[i][1];
+				break;
+			}
+		}
+
+		if (i == ARRAY_SIZE(ad5755_dcdc_freq_table)) {
+			dev_err(dev,
+				"adi,dc-dc-freq out of range selecting 410kHz");
+		}
+	}
+
+	pdata->dc_dc_maxv = AD5755_DC_DC_MAXV_23V;
+	if (!of_property_read_u32(np, "adi,dc-dc-max-microvolt", &tmp)) {
+		for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_maxv_table); i++) {
+			if (tmp == ad5755_dcdc_maxv_table[i][0]) {
+				pdata->dc_dc_maxv = ad5755_dcdc_maxv_table[i][1];
+				break;
+			}
+		}
+		if (i == ARRAY_SIZE(ad5755_dcdc_maxv_table)) {
+				dev_err(dev,
+					"adi,dc-dc-maxv out of range selecting 23V");
+		}
+	}
+
+	devnr = 0;
+	for_each_child_of_node(np, pp) {
+		if (devnr > AD5755_NUM_CHANNELS) {
+			dev_err(dev,
+				"There is to many channels defined in DT\n");
+			goto error_out;
+		}
+
+		if (!of_property_read_u32(pp, "adi,mode", &tmp))
+			pdata->dac[devnr].mode = tmp;
+		else
+			pdata->dac[devnr].mode = AD5755_MODE_CURRENT_4mA_20mA;
+
+		pdata->dac[devnr].ext_current_sense_resistor =
+		    of_property_read_bool(pp, "adi,ext-current-sense-resistor");
+
+		pdata->dac[devnr].enable_voltage_overrange =
+		    of_property_read_bool(pp, "adi,enable-voltage-overrange");
+
+		if (!of_property_read_u32_array(pp, "adi,slew", tmparray, 3)) {
+			pdata->dac[devnr].slew.enable = tmparray[0];
+
+			pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k;
+			for (i = 0; i < ARRAY_SIZE(ad5755_slew_rate_table); i++) {
+				if (tmparray[1] == ad5755_slew_rate_table[i][0]) {
+					pdata->dac[devnr].slew.rate =
+						ad5755_slew_rate_table[i][1];
+					break;
+				}
+			}
+			if (i == ARRAY_SIZE(ad5755_slew_rate_table)) {
+				dev_err(dev,
+					"channel %d slew rate out of range selecting 64kHz",
+					devnr);
+			}
+
+			pdata->dac[devnr].slew.step_size = AD5755_SLEW_STEP_SIZE_1;
+			for (i = 0; i < ARRAY_SIZE(ad5755_slew_step_table); i++) {
+				if (tmparray[2] == ad5755_slew_step_table[i][0]) {
+					pdata->dac[devnr].slew.step_size =
+						ad5755_slew_step_table[i][1];
+					break;
+				}
+			}
+			if (i == ARRAY_SIZE(ad5755_slew_step_table)) {
+				dev_err(dev,
+					"channel %d slew step size out of range selecting 1 LSB",
+					devnr);
+			}
+		} else {
+			pdata->dac[devnr].slew.enable = false;
+			pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k;
+			pdata->dac[devnr].slew.step_size =
+			    AD5755_SLEW_STEP_SIZE_1;
+		}
+		devnr++;
+	}
+
+	return pdata;
+
+ error_out:
+	devm_kfree(dev, pdata);
+	return NULL;
+}
+#else
+static
+struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
 static int ad5755_probe(struct spi_device *spi)
 {
 	enum ad5755_type type = spi_get_device_id(spi)->driver_data;
@@ -583,8 +752,15 @@ static int ad5755_probe(struct spi_device *spi)
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->num_channels = AD5755_NUM_CHANNELS;
 
-	if (!pdata)
+	if (spi->dev.of_node)
+		pdata = ad5755_parse_dt(&spi->dev);
+	else
+		pdata = spi->dev.platform_data;
+
+	if (!pdata) {
+		dev_warn(&spi->dev, "no platform data? using default\n");
 		pdata = &ad5755_default_pdata;
+	}
 
 	ret = ad5755_init_channels(indio_dev, pdata);
 	if (ret)
@@ -607,6 +783,16 @@ static const struct spi_device_id ad5755_id[] = {
 };
 MODULE_DEVICE_TABLE(spi, ad5755_id);
 
+static const struct of_device_id ad5755_of_match[] = {
+	{ .compatible = "adi,ad5755" },
+	{ .compatible = "adi,ad5755-1" },
+	{ .compatible = "adi,ad5757" },
+	{ .compatible = "adi,ad5735" },
+	{ .compatible = "adi,ad5737" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ad5755_of_match);
+
 static struct spi_driver ad5755_driver = {
 	.driver = {
 		.name = "ad5755",
diff --git b/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c
new file mode 100644
index 0000000..55d1456
--- /dev/null
+++ b/drivers/iio/dac/lpc18xx_dac.c
@@ -0,0 +1,210 @@
+/*
+ * IIO DAC driver for NXP LPC18xx DAC
+ *
+ * Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com>
+ *
+ * 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.
+ *
+ * UNSUPPORTED hardware features:
+ *  - Interrupts
+ *  - DMA
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+/* LPC18XX DAC registers and bits */
+#define LPC18XX_DAC_CR			0x000
+#define  LPC18XX_DAC_CR_VALUE_SHIFT	6
+#define  LPC18XX_DAC_CR_VALUE_MASK	0x3ff
+#define  LPC18XX_DAC_CR_BIAS		BIT(16)
+#define LPC18XX_DAC_CTRL		0x004
+#define  LPC18XX_DAC_CTRL_DMA_ENA	BIT(3)
+
+struct lpc18xx_dac {
+	struct regulator *vref;
+	void __iomem *base;
+	struct mutex lock;
+	struct clk *clk;
+};
+
+static const struct iio_chan_spec lpc18xx_dac_iio_channels[] = {
+	{
+		.type = IIO_VOLTAGE,
+		.output = 1,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+	},
+};
+
+static int lpc18xx_dac_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct lpc18xx_dac *dac = iio_priv(indio_dev);
+	u32 reg;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		reg = readl(dac->base + LPC18XX_DAC_CR);
+		*val = reg >> LPC18XX_DAC_CR_VALUE_SHIFT;
+		*val &= LPC18XX_DAC_CR_VALUE_MASK;
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		*val = regulator_get_voltage(dac->vref) / 1000;
+		*val2 = 10;
+
+		return IIO_VAL_FRACTIONAL_LOG2;
+	}
+
+	return -EINVAL;
+}
+
+static int lpc18xx_dac_write_raw(struct iio_dev *indio_dev,
+				 struct iio_chan_spec const *chan,
+				 int val, int val2, long mask)
+{
+	struct lpc18xx_dac *dac = iio_priv(indio_dev);
+	u32 reg;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val < 0 || val > LPC18XX_DAC_CR_VALUE_MASK)
+			return -EINVAL;
+
+		reg = LPC18XX_DAC_CR_BIAS;
+		reg |= val << LPC18XX_DAC_CR_VALUE_SHIFT;
+
+		mutex_lock(&dac->lock);
+		writel(reg, dac->base + LPC18XX_DAC_CR);
+		writel(LPC18XX_DAC_CTRL_DMA_ENA, dac->base + LPC18XX_DAC_CTRL);
+		mutex_unlock(&dac->lock);
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info lpc18xx_dac_info = {
+	.read_raw = lpc18xx_dac_read_raw,
+	.write_raw = lpc18xx_dac_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int lpc18xx_dac_probe(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev;
+	struct lpc18xx_dac *dac;
+	struct resource *res;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, indio_dev);
+	dac = iio_priv(indio_dev);
+	mutex_init(&dac->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dac->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dac->base))
+		return PTR_ERR(dac->base);
+
+	dac->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dac->clk)) {
+		dev_err(&pdev->dev, "error getting clock\n");
+		return PTR_ERR(dac->clk);
+	}
+
+	dac->vref = devm_regulator_get(&pdev->dev, "vref");
+	if (IS_ERR(dac->vref)) {
+		dev_err(&pdev->dev, "error getting regulator\n");
+		return PTR_ERR(dac->vref);
+	}
+
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &lpc18xx_dac_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = lpc18xx_dac_iio_channels;
+	indio_dev->num_channels = ARRAY_SIZE(lpc18xx_dac_iio_channels);
+
+	ret = regulator_enable(dac->vref);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to enable regulator\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(dac->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to enable clock\n");
+		goto dis_reg;
+	}
+
+	writel(0, dac->base + LPC18XX_DAC_CTRL);
+	writel(0, dac->base + LPC18XX_DAC_CR);
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register device\n");
+		goto dis_clk;
+	}
+
+	return 0;
+
+dis_clk:
+	clk_disable_unprepare(dac->clk);
+dis_reg:
+	regulator_disable(dac->vref);
+	return ret;
+}
+
+static int lpc18xx_dac_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct lpc18xx_dac *dac = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	writel(0, dac->base + LPC18XX_DAC_CTRL);
+	clk_disable_unprepare(dac->clk);
+	regulator_disable(dac->vref);
+
+	return 0;
+}
+
+static const struct of_device_id lpc18xx_dac_match[] = {
+	{ .compatible = "nxp,lpc1850-dac" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, lpc18xx_dac_match);
+
+static struct platform_driver lpc18xx_dac_driver = {
+	.probe	= lpc18xx_dac_probe,
+	.remove	= lpc18xx_dac_remove,
+	.driver	= {
+		.name = "lpc18xx-dac",
+		.of_match_table = lpc18xx_dac_match,
+	},
+};
+module_platform_driver(lpc18xx_dac_driver);
+
+MODULE_DESCRIPTION("LPC18xx DAC driver");
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/stx104.c b/drivers/iio/dac/stx104.c
index 174f4b7..792a971 100644
--- a/drivers/iio/dac/stx104.c
+++ b/drivers/iio/dac/stx104.c
@@ -14,6 +14,7 @@
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/gpio/driver.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/types.h>
 #include <linux/io.h>
@@ -21,6 +22,7 @@
 #include <linux/isa.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/spinlock.h>
 
 #define STX104_NUM_CHAN 2
 
@@ -33,16 +35,9 @@
 }
 
 #define STX104_EXTENT 16
-/**
- * The highest base address possible for an ISA device is 0x3FF; this results in
- * 1024 possible base addresses. Dividing the number of possible base addresses
- * by the address extent taken by each device results in the maximum number of
- * devices on a system.
- */
-#define MAX_NUM_STX104 (1024 / STX104_EXTENT)
 
-static unsigned base[MAX_NUM_STX104];
-static unsigned num_stx104;
+static unsigned int base[max_num_isa_dev(STX104_EXTENT)];
+static unsigned int num_stx104;
 module_param_array(base, uint, &num_stx104, 0);
 MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
 
@@ -56,6 +51,20 @@ struct stx104_iio {
 	unsigned base;
 };
 
+/**
+ * struct stx104_gpio - GPIO device private data structure
+ * @chip:	instance of the gpio_chip
+ * @lock:	synchronization lock to prevent I/O race conditions
+ * @base:	base port address of the GPIO device
+ * @out_state:	output bits state
+ */
+struct stx104_gpio {
+	struct gpio_chip chip;
+	spinlock_t lock;
+	unsigned int base;
+	unsigned int out_state;
+};
+
 static int stx104_read_raw(struct iio_dev *indio_dev,
 	struct iio_chan_spec const *chan, int *val, int *val2, long mask)
 {
@@ -95,15 +104,81 @@ static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = {
 	STX104_CHAN(1)
 };
 
+static int stx104_gpio_get_direction(struct gpio_chip *chip,
+	unsigned int offset)
+{
+	if (offset < 4)
+		return 1;
+
+	return 0;
+}
+
+static int stx104_gpio_direction_input(struct gpio_chip *chip,
+	unsigned int offset)
+{
+	if (offset >= 4)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int stx104_gpio_direction_output(struct gpio_chip *chip,
+	unsigned int offset, int value)
+{
+	if (offset < 4)
+		return -EINVAL;
+
+	chip->set(chip, offset, value);
+	return 0;
+}
+
+static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+
+	if (offset >= 4)
+		return -EINVAL;
+
+	return !!(inb(stx104gpio->base) & BIT(offset));
+}
+
+static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
+	int value)
+{
+	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+	const unsigned int mask = BIT(offset) >> 4;
+	unsigned long flags;
+
+	if (offset < 4)
+		return;
+
+	spin_lock_irqsave(&stx104gpio->lock, flags);
+
+	if (value)
+		stx104gpio->out_state |= mask;
+	else
+		stx104gpio->out_state &= ~mask;
+
+	outb(stx104gpio->out_state, stx104gpio->base);
+
+	spin_unlock_irqrestore(&stx104gpio->lock, flags);
+}
+
 static int stx104_probe(struct device *dev, unsigned int id)
 {
 	struct iio_dev *indio_dev;
 	struct stx104_iio *priv;
+	struct stx104_gpio *stx104gpio;
+	int err;
 
 	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
 	if (!indio_dev)
 		return -ENOMEM;
 
+	stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL);
+	if (!stx104gpio)
+		return -ENOMEM;
+
 	if (!devm_request_region(dev, base[id], STX104_EXTENT,
 		dev_name(dev))) {
 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@@ -124,28 +199,56 @@ static int stx104_probe(struct device *dev, unsigned int id)
 	outw(0, base[id] + 4);
 	outw(0, base[id] + 6);
 
-	return devm_iio_device_register(dev, indio_dev);
-}
+	err = devm_iio_device_register(dev, indio_dev);
+	if (err) {
+		dev_err(dev, "IIO device registering failed (%d)\n", err);
+		return err;
+	}
 
-static struct isa_driver stx104_driver = {
-	.probe = stx104_probe,
-	.driver = {
-		.name = "stx104"
+	stx104gpio->chip.label = dev_name(dev);
+	stx104gpio->chip.parent = dev;
+	stx104gpio->chip.owner = THIS_MODULE;
+	stx104gpio->chip.base = -1;
+	stx104gpio->chip.ngpio = 8;
+	stx104gpio->chip.get_direction = stx104_gpio_get_direction;
+	stx104gpio->chip.direction_input = stx104_gpio_direction_input;
+	stx104gpio->chip.direction_output = stx104_gpio_direction_output;
+	stx104gpio->chip.get = stx104_gpio_get;
+	stx104gpio->chip.set = stx104_gpio_set;
+	stx104gpio->base = base[id] + 3;
+	stx104gpio->out_state = 0x0;
+
+	spin_lock_init(&stx104gpio->lock);
+
+	dev_set_drvdata(dev, stx104gpio);
+
+	err = gpiochip_add_data(&stx104gpio->chip, stx104gpio);
+	if (err) {
+		dev_err(dev, "GPIO registering failed (%d)\n", err);
+		return err;
 	}
-};
 
-static void __exit stx104_exit(void)
-{
-	isa_unregister_driver(&stx104_driver);
+	return 0;
 }
 
-static int __init stx104_init(void)
+static int stx104_remove(struct device *dev, unsigned int id)
 {
-	return isa_register_driver(&stx104_driver, num_stx104);
+	struct stx104_gpio *const stx104gpio = dev_get_drvdata(dev);
+
+	gpiochip_remove(&stx104gpio->chip);
+
+	return 0;
 }
 
-module_init(stx104_init);
-module_exit(stx104_exit);
+static struct isa_driver stx104_driver = {
+	.probe = stx104_probe,
+	.driver = {
+		.name = "stx104"
+	},
+	.remove = stx104_remove
+};
+
+module_isa_driver(stx104_driver, num_stx104);
 
 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
 MODULE_DESCRIPTION("Apex Embedded Systems STX104 DAC driver");
diff --git a/drivers/iio/dummy/Kconfig b/drivers/iio/dummy/Kconfig
index 71805ce..aa5824d 100644
--- a/drivers/iio/dummy/Kconfig
+++ b/drivers/iio/dummy/Kconfig
@@ -10,6 +10,7 @@ config IIO_DUMMY_EVGEN
 
 config IIO_SIMPLE_DUMMY
        tristate "An example driver with no hardware requirements"
+       depends on IIO_SW_DEVICE
        help
 	 Driver intended mainly as documentation for how to write
 	 a driver. May also be useful for testing userspace code
diff --git a/drivers/iio/dummy/iio_simple_dummy.c b/drivers/iio/dummy/iio_simple_dummy.c
index 43fe4ba..ad3410e 100644
--- a/drivers/iio/dummy/iio_simple_dummy.c
+++ b/drivers/iio/dummy/iio_simple_dummy.c
@@ -17,26 +17,18 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/string.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/events.h>
 #include <linux/iio/buffer.h>
+#include <linux/iio/sw_device.h>
 #include "iio_simple_dummy.h"
 
-/*
- * A few elements needed to fake a bus for this driver
- * Note instances parameter controls how many of these
- * dummy devices are registered.
- */
-static unsigned instances = 1;
-module_param(instances, uint, 0);
-
-/* Pointer array used to fake bus elements */
-static struct iio_dev **iio_dummy_devs;
-
-/* Fake a name for the part number, usually obtained from the id table */
-static const char *iio_dummy_part_number = "iio_dummy_part_no";
+static struct config_item_type iio_dummy_type = {
+	.ct_owner = THIS_MODULE,
+};
 
 /**
  * struct iio_dummy_accel_calibscale - realworld to register mapping
@@ -572,12 +564,18 @@ static int iio_dummy_init_device(struct iio_dev *indio_dev)
  *                      const struct i2c_device_id *id)
  * SPI: iio_dummy_probe(struct spi_device *spi)
  */
-static int iio_dummy_probe(int index)
+static struct iio_sw_device *iio_dummy_probe(const char *name)
 {
 	int ret;
 	struct iio_dev *indio_dev;
 	struct iio_dummy_state *st;
+	struct iio_sw_device *swd;
 
+	swd = kzalloc(sizeof(*swd), GFP_KERNEL);
+	if (!swd) {
+		ret = -ENOMEM;
+		goto error_kzalloc;
+	}
 	/*
 	 * Allocate an IIO device.
 	 *
@@ -608,7 +606,7 @@ static int iio_dummy_probe(int index)
 	 * i2c_set_clientdata(client, indio_dev);
 	 * spi_set_drvdata(spi, indio_dev);
 	 */
-	iio_dummy_devs[index] = indio_dev;
+	swd->device = indio_dev;
 
 	/*
 	 * Set the device name.
@@ -619,7 +617,7 @@ static int iio_dummy_probe(int index)
 	 *    indio_dev->name = id->name;
 	 *    indio_dev->name = spi_get_device_id(spi)->name;
 	 */
-	indio_dev->name = iio_dummy_part_number;
+	indio_dev->name = kstrdup(name, GFP_KERNEL);
 
 	/* Provide description of available channels */
 	indio_dev->channels = iio_dummy_channels;
@@ -646,7 +644,9 @@ static int iio_dummy_probe(int index)
 	if (ret < 0)
 		goto error_unconfigure_buffer;
 
-	return 0;
+	iio_swd_group_init_type_name(swd, name, &iio_dummy_type);
+
+	return swd;
 error_unconfigure_buffer:
 	iio_simple_dummy_unconfigure_buffer(indio_dev);
 error_unregister_events:
@@ -654,16 +654,18 @@ error_unregister_events:
 error_free_device:
 	iio_device_free(indio_dev);
 error_ret:
-	return ret;
+	kfree(swd);
+error_kzalloc:
+	return ERR_PTR(ret);
 }
 
 /**
  * iio_dummy_remove() - device instance removal function
- * @index: device index.
+ * @swd: pointer to software IIO device abstraction
  *
  * Parameters follow those of iio_dummy_probe for buses.
  */
-static void iio_dummy_remove(int index)
+static int iio_dummy_remove(struct iio_sw_device *swd)
 {
 	/*
 	 * Get a pointer to the device instance iio_dev structure
@@ -671,7 +673,7 @@ static void iio_dummy_remove(int index)
 	 * struct iio_dev *indio_dev = i2c_get_clientdata(client);
 	 * struct iio_dev *indio_dev = spi_get_drvdata(spi);
 	 */
-	struct iio_dev *indio_dev = iio_dummy_devs[index];
+	struct iio_dev *indio_dev = swd->device;
 
 	/* Unregister the device */
 	iio_device_unregister(indio_dev);
@@ -684,11 +686,13 @@ static void iio_dummy_remove(int index)
 	iio_simple_dummy_events_unregister(indio_dev);
 
 	/* Free all structures */
+	kfree(indio_dev->name);
 	iio_device_free(indio_dev);
-}
 
+	return 0;
+}
 /**
- * iio_dummy_init() -  device driver registration
+ * module_iio_sw_device_driver() -  device driver registration
  *
  * Varies depending on bus type of the device. As there is no device
  * here, call probe directly. For information on device registration
@@ -697,50 +701,18 @@ static void iio_dummy_remove(int index)
  * spi:
  * Documentation/spi/spi-summary
  */
-static __init int iio_dummy_init(void)
-{
-	int i, ret;
-
-	if (instances > 10) {
-		instances = 1;
-		return -EINVAL;
-	}
-
-	/* Fake a bus */
-	iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs),
-				 GFP_KERNEL);
-	/* Here we have no actual device so call probe */
-	for (i = 0; i < instances; i++) {
-		ret = iio_dummy_probe(i);
-		if (ret < 0)
-			goto error_remove_devs;
-	}
-	return 0;
-
-error_remove_devs:
-	while (i--)
-		iio_dummy_remove(i);
-
-	kfree(iio_dummy_devs);
-	return ret;
-}
-module_init(iio_dummy_init);
+static const struct iio_sw_device_ops iio_dummy_device_ops = {
+	.probe = iio_dummy_probe,
+	.remove = iio_dummy_remove,
+};
 
-/**
- * iio_dummy_exit() - device driver removal
- *
- * Varies depending on bus type of the device.
- * As there is no device here, call remove directly.
- */
-static __exit void iio_dummy_exit(void)
-{
-	int i;
+static struct iio_sw_device_type iio_dummy_device = {
+	.name = "dummy",
+	.owner = THIS_MODULE,
+	.ops = &iio_dummy_device_ops,
+};
 
-	for (i = 0; i < instances; i++)
-		iio_dummy_remove(i);
-	kfree(iio_dummy_devs);
-}
-module_exit(iio_dummy_exit);
+module_iio_sw_device_driver(iio_dummy_device);
 
 MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
 MODULE_DESCRIPTION("IIO dummy driver");
diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c
index cf44a6f..b383892 100644
--- a/drivers/iio/dummy/iio_simple_dummy_buffer.c
+++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c
@@ -85,7 +85,8 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
 		}
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, data, iio_get_time_ns());
+	iio_push_to_buffers_with_timestamp(indio_dev, data,
+					   iio_get_time_ns(indio_dev));
 
 	kfree(data);
 
diff --git a/drivers/iio/dummy/iio_simple_dummy_events.c b/drivers/iio/dummy/iio_simple_dummy_events.c
index 6eb600f..ed63ffd 100644
--- a/drivers/iio/dummy/iio_simple_dummy_events.c
+++ b/drivers/iio/dummy/iio_simple_dummy_events.c
@@ -158,7 +158,7 @@ static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private)
 	struct iio_dev *indio_dev = private;
 	struct iio_dummy_state *st = iio_priv(indio_dev);
 
-	st->event_timestamp = iio_get_time_ns();
+	st->event_timestamp = iio_get_time_ns(indio_dev);
 	return IRQ_WAKE_THREAD;
 }
 
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 44a30f2..99eba52 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -284,7 +284,7 @@ struct ad9523_state {
 	} data[2] ____cacheline_aligned;
 };
 
-static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
+static int ad9523_read(struct iio_dev *indio_dev, unsigned int addr)
 {
 	struct ad9523_state *st = iio_priv(indio_dev);
 	int ret;
@@ -318,7 +318,8 @@ static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
 	return ret;
 };
 
-static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val)
+static int ad9523_write(struct iio_dev *indio_dev,
+		unsigned int addr, unsigned int val)
 {
 	struct ad9523_state *st = iio_priv(indio_dev);
 	int ret;
@@ -351,11 +352,11 @@ static int ad9523_io_update(struct iio_dev *indio_dev)
 }
 
 static int ad9523_vco_out_map(struct iio_dev *indio_dev,
-			      unsigned ch, unsigned out)
+			      unsigned int ch, unsigned int out)
 {
 	struct ad9523_state *st = iio_priv(indio_dev);
 	int ret;
-	unsigned mask;
+	unsigned int mask;
 
 	switch (ch) {
 	case 0 ... 3:
@@ -405,7 +406,7 @@ static int ad9523_vco_out_map(struct iio_dev *indio_dev,
 }
 
 static int ad9523_set_clock_provider(struct iio_dev *indio_dev,
-			      unsigned ch, unsigned long freq)
+			      unsigned int ch, unsigned long freq)
 {
 	struct ad9523_state *st = iio_priv(indio_dev);
 	long tmp1, tmp2;
@@ -619,7 +620,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,
 			   long m)
 {
 	struct ad9523_state *st = iio_priv(indio_dev);
-	unsigned code;
+	unsigned int code;
 	int ret;
 
 	mutex_lock(&indio_dev->mlock);
@@ -655,7 +656,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,
 			    long mask)
 {
 	struct ad9523_state *st = iio_priv(indio_dev);
-	unsigned reg;
+	unsigned int reg;
 	int ret, tmp, code;
 
 	mutex_lock(&indio_dev->mlock);
@@ -709,8 +710,8 @@ out:
 }
 
 static int ad9523_reg_access(struct iio_dev *indio_dev,
-			      unsigned reg, unsigned writeval,
-			      unsigned *readval)
+			      unsigned int reg, unsigned int writeval,
+			      unsigned int *readval)
 {
 	int ret;
 
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index e816d29..205a844 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -93,7 +93,7 @@ config IIO_ST_GYRO_3AXIS
 	select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
 	help
 	  Say yes here to build support for STMicroelectronics gyroscopes:
-	  L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330.
+	  L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330, LSM9DS0.
 
 	  This driver can also be built as a module. If so, these modules
 	  will be created:
diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c
index 4dac567..f7fcfa8 100644
--- a/drivers/iio/gyro/bmg160_core.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/iio/iio.h>
@@ -31,7 +30,6 @@
 #include "bmg160.h"
 
 #define BMG160_IRQ_NAME		"bmg160_event"
-#define BMG160_GPIO_NAME		"gpio_int"
 
 #define BMG160_REG_CHIP_ID		0x00
 #define BMG160_CHIP_ID_VAL		0x0F
@@ -52,6 +50,7 @@
 #define BMG160_REG_PMU_BW		0x10
 #define BMG160_NO_FILTER		0
 #define BMG160_DEF_BW			100
+#define BMG160_REG_PMU_BW_RES		BIT(7)
 
 #define BMG160_REG_INT_MAP_0		0x17
 #define BMG160_INT_MAP_0_BIT_ANY	BIT(1)
@@ -97,13 +96,11 @@
 #define BMG160_AUTO_SUSPEND_DELAY_MS	2000
 
 struct bmg160_data {
-	struct device *dev;
 	struct regmap *regmap;
 	struct iio_trigger *dready_trig;
 	struct iio_trigger *motion_trig;
 	struct mutex mutex;
 	s16 buffer[8];
-	u8 bw_bits;
 	u32 dps_range;
 	int ev_enable_state;
 	int slope_thres;
@@ -116,16 +113,20 @@ enum bmg160_axis {
 	AXIS_X,
 	AXIS_Y,
 	AXIS_Z,
+	AXIS_MAX,
 };
 
 static const struct {
-	int val;
+	int odr;
+	int filter;
 	int bw_bits;
-} bmg160_samp_freq_table[] = { {100, 0x07},
-			       {200, 0x06},
-			       {400, 0x03},
-			       {1000, 0x02},
-			       {2000, 0x01} };
+} bmg160_samp_freq_table[] = { {100, 32, 0x07},
+			       {200, 64, 0x06},
+			       {100, 12, 0x05},
+			       {200, 23, 0x04},
+			       {400, 47, 0x03},
+			       {1000, 116, 0x02},
+			       {2000, 230, 0x01} };
 
 static const struct {
 	int scale;
@@ -138,11 +139,12 @@ static const struct {
 
 static int bmg160_set_mode(struct bmg160_data *data, u8 mode)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 
 	ret = regmap_write(data->regmap, BMG160_REG_PMU_LPW, mode);
 	if (ret < 0) {
-		dev_err(data->dev, "Error writing reg_pmu_lpw\n");
+		dev_err(dev, "Error writing reg_pmu_lpw\n");
 		return ret;
 	}
 
@@ -154,7 +156,7 @@ static int bmg160_convert_freq_to_bit(int val)
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) {
-		if (bmg160_samp_freq_table[i].val == val)
+		if (bmg160_samp_freq_table[i].odr == val)
 			return bmg160_samp_freq_table[i].bw_bits;
 	}
 
@@ -163,6 +165,7 @@ static int bmg160_convert_freq_to_bit(int val)
 
 static int bmg160_set_bw(struct bmg160_data *data, int val)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 	int bw_bits;
 
@@ -172,29 +175,76 @@ static int bmg160_set_bw(struct bmg160_data *data, int val)
 
 	ret = regmap_write(data->regmap, BMG160_REG_PMU_BW, bw_bits);
 	if (ret < 0) {
-		dev_err(data->dev, "Error writing reg_pmu_bw\n");
+		dev_err(dev, "Error writing reg_pmu_bw\n");
 		return ret;
 	}
 
-	data->bw_bits = bw_bits;
+	return 0;
+}
+
+static int bmg160_get_filter(struct bmg160_data *data, int *val)
+{
+	struct device *dev = regmap_get_device(data->regmap);
+	int ret;
+	int i;
+	unsigned int bw_bits;
+
+	ret = regmap_read(data->regmap, BMG160_REG_PMU_BW, &bw_bits);
+	if (ret < 0) {
+		dev_err(dev, "Error reading reg_pmu_bw\n");
+		return ret;
+	}
+
+	/* Ignore the readonly reserved bit. */
+	bw_bits &= ~BMG160_REG_PMU_BW_RES;
+
+	for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) {
+		if (bmg160_samp_freq_table[i].bw_bits == bw_bits)
+			break;
+	}
+
+	*val = bmg160_samp_freq_table[i].filter;
+
+	return ret ? ret : IIO_VAL_INT;
+}
+
+
+static int bmg160_set_filter(struct bmg160_data *data, int val)
+{
+	struct device *dev = regmap_get_device(data->regmap);
+	int ret;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) {
+		if (bmg160_samp_freq_table[i].filter == val)
+			break;
+	}
+
+	ret = regmap_write(data->regmap, BMG160_REG_PMU_BW,
+			   bmg160_samp_freq_table[i].bw_bits);
+	if (ret < 0) {
+		dev_err(dev, "Error writing reg_pmu_bw\n");
+		return ret;
+	}
 
 	return 0;
 }
 
 static int bmg160_chip_init(struct bmg160_data *data)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 	unsigned int val;
 
 	ret = regmap_read(data->regmap, BMG160_REG_CHIP_ID, &val);
 	if (ret < 0) {
-		dev_err(data->dev, "Error reading reg_chip_id\n");
+		dev_err(dev, "Error reading reg_chip_id\n");
 		return ret;
 	}
 
-	dev_dbg(data->dev, "Chip Id %x\n", val);
+	dev_dbg(dev, "Chip Id %x\n", val);
 	if (val != BMG160_CHIP_ID_VAL) {
-		dev_err(data->dev, "invalid chip %x\n", val);
+		dev_err(dev, "invalid chip %x\n", val);
 		return -ENODEV;
 	}
 
@@ -213,14 +263,14 @@ static int bmg160_chip_init(struct bmg160_data *data)
 	/* Set Default Range */
 	ret = regmap_write(data->regmap, BMG160_REG_RANGE, BMG160_RANGE_500DPS);
 	if (ret < 0) {
-		dev_err(data->dev, "Error writing reg_range\n");
+		dev_err(dev, "Error writing reg_range\n");
 		return ret;
 	}
 	data->dps_range = BMG160_RANGE_500DPS;
 
 	ret = regmap_read(data->regmap, BMG160_REG_SLOPE_THRES, &val);
 	if (ret < 0) {
-		dev_err(data->dev, "Error reading reg_slope_thres\n");
+		dev_err(dev, "Error reading reg_slope_thres\n");
 		return ret;
 	}
 	data->slope_thres = val;
@@ -229,7 +279,7 @@ static int bmg160_chip_init(struct bmg160_data *data)
 	ret = regmap_update_bits(data->regmap, BMG160_REG_INT_EN_1,
 				 BMG160_INT1_BIT_OD, 0);
 	if (ret < 0) {
-		dev_err(data->dev, "Error updating bits in reg_int_en_1\n");
+		dev_err(dev, "Error updating bits in reg_int_en_1\n");
 		return ret;
 	}
 
@@ -237,7 +287,7 @@ static int bmg160_chip_init(struct bmg160_data *data)
 			   BMG160_INT_MODE_LATCH_INT |
 			   BMG160_INT_MODE_LATCH_RESET);
 	if (ret < 0) {
-		dev_err(data->dev,
+		dev_err(dev,
 			"Error writing reg_motion_intr\n");
 		return ret;
 	}
@@ -248,20 +298,21 @@ static int bmg160_chip_init(struct bmg160_data *data)
 static int bmg160_set_power_state(struct bmg160_data *data, bool on)
 {
 #ifdef CONFIG_PM
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 
 	if (on)
-		ret = pm_runtime_get_sync(data->dev);
+		ret = pm_runtime_get_sync(dev);
 	else {
-		pm_runtime_mark_last_busy(data->dev);
-		ret = pm_runtime_put_autosuspend(data->dev);
+		pm_runtime_mark_last_busy(dev);
+		ret = pm_runtime_put_autosuspend(dev);
 	}
 
 	if (ret < 0) {
-		dev_err(data->dev,
-			"Failed: bmg160_set_power_state for %d\n", on);
+		dev_err(dev, "Failed: bmg160_set_power_state for %d\n", on);
+
 		if (on)
-			pm_runtime_put_noidle(data->dev);
+			pm_runtime_put_noidle(dev);
 
 		return ret;
 	}
@@ -273,6 +324,7 @@ static int bmg160_set_power_state(struct bmg160_data *data, bool on)
 static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
 					     bool status)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 
 	/* Enable/Disable INT_MAP0 mapping */
@@ -280,7 +332,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
 				 BMG160_INT_MAP_0_BIT_ANY,
 				 (status ? BMG160_INT_MAP_0_BIT_ANY : 0));
 	if (ret < 0) {
-		dev_err(data->dev, "Error updating bits reg_int_map0\n");
+		dev_err(dev, "Error updating bits reg_int_map0\n");
 		return ret;
 	}
 
@@ -290,8 +342,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
 		ret = regmap_write(data->regmap, BMG160_REG_SLOPE_THRES,
 				   data->slope_thres);
 		if (ret < 0) {
-			dev_err(data->dev,
-				"Error writing reg_slope_thres\n");
+			dev_err(dev, "Error writing reg_slope_thres\n");
 			return ret;
 		}
 
@@ -299,8 +350,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
 				   BMG160_INT_MOTION_X | BMG160_INT_MOTION_Y |
 				   BMG160_INT_MOTION_Z);
 		if (ret < 0) {
-			dev_err(data->dev,
-				"Error writing reg_motion_intr\n");
+			dev_err(dev, "Error writing reg_motion_intr\n");
 			return ret;
 		}
 
@@ -315,8 +365,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
 					   BMG160_INT_MODE_LATCH_INT |
 					   BMG160_INT_MODE_LATCH_RESET);
 			if (ret < 0) {
-				dev_err(data->dev,
-					"Error writing reg_rst_latch\n");
+				dev_err(dev, "Error writing reg_rst_latch\n");
 				return ret;
 			}
 		}
@@ -329,7 +378,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
 	}
 
 	if (ret < 0) {
-		dev_err(data->dev, "Error writing reg_int_en0\n");
+		dev_err(dev, "Error writing reg_int_en0\n");
 		return ret;
 	}
 
@@ -339,6 +388,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
 static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
 					   bool status)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 
 	/* Enable/Disable INT_MAP1 mapping */
@@ -346,7 +396,7 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
 				 BMG160_INT_MAP_1_BIT_NEW_DATA,
 				 (status ? BMG160_INT_MAP_1_BIT_NEW_DATA : 0));
 	if (ret < 0) {
-		dev_err(data->dev, "Error updating bits in reg_int_map1\n");
+		dev_err(dev, "Error updating bits in reg_int_map1\n");
 		return ret;
 	}
 
@@ -355,9 +405,8 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
 				   BMG160_INT_MODE_NON_LATCH_INT |
 				   BMG160_INT_MODE_LATCH_RESET);
 		if (ret < 0) {
-			dev_err(data->dev,
-				"Error writing reg_rst_latch\n");
-				return ret;
+			dev_err(dev, "Error writing reg_rst_latch\n");
+			return ret;
 		}
 
 		ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0,
@@ -369,16 +418,15 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
 				   BMG160_INT_MODE_LATCH_INT |
 				   BMG160_INT_MODE_LATCH_RESET);
 		if (ret < 0) {
-			dev_err(data->dev,
-				"Error writing reg_rst_latch\n");
-				return ret;
+			dev_err(dev, "Error writing reg_rst_latch\n");
+			return ret;
 		}
 
 		ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, 0);
 	}
 
 	if (ret < 0) {
-		dev_err(data->dev, "Error writing reg_int_en0\n");
+		dev_err(dev, "Error writing reg_int_en0\n");
 		return ret;
 	}
 
@@ -387,11 +435,23 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
 
 static int bmg160_get_bw(struct bmg160_data *data, int *val)
 {
+	struct device *dev = regmap_get_device(data->regmap);	
 	int i;
+	unsigned int bw_bits;
+	int ret;
+
+	ret = regmap_read(data->regmap, BMG160_REG_PMU_BW, &bw_bits);
+	if (ret < 0) {
+		dev_err(dev, "Error reading reg_pmu_bw\n");
+		return ret;
+	}
+
+	/* Ignore the readonly reserved bit. */
+	bw_bits &= ~BMG160_REG_PMU_BW_RES;
 
 	for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) {
-		if (bmg160_samp_freq_table[i].bw_bits == data->bw_bits) {
-			*val = bmg160_samp_freq_table[i].val;
+		if (bmg160_samp_freq_table[i].bw_bits == bw_bits) {
+			*val = bmg160_samp_freq_table[i].odr;
 			return IIO_VAL_INT;
 		}
 	}
@@ -401,6 +461,7 @@ static int bmg160_get_bw(struct bmg160_data *data, int *val)
 
 static int bmg160_set_scale(struct bmg160_data *data, int val)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret, i;
 
 	for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) {
@@ -408,8 +469,7 @@ static int bmg160_set_scale(struct bmg160_data *data, int val)
 			ret = regmap_write(data->regmap, BMG160_REG_RANGE,
 					   bmg160_scale_table[i].dps_range);
 			if (ret < 0) {
-				dev_err(data->dev,
-					"Error writing reg_range\n");
+				dev_err(dev, "Error writing reg_range\n");
 				return ret;
 			}
 			data->dps_range = bmg160_scale_table[i].dps_range;
@@ -422,6 +482,7 @@ static int bmg160_set_scale(struct bmg160_data *data, int val)
 
 static int bmg160_get_temp(struct bmg160_data *data, int *val)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 	unsigned int raw_val;
 
@@ -434,7 +495,7 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val)
 
 	ret = regmap_read(data->regmap, BMG160_REG_TEMP, &raw_val);
 	if (ret < 0) {
-		dev_err(data->dev, "Error reading reg_temp\n");
+		dev_err(dev, "Error reading reg_temp\n");
 		bmg160_set_power_state(data, false);
 		mutex_unlock(&data->mutex);
 		return ret;
@@ -451,6 +512,7 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val)
 
 static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
 {
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 	__le16 raw_val;
 
@@ -464,7 +526,7 @@ static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
 	ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(axis), &raw_val,
 			       sizeof(raw_val));
 	if (ret < 0) {
-		dev_err(data->dev, "Error reading axis %d\n", axis);
+		dev_err(dev, "Error reading axis %d\n", axis);
 		bmg160_set_power_state(data, false);
 		mutex_unlock(&data->mutex);
 		return ret;
@@ -506,6 +568,8 @@ static int bmg160_read_raw(struct iio_dev *indio_dev,
 			return IIO_VAL_INT;
 		} else
 			return -EINVAL;
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		return bmg160_get_filter(data, val);
 	case IIO_CHAN_INFO_SCALE:
 		*val = 0;
 		switch (chan->type) {
@@ -570,6 +634,26 @@ static int bmg160_write_raw(struct iio_dev *indio_dev,
 		ret = bmg160_set_power_state(data, false);
 		mutex_unlock(&data->mutex);
 		return ret;
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		if (val2)
+			return -EINVAL;
+
+		mutex_lock(&data->mutex);
+		ret = bmg160_set_power_state(data, true);
+		if (ret < 0) {
+			bmg160_set_power_state(data, false);
+			mutex_unlock(&data->mutex);
+			return ret;
+		}
+		ret = bmg160_set_filter(data, val);
+		if (ret < 0) {
+			bmg160_set_power_state(data, false);
+			mutex_unlock(&data->mutex);
+			return ret;
+		}
+		ret = bmg160_set_power_state(data, false);
+		mutex_unlock(&data->mutex);
+		return ret;
 	case IIO_CHAN_INFO_SCALE:
 		if (val)
 			return -EINVAL;
@@ -727,7 +811,8 @@ static const struct iio_event_spec bmg160_event = {
 	.channel2 = IIO_MOD_##_axis,					\
 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\
 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |		\
-				    BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ) |				\
+		BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),	\
 	.scan_index = AXIS_##_axis,					\
 	.scan_type = {							\
 		.sign = 's',						\
@@ -764,26 +849,23 @@ static const struct iio_info bmg160_info = {
 	.driver_module		= THIS_MODULE,
 };
 
+static const unsigned long bmg160_accel_scan_masks[] = {
+					BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
+					0};
+
 static irqreturn_t bmg160_trigger_handler(int irq, void *p)
 {
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct bmg160_data *data = iio_priv(indio_dev);
-	int bit, ret, i = 0;
-	unsigned int val;
+	int ret;
 
 	mutex_lock(&data->mutex);
-	for_each_set_bit(bit, indio_dev->active_scan_mask,
-			 indio_dev->masklength) {
-		ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(bit),
-				       &val, 2);
-		if (ret < 0) {
-			mutex_unlock(&data->mutex);
-			goto err;
-		}
-		data->buffer[i++] = val;
-	}
+	ret = regmap_bulk_read(data->regmap, BMG160_REG_XOUT_L,
+			       data->buffer, AXIS_MAX * 2);
 	mutex_unlock(&data->mutex);
+	if (ret < 0)
+		goto err;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
 					   pf->timestamp);
@@ -797,6 +879,7 @@ static int bmg160_trig_try_reen(struct iio_trigger *trig)
 {
 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
 	struct bmg160_data *data = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 
 	/* new data interrupts don't need ack */
@@ -808,7 +891,7 @@ static int bmg160_trig_try_reen(struct iio_trigger *trig)
 			   BMG160_INT_MODE_LATCH_INT |
 			   BMG160_INT_MODE_LATCH_RESET);
 	if (ret < 0) {
-		dev_err(data->dev, "Error writing reg_rst_latch\n");
+		dev_err(dev, "Error writing reg_rst_latch\n");
 		return ret;
 	}
 
@@ -868,13 +951,14 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
 {
 	struct iio_dev *indio_dev = private;
 	struct bmg160_data *data = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(data->regmap);
 	int ret;
 	int dir;
 	unsigned int val;
 
 	ret = regmap_read(data->regmap, BMG160_REG_INT_STATUS_2, &val);
 	if (ret < 0) {
-		dev_err(data->dev, "Error reading reg_int_status2\n");
+		dev_err(dev, "Error reading reg_int_status2\n");
 		goto ack_intr_status;
 	}
 
@@ -885,25 +969,25 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
 
 	if (val & BMG160_ANY_MOTION_BIT_X)
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
-							0,
-							IIO_MOD_X,
-							IIO_EV_TYPE_ROC,
-							dir),
-							iio_get_time_ns());
+							     0,
+							     IIO_MOD_X,
+							     IIO_EV_TYPE_ROC,
+							     dir),
+			       iio_get_time_ns(indio_dev));
 	if (val & BMG160_ANY_MOTION_BIT_Y)
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
-							0,
-							IIO_MOD_Y,
-							IIO_EV_TYPE_ROC,
-							dir),
-							iio_get_time_ns());
+							     0,
+							     IIO_MOD_Y,
+							     IIO_EV_TYPE_ROC,
+							     dir),
+			       iio_get_time_ns(indio_dev));
 	if (val & BMG160_ANY_MOTION_BIT_Z)
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
-							0,
-							IIO_MOD_Z,
-							IIO_EV_TYPE_ROC,
-							dir),
-							iio_get_time_ns());
+							     0,
+							     IIO_MOD_Z,
+							     IIO_EV_TYPE_ROC,
+							     dir),
+			       iio_get_time_ns(indio_dev));
 
 ack_intr_status:
 	if (!data->dready_trigger_on) {
@@ -911,8 +995,7 @@ ack_intr_status:
 				   BMG160_INT_MODE_LATCH_INT |
 				   BMG160_INT_MODE_LATCH_RESET);
 		if (ret < 0)
-			dev_err(data->dev,
-				"Error writing reg_rst_latch\n");
+			dev_err(dev, "Error writing reg_rst_latch\n");
 	}
 
 	return IRQ_HANDLED;
@@ -956,29 +1039,6 @@ static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = {
 	.postdisable = bmg160_buffer_postdisable,
 };
 
-static int bmg160_gpio_probe(struct bmg160_data *data)
-
-{
-	struct device *dev;
-	struct gpio_desc *gpio;
-
-	dev = data->dev;
-
-	/* data ready gpio interrupt pin */
-	gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0, GPIOD_IN);
-	if (IS_ERR(gpio)) {
-		dev_err(dev, "acpi gpio get index failed\n");
-		return PTR_ERR(gpio);
-	}
-
-	data->irq = gpiod_to_irq(gpio);
-
-	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio),
-		data->irq);
-
-	return 0;
-}
-
 static const char *bmg160_match_acpi_device(struct device *dev)
 {
 	const struct acpi_device_id *id;
@@ -1003,7 +1063,6 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
 
 	data = iio_priv(indio_dev);
 	dev_set_drvdata(dev, indio_dev);
-	data->dev = dev;
 	data->irq = irq;
 	data->regmap = regmap;
 
@@ -1020,12 +1079,10 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
 	indio_dev->channels = bmg160_channels;
 	indio_dev->num_channels = ARRAY_SIZE(bmg160_channels);
 	indio_dev->name = name;
+	indio_dev->available_scan_masks = bmg160_accel_scan_masks;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &bmg160_info;
 
-	if (data->irq <= 0)
-		bmg160_gpio_probe(data);
-
 	if (data->irq > 0) {
 		ret = devm_request_threaded_irq(dev,
 						data->irq,
@@ -1168,7 +1225,7 @@ static int bmg160_runtime_suspend(struct device *dev)
 
 	ret = bmg160_set_mode(data, BMG160_MODE_SUSPEND);
 	if (ret < 0) {
-		dev_err(data->dev, "set mode failed\n");
+		dev_err(dev, "set mode failed\n");
 		return -EAGAIN;
 	}
 
diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h
index 5353d63..a5c5c4e 100644
--- a/drivers/iio/gyro/st_gyro.h
+++ b/drivers/iio/gyro/st_gyro.h
@@ -21,6 +21,7 @@
 #define L3GD20_GYRO_DEV_NAME		"l3gd20"
 #define L3G4IS_GYRO_DEV_NAME		"l3g4is_ui"
 #define LSM330_GYRO_DEV_NAME		"lsm330_gyro"
+#define LSM9DS0_GYRO_DEV_NAME		"lsm9ds0_gyro"
 
 /**
  * struct st_sensors_platform_data - gyro platform data
diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c
index d67b17b..a537704 100644
--- a/drivers/iio/gyro/st_gyro_buffer.c
+++ b/drivers/iio/gyro/st_gyro_buffer.c
@@ -91,7 +91,7 @@ static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = {
 
 int st_gyro_allocate_ring(struct iio_dev *indio_dev)
 {
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+	return iio_triggered_buffer_setup(indio_dev, NULL,
 		&st_sensors_trigger_handler, &st_gyro_buffer_setup_ops);
 }
 
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index 110f95b..aea034d 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -190,6 +190,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
 			 * drain settings, but only for INT1 and not
 			 * for the DRDY line on INT2.
 			 */
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_GYRO_1_MULTIREAD_BIT,
 		.bootime = 2,
@@ -203,6 +204,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
 			[2] = LSM330DLC_GYRO_DEV_NAME,
 			[3] = L3G4IS_GYRO_DEV_NAME,
 			[4] = LSM330_GYRO_DEV_NAME,
+			[5] = LSM9DS0_GYRO_DEV_NAME,
 		},
 		.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
 		.odr = {
@@ -258,6 +260,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
 			 * drain settings, but only for INT1 and not
 			 * for the DRDY line on INT2.
 			 */
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
 		.bootime = 2,
@@ -322,6 +325,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
 			 * drain settings, but only for INT1 and not
 			 * for the DRDY line on INT2.
 			 */
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_GYRO_3_MULTIREAD_BIT,
 		.bootime = 2,
@@ -405,6 +409,7 @@ static const struct iio_info gyro_info = {
 static const struct iio_trigger_ops st_gyro_trigger_ops = {
 	.owner = THIS_MODULE,
 	.set_trigger_state = ST_GYRO_TRIGGER_SET_STATE,
+	.validate_device = st_sensors_validate_device,
 };
 #define ST_GYRO_TRIGGER_OPS (&st_gyro_trigger_ops)
 #else
@@ -421,13 +426,15 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
 	indio_dev->info = &gyro_info;
 	mutex_init(&gdata->tb.buf_lock);
 
-	st_sensors_power_enable(indio_dev);
+	err = st_sensors_power_enable(indio_dev);
+	if (err)
+		return err;
 
 	err = st_sensors_check_device_support(indio_dev,
 					ARRAY_SIZE(st_gyro_sensors_settings),
 					st_gyro_sensors_settings);
 	if (err < 0)
-		return err;
+		goto st_gyro_power_off;
 
 	gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS;
 	gdata->multiread_bit = gdata->sensor_settings->multi_read_bit;
@@ -441,11 +448,11 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
 	err = st_sensors_init_sensor(indio_dev,
 				(struct st_sensors_platform_data *)&gyro_pdata);
 	if (err < 0)
-		return err;
+		goto st_gyro_power_off;
 
 	err = st_gyro_allocate_ring(indio_dev);
 	if (err < 0)
-		return err;
+		goto st_gyro_power_off;
 
 	if (irq > 0) {
 		err = st_sensors_allocate_trigger(indio_dev,
@@ -468,6 +475,8 @@ st_gyro_device_register_error:
 		st_sensors_deallocate_trigger(indio_dev);
 st_gyro_probe_trigger_error:
 	st_gyro_deallocate_ring(indio_dev);
+st_gyro_power_off:
+	st_sensors_power_disable(indio_dev);
 
 	return err;
 }
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index 6848451..40056b8 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -48,6 +48,10 @@ static const struct of_device_id st_gyro_of_match[] = {
 		.compatible = "st,lsm330-gyro",
 		.data = LSM330_GYRO_DEV_NAME,
 	},
+	{
+		.compatible = "st,lsm9ds0-gyro",
+		.data = LSM9DS0_GYRO_DEV_NAME,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, st_gyro_of_match);
@@ -93,6 +97,7 @@ static const struct i2c_device_id st_gyro_id_table[] = {
 	{ L3GD20_GYRO_DEV_NAME },
 	{ L3G4IS_GYRO_DEV_NAME },
 	{ LSM330_GYRO_DEV_NAME },
+	{ LSM9DS0_GYRO_DEV_NAME },
 	{},
 };
 MODULE_DEVICE_TABLE(i2c, st_gyro_id_table);
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index d2b7a5f..fbf2fae 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -54,6 +54,7 @@ static const struct spi_device_id st_gyro_id_table[] = {
 	{ L3GD20_GYRO_DEV_NAME },
 	{ L3G4IS_GYRO_DEV_NAME },
 	{ LSM330_GYRO_DEV_NAME },
+	{ LSM9DS0_GYRO_DEV_NAME },
 	{},
 };
 MODULE_DEVICE_TABLE(spi, st_gyro_id_table);
diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c
index 88e43f8..9a08146 100644
--- a/drivers/iio/health/afe4403.c
+++ b/drivers/iio/health/afe4403.c
@@ -1,7 +1,7 @@
 /*
  * AFE4403 Heart Rate Monitors and Low-Cost Pulse Oximeters
  *
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
  *	Andrew F. Davis <afd@ti.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -39,127 +39,90 @@
 #define AFE4403_TIAGAIN			0x20
 #define AFE4403_TIA_AMB_GAIN		0x21
 
-/* AFE4403 GAIN register fields */
-#define AFE4403_TIAGAIN_RES_MASK	GENMASK(2, 0)
-#define AFE4403_TIAGAIN_RES_SHIFT	0
-#define AFE4403_TIAGAIN_CAP_MASK	GENMASK(7, 3)
-#define AFE4403_TIAGAIN_CAP_SHIFT	3
-
-/* AFE4403 LEDCNTRL register fields */
-#define AFE440X_LEDCNTRL_LED1_MASK		GENMASK(15, 8)
-#define AFE440X_LEDCNTRL_LED1_SHIFT		8
-#define AFE440X_LEDCNTRL_LED2_MASK		GENMASK(7, 0)
-#define AFE440X_LEDCNTRL_LED2_SHIFT		0
-#define AFE440X_LEDCNTRL_LED_RANGE_MASK		GENMASK(17, 16)
-#define AFE440X_LEDCNTRL_LED_RANGE_SHIFT	16
-
-/* AFE4403 CONTROL2 register fields */
-#define AFE440X_CONTROL2_PWR_DWN_TX	BIT(2)
-#define AFE440X_CONTROL2_EN_SLOW_DIAG	BIT(8)
-#define AFE440X_CONTROL2_DIAG_OUT_TRI	BIT(10)
-#define AFE440X_CONTROL2_TX_BRDG_MOD	BIT(11)
-#define AFE440X_CONTROL2_TX_REF_MASK	GENMASK(18, 17)
-#define AFE440X_CONTROL2_TX_REF_SHIFT	17
-
-/* AFE4404 NULL fields */
-#define NULL_MASK	0
-#define NULL_SHIFT	0
-
-/* AFE4403 LEDCNTRL values */
-#define AFE440X_LEDCNTRL_RANGE_TX_HALF	0x1
-#define AFE440X_LEDCNTRL_RANGE_TX_FULL	0x2
-#define AFE440X_LEDCNTRL_RANGE_TX_OFF	0x3
-
-/* AFE4403 CONTROL2 values */
-#define AFE440X_CONTROL2_TX_REF_025	0x0
-#define AFE440X_CONTROL2_TX_REF_050	0x1
-#define AFE440X_CONTROL2_TX_REF_100	0x2
-#define AFE440X_CONTROL2_TX_REF_075	0x3
-
-/* AFE4403 CONTROL3 values */
-#define AFE440X_CONTROL3_CLK_DIV_2	0x0
-#define AFE440X_CONTROL3_CLK_DIV_4	0x2
-#define AFE440X_CONTROL3_CLK_DIV_6	0x3
-#define AFE440X_CONTROL3_CLK_DIV_8	0x4
-#define AFE440X_CONTROL3_CLK_DIV_12	0x5
-#define AFE440X_CONTROL3_CLK_DIV_1	0x7
-
-/* AFE4403 TIAGAIN_CAP values */
-#define AFE4403_TIAGAIN_CAP_5_P		0x0
-#define AFE4403_TIAGAIN_CAP_10_P	0x1
-#define AFE4403_TIAGAIN_CAP_20_P	0x2
-#define AFE4403_TIAGAIN_CAP_30_P	0x3
-#define AFE4403_TIAGAIN_CAP_55_P	0x8
-#define AFE4403_TIAGAIN_CAP_155_P	0x10
-
-/* AFE4403 TIAGAIN_RES values */
-#define AFE4403_TIAGAIN_RES_500_K	0x0
-#define AFE4403_TIAGAIN_RES_250_K	0x1
-#define AFE4403_TIAGAIN_RES_100_K	0x2
-#define AFE4403_TIAGAIN_RES_50_K	0x3
-#define AFE4403_TIAGAIN_RES_25_K	0x4
-#define AFE4403_TIAGAIN_RES_10_K	0x5
-#define AFE4403_TIAGAIN_RES_1_M		0x6
-#define AFE4403_TIAGAIN_RES_NONE	0x7
+enum afe4403_fields {
+	/* Gains */
+	F_RF_LED1, F_CF_LED1,
+	F_RF_LED, F_CF_LED,
+
+	/* LED Current */
+	F_ILED1, F_ILED2,
+
+	/* sentinel */
+	F_MAX_FIELDS
+};
+
+static const struct reg_field afe4403_reg_fields[] = {
+	/* Gains */
+	[F_RF_LED1]	= REG_FIELD(AFE4403_TIAGAIN, 0, 2),
+	[F_CF_LED1]	= REG_FIELD(AFE4403_TIAGAIN, 3, 7),
+	[F_RF_LED]	= REG_FIELD(AFE4403_TIA_AMB_GAIN, 0, 2),
+	[F_CF_LED]	= REG_FIELD(AFE4403_TIA_AMB_GAIN, 3, 7),
+	/* LED Current */
+	[F_ILED1]	= REG_FIELD(AFE440X_LEDCNTRL, 0, 7),
+	[F_ILED2]	= REG_FIELD(AFE440X_LEDCNTRL, 8, 15),
+};
 
 /**
- * struct afe4403_data
- * @dev - Device structure
- * @spi - SPI device handle
- * @regmap - Register map of the device
- * @regulator - Pointer to the regulator for the IC
- * @trig - IIO trigger for this device
- * @irq - ADC_RDY line interrupt number
+ * struct afe4403_data - AFE4403 device instance data
+ * @dev: Device structure
+ * @spi: SPI device handle
+ * @regmap: Register map of the device
+ * @fields: Register fields of the device
+ * @regulator: Pointer to the regulator for the IC
+ * @trig: IIO trigger for this device
+ * @irq: ADC_RDY line interrupt number
  */
 struct afe4403_data {
 	struct device *dev;
 	struct spi_device *spi;
 	struct regmap *regmap;
+	struct regmap_field *fields[F_MAX_FIELDS];
 	struct regulator *regulator;
 	struct iio_trigger *trig;
 	int irq;
 };
 
 enum afe4403_chan_id {
+	LED2 = 1,
+	ALED2,
 	LED1,
 	ALED1,
-	LED2,
-	ALED2,
-	LED1_ALED1,
 	LED2_ALED2,
-	ILED1,
-	ILED2,
+	LED1_ALED1,
 };
 
-static const struct afe440x_reg_info afe4403_reg_info[] = {
-	[LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, 0, NULL),
-	[ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, 0, NULL),
-	[LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, 0, NULL),
-	[ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, 0, NULL),
-	[LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL),
-	[LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL),
-	[ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE440X_LEDCNTRL_LED1),
-	[ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE440X_LEDCNTRL_LED2),
+static const unsigned int afe4403_channel_values[] = {
+	[LED2] = AFE440X_LED2VAL,
+	[ALED2] = AFE440X_ALED2VAL,
+	[LED1] = AFE440X_LED1VAL,
+	[ALED1] = AFE440X_ALED1VAL,
+	[LED2_ALED2] = AFE440X_LED2_ALED2VAL,
+	[LED1_ALED1] = AFE440X_LED1_ALED1VAL,
+};
+
+static const unsigned int afe4403_channel_leds[] = {
+	[LED2] = F_ILED2,
+	[LED1] = F_ILED1,
 };
 
 static const struct iio_chan_spec afe4403_channels[] = {
 	/* ADC values */
-	AFE440X_INTENSITY_CHAN(LED1, "led1", 0),
-	AFE440X_INTENSITY_CHAN(ALED1, "led1_ambient", 0),
-	AFE440X_INTENSITY_CHAN(LED2, "led2", 0),
-	AFE440X_INTENSITY_CHAN(ALED2, "led2_ambient", 0),
-	AFE440X_INTENSITY_CHAN(LED1_ALED1, "led1-led1_ambient", 0),
-	AFE440X_INTENSITY_CHAN(LED2_ALED2, "led2-led2_ambient", 0),
+	AFE440X_INTENSITY_CHAN(LED2, 0),
+	AFE440X_INTENSITY_CHAN(ALED2, 0),
+	AFE440X_INTENSITY_CHAN(LED1, 0),
+	AFE440X_INTENSITY_CHAN(ALED1, 0),
+	AFE440X_INTENSITY_CHAN(LED2_ALED2, 0),
+	AFE440X_INTENSITY_CHAN(LED1_ALED1, 0),
 	/* LED current */
-	AFE440X_CURRENT_CHAN(ILED1, "led1"),
-	AFE440X_CURRENT_CHAN(ILED2, "led2"),
+	AFE440X_CURRENT_CHAN(LED2),
+	AFE440X_CURRENT_CHAN(LED1),
 };
 
 static const struct afe440x_val_table afe4403_res_table[] = {
 	{ 500000 }, { 250000 }, { 100000 }, { 50000 },
 	{ 25000 }, { 10000 }, { 1000000 }, { 0 },
 };
-AFE440X_TABLE_ATTR(tia_resistance_available, afe4403_res_table);
+AFE440X_TABLE_ATTR(in_intensity_resistance_available, afe4403_res_table);
 
 static const struct afe440x_val_table afe4403_cap_table[] = {
 	{ 0, 5000 }, { 0, 10000 }, { 0, 20000 }, { 0, 25000 },
@@ -171,7 +134,7 @@ static const struct afe440x_val_table afe4403_cap_table[] = {
 	{ 0, 205000 }, { 0, 210000 }, { 0, 220000 }, { 0, 225000 },
 	{ 0, 230000 }, { 0, 235000 }, { 0, 245000 }, { 0, 250000 },
 };
-AFE440X_TABLE_ATTR(tia_capacitance_available, afe4403_cap_table);
+AFE440X_TABLE_ATTR(in_intensity_capacitance_available, afe4403_cap_table);
 
 static ssize_t afe440x_show_register(struct device *dev,
 				     struct device_attribute *attr,
@@ -180,38 +143,21 @@ static ssize_t afe440x_show_register(struct device *dev,
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct afe4403_data *afe = iio_priv(indio_dev);
 	struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr);
-	unsigned int reg_val, type;
+	unsigned int reg_val;
 	int vals[2];
-	int ret, val_len;
+	int ret;
 
-	ret = regmap_read(afe->regmap, afe440x_attr->reg, &reg_val);
+	ret = regmap_field_read(afe->fields[afe440x_attr->field], &reg_val);
 	if (ret)
 		return ret;
 
-	reg_val &= afe440x_attr->mask;
-	reg_val >>= afe440x_attr->shift;
-
-	switch (afe440x_attr->type) {
-	case SIMPLE:
-		type = IIO_VAL_INT;
-		val_len = 1;
-		vals[0] = reg_val;
-		break;
-	case RESISTANCE:
-	case CAPACITANCE:
-		type = IIO_VAL_INT_PLUS_MICRO;
-		val_len = 2;
-		if (reg_val < afe440x_attr->table_size) {
-			vals[0] = afe440x_attr->val_table[reg_val].integer;
-			vals[1] = afe440x_attr->val_table[reg_val].fract;
-			break;
-		}
-		return -EINVAL;
-	default:
+	if (reg_val >= afe440x_attr->table_size)
 		return -EINVAL;
-	}
 
-	return iio_format_value(buf, type, val_len, vals);
+	vals[0] = afe440x_attr->val_table[reg_val].integer;
+	vals[1] = afe440x_attr->val_table[reg_val].fract;
+
+	return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, vals);
 }
 
 static ssize_t afe440x_store_register(struct device *dev,
@@ -227,48 +173,43 @@ static ssize_t afe440x_store_register(struct device *dev,
 	if (ret)
 		return ret;
 
-	switch (afe440x_attr->type) {
-	case SIMPLE:
-		val = integer;
-		break;
-	case RESISTANCE:
-	case CAPACITANCE:
-		for (val = 0; val < afe440x_attr->table_size; val++)
-			if (afe440x_attr->val_table[val].integer == integer &&
-			    afe440x_attr->val_table[val].fract == fract)
-				break;
-		if (val == afe440x_attr->table_size)
-			return -EINVAL;
-		break;
-	default:
+	for (val = 0; val < afe440x_attr->table_size; val++)
+		if (afe440x_attr->val_table[val].integer == integer &&
+		    afe440x_attr->val_table[val].fract == fract)
+			break;
+	if (val == afe440x_attr->table_size)
 		return -EINVAL;
-	}
 
-	ret = regmap_update_bits(afe->regmap, afe440x_attr->reg,
-				 afe440x_attr->mask,
-				 (val << afe440x_attr->shift));
+	ret = regmap_field_write(afe->fields[afe440x_attr->field], val);
 	if (ret)
 		return ret;
 
 	return count;
 }
 
-static AFE440X_ATTR(tia_separate_en, AFE4403_TIAGAIN, AFE440X_TIAGAIN_ENSEPGAIN, SIMPLE, NULL, 0);
+static AFE440X_ATTR(in_intensity1_resistance, F_RF_LED, afe4403_res_table);
+static AFE440X_ATTR(in_intensity1_capacitance, F_CF_LED, afe4403_cap_table);
+
+static AFE440X_ATTR(in_intensity2_resistance, F_RF_LED, afe4403_res_table);
+static AFE440X_ATTR(in_intensity2_capacitance, F_CF_LED, afe4403_cap_table);
 
-static AFE440X_ATTR(tia_resistance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_RES, RESISTANCE, afe4403_res_table, ARRAY_SIZE(afe4403_res_table));
-static AFE440X_ATTR(tia_capacitance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_CAP, CAPACITANCE, afe4403_cap_table, ARRAY_SIZE(afe4403_cap_table));
+static AFE440X_ATTR(in_intensity3_resistance, F_RF_LED1, afe4403_res_table);
+static AFE440X_ATTR(in_intensity3_capacitance, F_CF_LED1, afe4403_cap_table);
 
-static AFE440X_ATTR(tia_resistance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, RESISTANCE, afe4403_res_table, ARRAY_SIZE(afe4403_res_table));
-static AFE440X_ATTR(tia_capacitance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, CAPACITANCE, afe4403_cap_table, ARRAY_SIZE(afe4403_cap_table));
+static AFE440X_ATTR(in_intensity4_resistance, F_RF_LED1, afe4403_res_table);
+static AFE440X_ATTR(in_intensity4_capacitance, F_CF_LED1, afe4403_cap_table);
 
 static struct attribute *afe440x_attributes[] = {
-	&afe440x_attr_tia_separate_en.dev_attr.attr,
-	&afe440x_attr_tia_resistance1.dev_attr.attr,
-	&afe440x_attr_tia_capacitance1.dev_attr.attr,
-	&afe440x_attr_tia_resistance2.dev_attr.attr,
-	&afe440x_attr_tia_capacitance2.dev_attr.attr,
-	&dev_attr_tia_resistance_available.attr,
-	&dev_attr_tia_capacitance_available.attr,
+	&dev_attr_in_intensity_resistance_available.attr,
+	&dev_attr_in_intensity_capacitance_available.attr,
+	&afe440x_attr_in_intensity1_resistance.dev_attr.attr,
+	&afe440x_attr_in_intensity1_capacitance.dev_attr.attr,
+	&afe440x_attr_in_intensity2_resistance.dev_attr.attr,
+	&afe440x_attr_in_intensity2_capacitance.dev_attr.attr,
+	&afe440x_attr_in_intensity3_resistance.dev_attr.attr,
+	&afe440x_attr_in_intensity3_capacitance.dev_attr.attr,
+	&afe440x_attr_in_intensity4_resistance.dev_attr.attr,
+	&afe440x_attr_in_intensity4_capacitance.dev_attr.attr,
 	NULL
 };
 
@@ -309,35 +250,26 @@ static int afe4403_read_raw(struct iio_dev *indio_dev,
 			    int *val, int *val2, long mask)
 {
 	struct afe4403_data *afe = iio_priv(indio_dev);
-	const struct afe440x_reg_info reg_info = afe4403_reg_info[chan->address];
+	unsigned int reg = afe4403_channel_values[chan->address];
+	unsigned int field = afe4403_channel_leds[chan->address];
 	int ret;
 
 	switch (chan->type) {
 	case IIO_INTENSITY:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
-			ret = afe4403_read(afe, reg_info.reg, val);
-			if (ret)
-				return ret;
-			return IIO_VAL_INT;
-		case IIO_CHAN_INFO_OFFSET:
-			ret = regmap_read(afe->regmap, reg_info.offreg,
-					  val);
+			ret = afe4403_read(afe, reg, val);
 			if (ret)
 				return ret;
-			*val &= reg_info.mask;
-			*val >>= reg_info.shift;
 			return IIO_VAL_INT;
 		}
 		break;
 	case IIO_CURRENT:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
-			ret = regmap_read(afe->regmap, reg_info.reg, val);
+			ret = regmap_field_read(afe->fields[field], val);
 			if (ret)
 				return ret;
-			*val &= reg_info.mask;
-			*val >>= reg_info.shift;
 			return IIO_VAL_INT;
 		case IIO_CHAN_INFO_SCALE:
 			*val = 0;
@@ -357,25 +289,13 @@ static int afe4403_write_raw(struct iio_dev *indio_dev,
 			     int val, int val2, long mask)
 {
 	struct afe4403_data *afe = iio_priv(indio_dev);
-	const struct afe440x_reg_info reg_info = afe4403_reg_info[chan->address];
+	unsigned int field = afe4403_channel_leds[chan->address];
 
 	switch (chan->type) {
-	case IIO_INTENSITY:
-		switch (mask) {
-		case IIO_CHAN_INFO_OFFSET:
-			return regmap_update_bits(afe->regmap,
-				reg_info.offreg,
-				reg_info.mask,
-				(val << reg_info.shift));
-		}
-		break;
 	case IIO_CURRENT:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
-			return regmap_update_bits(afe->regmap,
-				reg_info.reg,
-				reg_info.mask,
-				(val << reg_info.shift));
+			return regmap_field_write(afe->fields[field], val);
 		}
 		break;
 	default:
@@ -410,7 +330,7 @@ static irqreturn_t afe4403_trigger_handler(int irq, void *private)
 	for_each_set_bit(bit, indio_dev->active_scan_mask,
 			 indio_dev->masklength) {
 		ret = spi_write_then_read(afe->spi,
-					  &afe4403_reg_info[bit].reg, 1,
+					  &afe4403_channel_values[bit], 1,
 					  rx, 3);
 		if (ret)
 			goto err;
@@ -472,12 +392,8 @@ static const struct iio_trigger_ops afe4403_trigger_ops = {
 
 static const struct reg_sequence afe4403_reg_sequences[] = {
 	AFE4403_TIMING_PAIRS,
-	{ AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN | 0x000007},
-	{ AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES_1_M },
-	{ AFE440X_LEDCNTRL, (0x14 << AFE440X_LEDCNTRL_LED1_SHIFT) |
-			    (0x14 << AFE440X_LEDCNTRL_LED2_SHIFT) },
-	{ AFE440X_CONTROL2, AFE440X_CONTROL2_TX_REF_050 <<
-			    AFE440X_CONTROL2_TX_REF_SHIFT },
+	{ AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN },
+	{ AFE4403_TIAGAIN, AFE440X_TIAGAIN_ENSEPGAIN },
 };
 
 static const struct regmap_range afe4403_yes_ranges[] = {
@@ -498,13 +414,11 @@ static const struct regmap_config afe4403_regmap_config = {
 	.volatile_table = &afe4403_volatile_table,
 };
 
-#ifdef CONFIG_OF
 static const struct of_device_id afe4403_of_match[] = {
 	{ .compatible = "ti,afe4403", },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, afe4403_of_match);
-#endif
 
 static int __maybe_unused afe4403_suspend(struct device *dev)
 {
@@ -553,7 +467,7 @@ static int afe4403_probe(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev;
 	struct afe4403_data *afe;
-	int ret;
+	int i, ret;
 
 	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*afe));
 	if (!indio_dev)
@@ -572,6 +486,15 @@ static int afe4403_probe(struct spi_device *spi)
 		return PTR_ERR(afe->regmap);
 	}
 
+	for (i = 0; i < F_MAX_FIELDS; i++) {
+		afe->fields[i] = devm_regmap_field_alloc(afe->dev, afe->regmap,
+							 afe4403_reg_fields[i]);
+		if (IS_ERR(afe->fields[i])) {
+			dev_err(afe->dev, "Unable to allocate regmap fields\n");
+			return PTR_ERR(afe->fields[i]);
+		}
+	}
+
 	afe->regulator = devm_regulator_get(afe->dev, "tx_sup");
 	if (IS_ERR(afe->regulator)) {
 		dev_err(afe->dev, "Unable to get regulator\n");
@@ -694,7 +617,7 @@ MODULE_DEVICE_TABLE(spi, afe4403_ids);
 static struct spi_driver afe4403_spi_driver = {
 	.driver = {
 		.name = AFE4403_DRIVER_NAME,
-		.of_match_table = of_match_ptr(afe4403_of_match),
+		.of_match_table = afe4403_of_match,
 		.pm = &afe4403_pm_ops,
 	},
 	.probe = afe4403_probe,
@@ -704,5 +627,5 @@ static struct spi_driver afe4403_spi_driver = {
 module_spi_driver(afe4403_spi_driver);
 
 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
-MODULE_DESCRIPTION("TI AFE4403 Heart Rate and Pulse Oximeter");
+MODULE_DESCRIPTION("TI AFE4403 Heart Rate Monitor and Pulse Oximeter AFE");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
index 5096a46..4526640 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -1,7 +1,7 @@
 /*
  * AFE4404 Heart Rate Monitors and Low-Cost Pulse Oximeters
  *
- * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
  *	Andrew F. Davis <afd@ti.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -48,118 +48,102 @@
 #define AFE4404_AVG_LED2_ALED2VAL	0x3f
 #define AFE4404_AVG_LED1_ALED1VAL	0x40
 
-/* AFE4404 GAIN register fields */
-#define AFE4404_TIA_GAIN_RES_MASK	GENMASK(2, 0)
-#define AFE4404_TIA_GAIN_RES_SHIFT	0
-#define AFE4404_TIA_GAIN_CAP_MASK	GENMASK(5, 3)
-#define AFE4404_TIA_GAIN_CAP_SHIFT	3
+/* AFE4404 CONTROL2 register fields */
+#define AFE440X_CONTROL2_OSC_ENABLE	BIT(9)
 
-/* AFE4404 LEDCNTRL register fields */
-#define AFE4404_LEDCNTRL_ILED1_MASK	GENMASK(5, 0)
-#define AFE4404_LEDCNTRL_ILED1_SHIFT	0
-#define AFE4404_LEDCNTRL_ILED2_MASK	GENMASK(11, 6)
-#define AFE4404_LEDCNTRL_ILED2_SHIFT	6
-#define AFE4404_LEDCNTRL_ILED3_MASK	GENMASK(17, 12)
-#define AFE4404_LEDCNTRL_ILED3_SHIFT	12
+enum afe4404_fields {
+	/* Gains */
+	F_TIA_GAIN_SEP, F_TIA_CF_SEP,
+	F_TIA_GAIN, TIA_CF,
 
-/* AFE4404 CONTROL2 register fields */
-#define AFE440X_CONTROL2_ILED_2X_MASK	BIT(17)
-#define AFE440X_CONTROL2_ILED_2X_SHIFT	17
-
-/* AFE4404 CONTROL3 register fields */
-#define AFE440X_CONTROL3_OSC_ENABLE	BIT(9)
-
-/* AFE4404 OFFDAC register current fields */
-#define AFE4404_OFFDAC_CURR_LED1_MASK	GENMASK(9, 5)
-#define AFE4404_OFFDAC_CURR_LED1_SHIFT	5
-#define AFE4404_OFFDAC_CURR_LED2_MASK	GENMASK(19, 15)
-#define AFE4404_OFFDAC_CURR_LED2_SHIFT	15
-#define AFE4404_OFFDAC_CURR_LED3_MASK	GENMASK(4, 0)
-#define AFE4404_OFFDAC_CURR_LED3_SHIFT	0
-#define AFE4404_OFFDAC_CURR_ALED1_MASK	GENMASK(14, 10)
-#define AFE4404_OFFDAC_CURR_ALED1_SHIFT	10
-#define AFE4404_OFFDAC_CURR_ALED2_MASK	GENMASK(4, 0)
-#define AFE4404_OFFDAC_CURR_ALED2_SHIFT	0
-
-/* AFE4404 NULL fields */
-#define NULL_MASK	0
-#define NULL_SHIFT	0
-
-/* AFE4404 TIA_GAIN_CAP values */
-#define AFE4404_TIA_GAIN_CAP_5_P	0x0
-#define AFE4404_TIA_GAIN_CAP_2_5_P	0x1
-#define AFE4404_TIA_GAIN_CAP_10_P	0x2
-#define AFE4404_TIA_GAIN_CAP_7_5_P	0x3
-#define AFE4404_TIA_GAIN_CAP_20_P	0x4
-#define AFE4404_TIA_GAIN_CAP_17_5_P	0x5
-#define AFE4404_TIA_GAIN_CAP_25_P	0x6
-#define AFE4404_TIA_GAIN_CAP_22_5_P	0x7
-
-/* AFE4404 TIA_GAIN_RES values */
-#define AFE4404_TIA_GAIN_RES_500_K	0x0
-#define AFE4404_TIA_GAIN_RES_250_K	0x1
-#define AFE4404_TIA_GAIN_RES_100_K	0x2
-#define AFE4404_TIA_GAIN_RES_50_K	0x3
-#define AFE4404_TIA_GAIN_RES_25_K	0x4
-#define AFE4404_TIA_GAIN_RES_10_K	0x5
-#define AFE4404_TIA_GAIN_RES_1_M	0x6
-#define AFE4404_TIA_GAIN_RES_2_M	0x7
+	/* LED Current */
+	F_ILED1, F_ILED2, F_ILED3,
+
+	/* Offset DAC */
+	F_OFFDAC_AMB2, F_OFFDAC_LED1, F_OFFDAC_AMB1, F_OFFDAC_LED2,
+
+	/* sentinel */
+	F_MAX_FIELDS
+};
+
+static const struct reg_field afe4404_reg_fields[] = {
+	/* Gains */
+	[F_TIA_GAIN_SEP]	= REG_FIELD(AFE4404_TIA_GAIN_SEP, 0, 2),
+	[F_TIA_CF_SEP]		= REG_FIELD(AFE4404_TIA_GAIN_SEP, 3, 5),
+	[F_TIA_GAIN]		= REG_FIELD(AFE4404_TIA_GAIN, 0, 2),
+	[TIA_CF]		= REG_FIELD(AFE4404_TIA_GAIN, 3, 5),
+	/* LED Current */
+	[F_ILED1]		= REG_FIELD(AFE440X_LEDCNTRL, 0, 5),
+	[F_ILED2]		= REG_FIELD(AFE440X_LEDCNTRL, 6, 11),
+	[F_ILED3]		= REG_FIELD(AFE440X_LEDCNTRL, 12, 17),
+	/* Offset DAC */
+	[F_OFFDAC_AMB2]		= REG_FIELD(AFE4404_OFFDAC, 0, 4),
+	[F_OFFDAC_LED1]		= REG_FIELD(AFE4404_OFFDAC, 5, 9),
+	[F_OFFDAC_AMB1]		= REG_FIELD(AFE4404_OFFDAC, 10, 14),
+	[F_OFFDAC_LED2]		= REG_FIELD(AFE4404_OFFDAC, 15, 19),
+};
 
 /**
- * struct afe4404_data
- * @dev - Device structure
- * @regmap - Register map of the device
- * @regulator - Pointer to the regulator for the IC
- * @trig - IIO trigger for this device
- * @irq - ADC_RDY line interrupt number
+ * struct afe4404_data - AFE4404 device instance data
+ * @dev: Device structure
+ * @regmap: Register map of the device
+ * @fields: Register fields of the device
+ * @regulator: Pointer to the regulator for the IC
+ * @trig: IIO trigger for this device
+ * @irq: ADC_RDY line interrupt number
  */
 struct afe4404_data {
 	struct device *dev;
 	struct regmap *regmap;
+	struct regmap_field *fields[F_MAX_FIELDS];
 	struct regulator *regulator;
 	struct iio_trigger *trig;
 	int irq;
 };
 
 enum afe4404_chan_id {
+	LED2 = 1,
+	ALED2,
 	LED1,
 	ALED1,
-	LED2,
-	ALED2,
-	LED3,
-	LED1_ALED1,
 	LED2_ALED2,
-	ILED1,
-	ILED2,
-	ILED3,
+	LED1_ALED1,
+};
+
+static const unsigned int afe4404_channel_values[] = {
+	[LED2] = AFE440X_LED2VAL,
+	[ALED2] = AFE440X_ALED2VAL,
+	[LED1] = AFE440X_LED1VAL,
+	[ALED1] = AFE440X_ALED1VAL,
+	[LED2_ALED2] = AFE440X_LED2_ALED2VAL,
+	[LED1_ALED1] = AFE440X_LED1_ALED1VAL,
 };
 
-static const struct afe440x_reg_info afe4404_reg_info[] = {
-	[LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED1),
-	[ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED1),
-	[LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED2),
-	[ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED2),
-	[LED3] = AFE440X_REG_INFO(AFE440X_ALED2VAL, 0, NULL),
-	[LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL),
-	[LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL),
-	[ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED1),
-	[ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED2),
-	[ILED3] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED3),
+static const unsigned int afe4404_channel_leds[] = {
+	[LED2] = F_ILED2,
+	[ALED2] = F_ILED3,
+	[LED1] = F_ILED1,
+};
+
+static const unsigned int afe4404_channel_offdacs[] = {
+	[LED2] = F_OFFDAC_LED2,
+	[ALED2] = F_OFFDAC_AMB2,
+	[LED1] = F_OFFDAC_LED1,
+	[ALED1] = F_OFFDAC_AMB1,
 };
 
 static const struct iio_chan_spec afe4404_channels[] = {
 	/* ADC values */
-	AFE440X_INTENSITY_CHAN(LED1, "led1", BIT(IIO_CHAN_INFO_OFFSET)),
-	AFE440X_INTENSITY_CHAN(ALED1, "led1_ambient", BIT(IIO_CHAN_INFO_OFFSET)),
-	AFE440X_INTENSITY_CHAN(LED2, "led2", BIT(IIO_CHAN_INFO_OFFSET)),
-	AFE440X_INTENSITY_CHAN(ALED2, "led2_ambient", BIT(IIO_CHAN_INFO_OFFSET)),
-	AFE440X_INTENSITY_CHAN(LED3, "led3", BIT(IIO_CHAN_INFO_OFFSET)),
-	AFE440X_INTENSITY_CHAN(LED1_ALED1, "led1-led1_ambient", 0),
-	AFE440X_INTENSITY_CHAN(LED2_ALED2, "led2-led2_ambient", 0),
+	AFE440X_INTENSITY_CHAN(LED2, BIT(IIO_CHAN_INFO_OFFSET)),
+	AFE440X_INTENSITY_CHAN(ALED2, BIT(IIO_CHAN_INFO_OFFSET)),
+	AFE440X_INTENSITY_CHAN(LED1, BIT(IIO_CHAN_INFO_OFFSET)),
+	AFE440X_INTENSITY_CHAN(ALED1, BIT(IIO_CHAN_INFO_OFFSET)),
+	AFE440X_INTENSITY_CHAN(LED2_ALED2, 0),
+	AFE440X_INTENSITY_CHAN(LED1_ALED1, 0),
 	/* LED current */
-	AFE440X_CURRENT_CHAN(ILED1, "led1"),
-	AFE440X_CURRENT_CHAN(ILED2, "led2"),
-	AFE440X_CURRENT_CHAN(ILED3, "led3"),
+	AFE440X_CURRENT_CHAN(LED2),
+	AFE440X_CURRENT_CHAN(ALED2),
+	AFE440X_CURRENT_CHAN(LED1),
 };
 
 static const struct afe440x_val_table afe4404_res_table[] = {
@@ -172,7 +156,7 @@ static const struct afe440x_val_table afe4404_res_table[] = {
 	{ .integer = 1000000, .fract = 0 },
 	{ .integer = 2000000, .fract = 0 },
 };
-AFE440X_TABLE_ATTR(tia_resistance_available, afe4404_res_table);
+AFE440X_TABLE_ATTR(in_intensity_resistance_available, afe4404_res_table);
 
 static const struct afe440x_val_table afe4404_cap_table[] = {
 	{ .integer = 0, .fract = 5000 },
@@ -184,7 +168,7 @@ static const struct afe440x_val_table afe4404_cap_table[] = {
 	{ .integer = 0, .fract = 25000 },
 	{ .integer = 0, .fract = 22500 },
 };
-AFE440X_TABLE_ATTR(tia_capacitance_available, afe4404_cap_table);
+AFE440X_TABLE_ATTR(in_intensity_capacitance_available, afe4404_cap_table);
 
 static ssize_t afe440x_show_register(struct device *dev,
 				     struct device_attribute *attr,
@@ -193,38 +177,21 @@ static ssize_t afe440x_show_register(struct device *dev,
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct afe4404_data *afe = iio_priv(indio_dev);
 	struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr);
-	unsigned int reg_val, type;
+	unsigned int reg_val;
 	int vals[2];
-	int ret, val_len;
+	int ret;
 
-	ret = regmap_read(afe->regmap, afe440x_attr->reg, &reg_val);
+	ret = regmap_field_read(afe->fields[afe440x_attr->field], &reg_val);
 	if (ret)
 		return ret;
 
-	reg_val &= afe440x_attr->mask;
-	reg_val >>= afe440x_attr->shift;
-
-	switch (afe440x_attr->type) {
-	case SIMPLE:
-		type = IIO_VAL_INT;
-		val_len = 1;
-		vals[0] = reg_val;
-		break;
-	case RESISTANCE:
-	case CAPACITANCE:
-		type = IIO_VAL_INT_PLUS_MICRO;
-		val_len = 2;
-		if (reg_val < afe440x_attr->table_size) {
-			vals[0] = afe440x_attr->val_table[reg_val].integer;
-			vals[1] = afe440x_attr->val_table[reg_val].fract;
-			break;
-		}
-		return -EINVAL;
-	default:
+	if (reg_val >= afe440x_attr->table_size)
 		return -EINVAL;
-	}
 
-	return iio_format_value(buf, type, val_len, vals);
+	vals[0] = afe440x_attr->val_table[reg_val].integer;
+	vals[1] = afe440x_attr->val_table[reg_val].fract;
+
+	return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, vals);
 }
 
 static ssize_t afe440x_store_register(struct device *dev,
@@ -240,48 +207,43 @@ static ssize_t afe440x_store_register(struct device *dev,
 	if (ret)
 		return ret;
 
-	switch (afe440x_attr->type) {
-	case SIMPLE:
-		val = integer;
-		break;
-	case RESISTANCE:
-	case CAPACITANCE:
-		for (val = 0; val < afe440x_attr->table_size; val++)
-			if (afe440x_attr->val_table[val].integer == integer &&
-			    afe440x_attr->val_table[val].fract == fract)
-				break;
-		if (val == afe440x_attr->table_size)
-			return -EINVAL;
-		break;
-	default:
+	for (val = 0; val < afe440x_attr->table_size; val++)
+		if (afe440x_attr->val_table[val].integer == integer &&
+		    afe440x_attr->val_table[val].fract == fract)
+			break;
+	if (val == afe440x_attr->table_size)
 		return -EINVAL;
-	}
 
-	ret = regmap_update_bits(afe->regmap, afe440x_attr->reg,
-				 afe440x_attr->mask,
-				 (val << afe440x_attr->shift));
+	ret = regmap_field_write(afe->fields[afe440x_attr->field], val);
 	if (ret)
 		return ret;
 
 	return count;
 }
 
-static AFE440X_ATTR(tia_separate_en, AFE4404_TIA_GAIN_SEP, AFE440X_TIAGAIN_ENSEPGAIN, SIMPLE, NULL, 0);
+static AFE440X_ATTR(in_intensity1_resistance, F_TIA_GAIN_SEP, afe4404_res_table);
+static AFE440X_ATTR(in_intensity1_capacitance, F_TIA_CF_SEP, afe4404_cap_table);
+
+static AFE440X_ATTR(in_intensity2_resistance, F_TIA_GAIN_SEP, afe4404_res_table);
+static AFE440X_ATTR(in_intensity2_capacitance, F_TIA_CF_SEP, afe4404_cap_table);
 
-static AFE440X_ATTR(tia_resistance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table));
-static AFE440X_ATTR(tia_capacitance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table));
+static AFE440X_ATTR(in_intensity3_resistance, F_TIA_GAIN, afe4404_res_table);
+static AFE440X_ATTR(in_intensity3_capacitance, TIA_CF, afe4404_cap_table);
 
-static AFE440X_ATTR(tia_resistance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table));
-static AFE440X_ATTR(tia_capacitance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table));
+static AFE440X_ATTR(in_intensity4_resistance, F_TIA_GAIN, afe4404_res_table);
+static AFE440X_ATTR(in_intensity4_capacitance, TIA_CF, afe4404_cap_table);
 
 static struct attribute *afe440x_attributes[] = {
-	&afe440x_attr_tia_separate_en.dev_attr.attr,
-	&afe440x_attr_tia_resistance1.dev_attr.attr,
-	&afe440x_attr_tia_capacitance1.dev_attr.attr,
-	&afe440x_attr_tia_resistance2.dev_attr.attr,
-	&afe440x_attr_tia_capacitance2.dev_attr.attr,
-	&dev_attr_tia_resistance_available.attr,
-	&dev_attr_tia_capacitance_available.attr,
+	&dev_attr_in_intensity_resistance_available.attr,
+	&dev_attr_in_intensity_capacitance_available.attr,
+	&afe440x_attr_in_intensity1_resistance.dev_attr.attr,
+	&afe440x_attr_in_intensity1_capacitance.dev_attr.attr,
+	&afe440x_attr_in_intensity2_resistance.dev_attr.attr,
+	&afe440x_attr_in_intensity2_capacitance.dev_attr.attr,
+	&afe440x_attr_in_intensity3_resistance.dev_attr.attr,
+	&afe440x_attr_in_intensity3_capacitance.dev_attr.attr,
+	&afe440x_attr_in_intensity4_resistance.dev_attr.attr,
+	&afe440x_attr_in_intensity4_capacitance.dev_attr.attr,
 	NULL
 };
 
@@ -294,35 +256,32 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
 			    int *val, int *val2, long mask)
 {
 	struct afe4404_data *afe = iio_priv(indio_dev);
-	const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address];
+	unsigned int value_reg = afe4404_channel_values[chan->address];
+	unsigned int led_field = afe4404_channel_leds[chan->address];
+	unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
 	int ret;
 
 	switch (chan->type) {
 	case IIO_INTENSITY:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
-			ret = regmap_read(afe->regmap, reg_info.reg, val);
+			ret = regmap_read(afe->regmap, value_reg, val);
 			if (ret)
 				return ret;
 			return IIO_VAL_INT;
 		case IIO_CHAN_INFO_OFFSET:
-			ret = regmap_read(afe->regmap, reg_info.offreg,
-					  val);
+			ret = regmap_field_read(afe->fields[offdac_field], val);
 			if (ret)
 				return ret;
-			*val &= reg_info.mask;
-			*val >>= reg_info.shift;
 			return IIO_VAL_INT;
 		}
 		break;
 	case IIO_CURRENT:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
-			ret = regmap_read(afe->regmap, reg_info.reg, val);
+			ret = regmap_field_read(afe->fields[led_field], val);
 			if (ret)
 				return ret;
-			*val &= reg_info.mask;
-			*val >>= reg_info.shift;
 			return IIO_VAL_INT;
 		case IIO_CHAN_INFO_SCALE:
 			*val = 0;
@@ -342,25 +301,20 @@ static int afe4404_write_raw(struct iio_dev *indio_dev,
 			     int val, int val2, long mask)
 {
 	struct afe4404_data *afe = iio_priv(indio_dev);
-	const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address];
+	unsigned int led_field = afe4404_channel_leds[chan->address];
+	unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
 
 	switch (chan->type) {
 	case IIO_INTENSITY:
 		switch (mask) {
 		case IIO_CHAN_INFO_OFFSET:
-			return regmap_update_bits(afe->regmap,
-				reg_info.offreg,
-				reg_info.mask,
-				(val << reg_info.shift));
+			return regmap_field_write(afe->fields[offdac_field], val);
 		}
 		break;
 	case IIO_CURRENT:
 		switch (mask) {
 		case IIO_CHAN_INFO_RAW:
-			return regmap_update_bits(afe->regmap,
-				reg_info.reg,
-				reg_info.mask,
-				(val << reg_info.shift));
+			return regmap_field_write(afe->fields[led_field], val);
 		}
 		break;
 	default:
@@ -387,7 +341,7 @@ static irqreturn_t afe4404_trigger_handler(int irq, void *private)
 
 	for_each_set_bit(bit, indio_dev->active_scan_mask,
 			 indio_dev->masklength) {
-		ret = regmap_read(afe->regmap, afe4404_reg_info[bit].reg,
+		ret = regmap_read(afe->regmap, afe4404_channel_values[bit],
 				  &buffer[i++]);
 		if (ret)
 			goto err;
@@ -443,11 +397,8 @@ static const struct iio_trigger_ops afe4404_trigger_ops = {
 static const struct reg_sequence afe4404_reg_sequences[] = {
 	AFE4404_TIMING_PAIRS,
 	{ AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN },
-	{ AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES_50_K },
-	{ AFE440X_LEDCNTRL, (0xf << AFE4404_LEDCNTRL_ILED1_SHIFT) |
-			    (0x3 << AFE4404_LEDCNTRL_ILED2_SHIFT) |
-			    (0x3 << AFE4404_LEDCNTRL_ILED3_SHIFT) },
-	{ AFE440X_CONTROL2, AFE440X_CONTROL3_OSC_ENABLE	},
+	{ AFE4404_TIA_GAIN_SEP, AFE440X_TIAGAIN_ENSEPGAIN },
+	{ AFE440X_CONTROL2, AFE440X_CONTROL2_OSC_ENABLE	},
 };
 
 static const struct regmap_range afe4404_yes_ranges[] = {
@@ -469,13 +420,11 @@ static const struct regmap_config afe4404_regmap_config = {
 	.volatile_table = &afe4404_volatile_table,
 };
 
-#ifdef CONFIG_OF
 static const struct of_device_id afe4404_of_match[] = {
 	{ .compatible = "ti,afe4404", },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, afe4404_of_match);
-#endif
 
 static int __maybe_unused afe4404_suspend(struct device *dev)
 {
@@ -525,7 +474,7 @@ static int afe4404_probe(struct i2c_client *client,
 {
 	struct iio_dev *indio_dev;
 	struct afe4404_data *afe;
-	int ret;
+	int i, ret;
 
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*afe));
 	if (!indio_dev)
@@ -543,6 +492,15 @@ static int afe4404_probe(struct i2c_client *client,
 		return PTR_ERR(afe->regmap);
 	}
 
+	for (i = 0; i < F_MAX_FIELDS; i++) {
+		afe->fields[i] = devm_regmap_field_alloc(afe->dev, afe->regmap,
+							 afe4404_reg_fields[i]);
+		if (IS_ERR(afe->fields[i])) {
+			dev_err(afe->dev, "Unable to allocate regmap fields\n");
+			return PTR_ERR(afe->fields[i]);
+		}
+	}
+
 	afe->regulator = devm_regulator_get(afe->dev, "tx_sup");
 	if (IS_ERR(afe->regulator)) {
 		dev_err(afe->dev, "Unable to get regulator\n");
@@ -665,7 +623,7 @@ MODULE_DEVICE_TABLE(i2c, afe4404_ids);
 static struct i2c_driver afe4404_i2c_driver = {
 	.driver = {
 		.name = AFE4404_DRIVER_NAME,
-		.of_match_table = of_match_ptr(afe4404_of_match),
+		.of_match_table = afe4404_of_match,
 		.pm = &afe4404_pm_ops,
 	},
 	.probe = afe4404_probe,
@@ -675,5 +633,5 @@ static struct i2c_driver afe4404_i2c_driver = {
 module_i2c_driver(afe4404_i2c_driver);
 
 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
-MODULE_DESCRIPTION("TI AFE4404 Heart Rate and Pulse Oximeter");
+MODULE_DESCRIPTION("TI AFE4404 Heart Rate Monitor and Pulse Oximeter AFE");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/health/afe440x.h b/drivers/iio/health/afe440x.h
index c671ab7..1a0f247 100644
--- a/drivers/iio/health/afe440x.h
+++ b/drivers/iio/health/afe440x.h
@@ -71,8 +71,7 @@
 #define AFE440X_CONTROL1_TIMEREN	BIT(8)
 
 /* TIAGAIN register fields */
-#define AFE440X_TIAGAIN_ENSEPGAIN_MASK	BIT(15)
-#define AFE440X_TIAGAIN_ENSEPGAIN_SHIFT	15
+#define AFE440X_TIAGAIN_ENSEPGAIN	BIT(15)
 
 /* CONTROL2 register fields */
 #define AFE440X_CONTROL2_PDN_AFE	BIT(0)
@@ -89,22 +88,7 @@
 #define AFE440X_CONTROL0_WRITE		0x0
 #define AFE440X_CONTROL0_READ		0x1
 
-struct afe440x_reg_info {
-	unsigned int reg;
-	unsigned int offreg;
-	unsigned int shift;
-	unsigned int mask;
-};
-
-#define AFE440X_REG_INFO(_reg, _offreg, _sm)			\
-	{							\
-		.reg = _reg,					\
-		.offreg = _offreg,				\
-		.shift = _sm ## _SHIFT,				\
-		.mask = _sm ## _MASK,				\
-	}
-
-#define AFE440X_INTENSITY_CHAN(_index, _name, _mask)		\
+#define AFE440X_INTENSITY_CHAN(_index, _mask)			\
 	{							\
 		.type = IIO_INTENSITY,				\
 		.channel = _index,				\
@@ -116,29 +100,23 @@ struct afe440x_reg_info {
 				.storagebits = 32,		\
 				.endianness = IIO_CPU,		\
 		},						\
-		.extend_name = _name,				\
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
 			_mask,					\
+		.indexed = true,				\
 	}
 
-#define AFE440X_CURRENT_CHAN(_index, _name)			\
+#define AFE440X_CURRENT_CHAN(_index)				\
 	{							\
 		.type = IIO_CURRENT,				\
 		.channel = _index,				\
 		.address = _index,				\
-		.scan_index = _index,				\
-		.extend_name = _name,				\
+		.scan_index = -1,				\
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
 			BIT(IIO_CHAN_INFO_SCALE),		\
+		.indexed = true,				\
 		.output = true,					\
 	}
 
-enum afe440x_reg_type {
-	SIMPLE,
-	RESISTANCE,
-	CAPACITANCE,
-};
-
 struct afe440x_val_table {
 	int integer;
 	int fract;
@@ -164,10 +142,7 @@ static DEVICE_ATTR_RO(_name)
 
 struct afe440x_attr {
 	struct device_attribute dev_attr;
-	unsigned int reg;
-	unsigned int shift;
-	unsigned int mask;
-	enum afe440x_reg_type type;
+	unsigned int field;
 	const struct afe440x_val_table *val_table;
 	unsigned int table_size;
 };
@@ -175,17 +150,14 @@ struct afe440x_attr {
 #define to_afe440x_attr(_dev_attr)				\
 	container_of(_dev_attr, struct afe440x_attr, dev_attr)
 
-#define AFE440X_ATTR(_name, _reg, _field, _type, _table, _size)	\
+#define AFE440X_ATTR(_name, _field, _table)			\
 	struct afe440x_attr afe440x_attr_##_name = {		\
 		.dev_attr = __ATTR(_name, (S_IRUGO | S_IWUSR),	\
 				   afe440x_show_register,	\
 				   afe440x_store_register),	\
-		.reg = _reg,					\
-		.shift = _field ## _SHIFT,			\
-		.mask = _field ## _MASK,			\
-		.type = _type,					\
+		.field = _field,				\
 		.val_table = _table,				\
-		.table_size = _size,				\
+		.table_size = ARRAY_SIZE(_table),		\
 	}
 
 #endif /* _AFE440X_H */
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
index 866dda1..738a86d 100644
--- a/drivers/iio/humidity/Kconfig
+++ b/drivers/iio/humidity/Kconfig
@@ -3,6 +3,16 @@
 #
 menu "Humidity sensors"
 
+config AM2315
+    tristate "Aosong AM2315 relative humidity and temperature sensor"
+    depends on I2C
+    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
diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile
index c9f089a..4a73442 100644
--- a/drivers/iio/humidity/Makefile
+++ b/drivers/iio/humidity/Makefile
@@ -2,6 +2,7 @@
 # Makefile for IIO humidity sensor drivers
 #
 
+obj-$(CONFIG_AM2315) += am2315.o
 obj-$(CONFIG_DHT11) += dht11.o
 obj-$(CONFIG_HDC100X) += hdc100x.o
 obj-$(CONFIG_HTU21) += htu21.o
diff --git b/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c
new file mode 100644
index 0000000..3e200f6
--- /dev/null
+++ b/drivers/iio/humidity/am2315.c
@@ -0,0 +1,302 @@
+/**
+ * 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 = {
+	.driver_module		= THIS_MODULE,
+	.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, NULL,
+					 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
index 20b500d..9c47bc9 100644
--- a/drivers/iio/humidity/dht11.c
+++ b/drivers/iio/humidity/dht11.c
@@ -96,6 +96,24 @@ struct dht11 {
 	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;
@@ -119,8 +137,12 @@ static int dht11_decode(struct dht11 *dht11, int offset)
 	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)
-			return -EIO;  /* lost synchronisation */
+		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;
 	}
 
@@ -130,8 +152,10 @@ static int dht11_decode(struct dht11 *dht11, int offset)
 	temp_dec = dht11_decode_byte(&bits[24]);
 	checksum = dht11_decode_byte(&bits[32]);
 
-	if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
+	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 < 20) {  /* DHT22 */
@@ -182,6 +206,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
 	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);
@@ -219,10 +244,13 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
 
 		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(&iio_dev->dev,
-				"Only %d signal edges detected\n",
-					dht11->num_edges);
+			dev_err(dht11->dev, "Only %d signal edges detected\n",
+				dht11->num_edges);
 			ret = -ETIMEDOUT;
 		}
 		if (ret < 0)
diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
index 11cbc38..0fbbd8c 100644
--- a/drivers/iio/humidity/htu21.c
+++ b/drivers/iio/humidity/htu21.c
@@ -236,6 +236,7 @@ static const struct i2c_device_id htu21_id[] = {
 	{"ms8607-humidity", MS8607},
 	{}
 };
+MODULE_DEVICE_TABLE(i2c, htu21_id);
 
 static struct i2c_driver htu21_driver = {
 	.probe = htu21_probe,
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index 3598835..4c45488 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -79,4 +79,7 @@ void iio_device_unregister_eventset(struct iio_dev *indio_dev);
 void iio_device_wakeup_eventset(struct iio_dev *indio_dev);
 int iio_event_getfd(struct iio_dev *indio_dev);
 
+struct iio_event_interface;
+bool iio_event_enabled(const struct iio_event_interface *ev_int);
+
 #endif
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 5e610f7..1f1ad41 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -25,6 +25,8 @@ config ADIS16480
 	  Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
 	  ADIS16485, ADIS16488 inertial sensors.
 
+source "drivers/iio/imu/bmi160/Kconfig"
+
 config KMX61
 	tristate "Kionix KMX61 6-axis accelerometer and magnetometer"
 	depends on I2C
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index e1e6e3d..c71bcd3 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -13,6 +13,7 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o
 adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
 obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
 
+obj-y += bmi160/
 obj-y += inv_mpu6050/
 
 obj-$(CONFIG_KMX61) += kmx61.o
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index 911255d..ad6f91d 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -324,7 +324,12 @@ static int adis_self_test(struct adis *adis)
 
 	msleep(adis->data->startup_delay);
 
-	return adis_check_status(adis);
+	ret = adis_check_status(adis);
+
+	if (adis->data->self_test_no_autoclear)
+		adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
+
+	return ret;
 }
 
 /**
diff --git b/drivers/iio/imu/bmi160/Kconfig b/drivers/iio/imu/bmi160/Kconfig
new file mode 100644
index 0000000..005c17c
--- /dev/null
+++ b/drivers/iio/imu/bmi160/Kconfig
@@ -0,0 +1,32 @@
+#
+# BMI160 IMU driver
+#
+
+config BMI160
+	tristate
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+
+config BMI160_I2C
+	tristate "Bosch BMI160 I2C driver"
+	depends on I2C
+	select BMI160
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for BMI160 IMU on I2C with
+	  accelerometer, gyroscope and external BMG160 magnetometer.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called bmi160_i2c.
+
+config BMI160_SPI
+	tristate "Bosch BMI160 SPI driver"
+	depends on SPI
+	select BMI160
+	select REGMAP_SPI
+	help
+	  If you say yes here you get support for BMI160 IMU on SPI with
+	  accelerometer, gyroscope and external BMG160 magnetometer.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called bmi160_spi.
diff --git b/drivers/iio/imu/bmi160/Makefile b/drivers/iio/imu/bmi160/Makefile
new file mode 100644
index 0000000..10365e4
--- /dev/null
+++ b/drivers/iio/imu/bmi160/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Bosch BMI160 IMU
+#
+obj-$(CONFIG_BMI160) += bmi160_core.o
+obj-$(CONFIG_BMI160_I2C) += bmi160_i2c.o
+obj-$(CONFIG_BMI160_SPI) += bmi160_spi.o
diff --git b/drivers/iio/imu/bmi160/bmi160.h b/drivers/iio/imu/bmi160/bmi160.h
new file mode 100644
index 0000000..d2ae6ed
--- /dev/null
+++ b/drivers/iio/imu/bmi160/bmi160.h
@@ -0,0 +1,10 @@
+#ifndef BMI160_H_
+#define BMI160_H_
+
+extern const struct regmap_config bmi160_regmap_config;
+
+int bmi160_core_probe(struct device *dev, struct regmap *regmap,
+		      const char *name, bool use_spi);
+void bmi160_core_remove(struct device *dev);
+
+#endif  /* BMI160_H_ */
diff --git b/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
new file mode 100644
index 0000000..e0251b8
--- /dev/null
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -0,0 +1,624 @@
+/*
+ * BMI160 - Bosch IMU (accel, gyro plus external magnetometer)
+ *
+ * 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.
+ *
+ * IIO core driver for BMI160, with support for I2C/SPI busses
+ *
+ * TODO: magnetometer, interrupts, hardware FIFO
+ */
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+
+#include "bmi160.h"
+
+#define BMI160_REG_CHIP_ID	0x00
+#define BMI160_CHIP_ID_VAL	0xD1
+
+#define BMI160_REG_PMU_STATUS	0x03
+
+/* X axis data low byte address, the rest can be obtained using axis offset */
+#define BMI160_REG_DATA_MAGN_XOUT_L	0x04
+#define BMI160_REG_DATA_GYRO_XOUT_L	0x0C
+#define BMI160_REG_DATA_ACCEL_XOUT_L	0x12
+
+#define BMI160_REG_ACCEL_CONFIG		0x40
+#define BMI160_ACCEL_CONFIG_ODR_MASK	GENMASK(3, 0)
+#define BMI160_ACCEL_CONFIG_BWP_MASK	GENMASK(6, 4)
+
+#define BMI160_REG_ACCEL_RANGE		0x41
+#define BMI160_ACCEL_RANGE_2G		0x03
+#define BMI160_ACCEL_RANGE_4G		0x05
+#define BMI160_ACCEL_RANGE_8G		0x08
+#define BMI160_ACCEL_RANGE_16G		0x0C
+
+#define BMI160_REG_GYRO_CONFIG		0x42
+#define BMI160_GYRO_CONFIG_ODR_MASK	GENMASK(3, 0)
+#define BMI160_GYRO_CONFIG_BWP_MASK	GENMASK(5, 4)
+
+#define BMI160_REG_GYRO_RANGE		0x43
+#define BMI160_GYRO_RANGE_2000DPS	0x00
+#define BMI160_GYRO_RANGE_1000DPS	0x01
+#define BMI160_GYRO_RANGE_500DPS	0x02
+#define BMI160_GYRO_RANGE_250DPS	0x03
+#define BMI160_GYRO_RANGE_125DPS	0x04
+
+#define BMI160_REG_CMD			0x7E
+#define BMI160_CMD_ACCEL_PM_SUSPEND	0x10
+#define BMI160_CMD_ACCEL_PM_NORMAL	0x11
+#define BMI160_CMD_ACCEL_PM_LOW_POWER	0x12
+#define BMI160_CMD_GYRO_PM_SUSPEND	0x14
+#define BMI160_CMD_GYRO_PM_NORMAL	0x15
+#define BMI160_CMD_GYRO_PM_FAST_STARTUP	0x17
+#define BMI160_CMD_SOFTRESET		0xB6
+
+#define BMI160_REG_DUMMY		0x7F
+
+#define BMI160_ACCEL_PMU_MIN_USLEEP	3200
+#define BMI160_ACCEL_PMU_MAX_USLEEP	3800
+#define BMI160_GYRO_PMU_MIN_USLEEP	55000
+#define BMI160_GYRO_PMU_MAX_USLEEP	80000
+#define BMI160_SOFTRESET_USLEEP		1000
+
+#define BMI160_CHANNEL(_type, _axis, _index) {			\
+	.type = _type,						\
+	.modified = 1,						\
+	.channel2 = IIO_MOD_##_axis,				\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |  \
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
+	.scan_index = _index,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+		.endianness = IIO_LE,				\
+	},							\
+}
+
+/* scan indexes follow DATA register order */
+enum bmi160_scan_axis {
+	BMI160_SCAN_EXT_MAGN_X = 0,
+	BMI160_SCAN_EXT_MAGN_Y,
+	BMI160_SCAN_EXT_MAGN_Z,
+	BMI160_SCAN_RHALL,
+	BMI160_SCAN_GYRO_X,
+	BMI160_SCAN_GYRO_Y,
+	BMI160_SCAN_GYRO_Z,
+	BMI160_SCAN_ACCEL_X,
+	BMI160_SCAN_ACCEL_Y,
+	BMI160_SCAN_ACCEL_Z,
+	BMI160_SCAN_TIMESTAMP,
+};
+
+enum bmi160_sensor_type {
+	BMI160_ACCEL	= 0,
+	BMI160_GYRO,
+	BMI160_EXT_MAGN,
+	BMI160_NUM_SENSORS /* must be last */
+};
+
+struct bmi160_data {
+	struct regmap *regmap;
+};
+
+const struct regmap_config bmi160_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+EXPORT_SYMBOL(bmi160_regmap_config);
+
+struct bmi160_regs {
+	u8 data; /* LSB byte register for X-axis */
+	u8 config;
+	u8 config_odr_mask;
+	u8 config_bwp_mask;
+	u8 range;
+	u8 pmu_cmd_normal;
+	u8 pmu_cmd_suspend;
+};
+
+static struct bmi160_regs bmi160_regs[] = {
+	[BMI160_ACCEL] = {
+		.data	= BMI160_REG_DATA_ACCEL_XOUT_L,
+		.config	= BMI160_REG_ACCEL_CONFIG,
+		.config_odr_mask = BMI160_ACCEL_CONFIG_ODR_MASK,
+		.config_bwp_mask = BMI160_ACCEL_CONFIG_BWP_MASK,
+		.range	= BMI160_REG_ACCEL_RANGE,
+		.pmu_cmd_normal = BMI160_CMD_ACCEL_PM_NORMAL,
+		.pmu_cmd_suspend = BMI160_CMD_ACCEL_PM_SUSPEND,
+	},
+	[BMI160_GYRO] = {
+		.data	= BMI160_REG_DATA_GYRO_XOUT_L,
+		.config	= BMI160_REG_GYRO_CONFIG,
+		.config_odr_mask = BMI160_GYRO_CONFIG_ODR_MASK,
+		.config_bwp_mask = BMI160_GYRO_CONFIG_BWP_MASK,
+		.range	= BMI160_REG_GYRO_RANGE,
+		.pmu_cmd_normal = BMI160_CMD_GYRO_PM_NORMAL,
+		.pmu_cmd_suspend = BMI160_CMD_GYRO_PM_SUSPEND,
+	},
+};
+
+struct bmi160_pmu_time {
+	unsigned long min;
+	unsigned long max;
+};
+
+static struct bmi160_pmu_time bmi160_pmu_time[] = {
+	[BMI160_ACCEL] = {
+		.min = BMI160_ACCEL_PMU_MIN_USLEEP,
+		.max = BMI160_ACCEL_PMU_MAX_USLEEP
+	},
+	[BMI160_GYRO] = {
+		.min = BMI160_GYRO_PMU_MIN_USLEEP,
+		.max = BMI160_GYRO_PMU_MIN_USLEEP,
+	},
+};
+
+struct bmi160_scale {
+	u8 bits;
+	int uscale;
+};
+
+struct bmi160_odr {
+	u8 bits;
+	int odr;
+	int uodr;
+};
+
+static const struct bmi160_scale bmi160_accel_scale[] = {
+	{ BMI160_ACCEL_RANGE_2G, 598},
+	{ BMI160_ACCEL_RANGE_4G, 1197},
+	{ BMI160_ACCEL_RANGE_8G, 2394},
+	{ BMI160_ACCEL_RANGE_16G, 4788},
+};
+
+static const struct bmi160_scale bmi160_gyro_scale[] = {
+	{ BMI160_GYRO_RANGE_2000DPS, 1065},
+	{ BMI160_GYRO_RANGE_1000DPS, 532},
+	{ BMI160_GYRO_RANGE_500DPS, 266},
+	{ BMI160_GYRO_RANGE_250DPS, 133},
+	{ BMI160_GYRO_RANGE_125DPS, 66},
+};
+
+struct bmi160_scale_item {
+	const struct bmi160_scale *tbl;
+	int num;
+};
+
+static const struct  bmi160_scale_item bmi160_scale_table[] = {
+	[BMI160_ACCEL] = {
+		.tbl	= bmi160_accel_scale,
+		.num	= ARRAY_SIZE(bmi160_accel_scale),
+	},
+	[BMI160_GYRO] = {
+		.tbl	= bmi160_gyro_scale,
+		.num	= ARRAY_SIZE(bmi160_gyro_scale),
+	},
+};
+
+static const struct bmi160_odr bmi160_accel_odr[] = {
+	{0x01, 0, 781250},
+	{0x02, 1, 562500},
+	{0x03, 3, 125000},
+	{0x04, 6, 250000},
+	{0x05, 12, 500000},
+	{0x06, 25, 0},
+	{0x07, 50, 0},
+	{0x08, 100, 0},
+	{0x09, 200, 0},
+	{0x0A, 400, 0},
+	{0x0B, 800, 0},
+	{0x0C, 1600, 0},
+};
+
+static const struct bmi160_odr bmi160_gyro_odr[] = {
+	{0x06, 25, 0},
+	{0x07, 50, 0},
+	{0x08, 100, 0},
+	{0x09, 200, 0},
+	{0x0A, 400, 0},
+	{0x0B, 800, 0},
+	{0x0C, 1600, 0},
+	{0x0D, 3200, 0},
+};
+
+struct bmi160_odr_item {
+	const struct bmi160_odr *tbl;
+	int num;
+};
+
+static const struct  bmi160_odr_item bmi160_odr_table[] = {
+	[BMI160_ACCEL] = {
+		.tbl	= bmi160_accel_odr,
+		.num	= ARRAY_SIZE(bmi160_accel_odr),
+	},
+	[BMI160_GYRO] = {
+		.tbl	= bmi160_gyro_odr,
+		.num	= ARRAY_SIZE(bmi160_gyro_odr),
+	},
+};
+
+static const struct iio_chan_spec bmi160_channels[] = {
+	BMI160_CHANNEL(IIO_ACCEL, X, BMI160_SCAN_ACCEL_X),
+	BMI160_CHANNEL(IIO_ACCEL, Y, BMI160_SCAN_ACCEL_Y),
+	BMI160_CHANNEL(IIO_ACCEL, Z, BMI160_SCAN_ACCEL_Z),
+	BMI160_CHANNEL(IIO_ANGL_VEL, X, BMI160_SCAN_GYRO_X),
+	BMI160_CHANNEL(IIO_ANGL_VEL, Y, BMI160_SCAN_GYRO_Y),
+	BMI160_CHANNEL(IIO_ANGL_VEL, Z, BMI160_SCAN_GYRO_Z),
+	IIO_CHAN_SOFT_TIMESTAMP(BMI160_SCAN_TIMESTAMP),
+};
+
+static enum bmi160_sensor_type bmi160_to_sensor(enum iio_chan_type iio_type)
+{
+	switch (iio_type) {
+	case IIO_ACCEL:
+		return BMI160_ACCEL;
+	case IIO_ANGL_VEL:
+		return BMI160_GYRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static
+int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t,
+		    bool mode)
+{
+	int ret;
+	u8 cmd;
+
+	if (mode)
+		cmd = bmi160_regs[t].pmu_cmd_normal;
+	else
+		cmd = bmi160_regs[t].pmu_cmd_suspend;
+
+	ret = regmap_write(data->regmap, BMI160_REG_CMD, cmd);
+	if (ret < 0)
+		return ret;
+
+	usleep_range(bmi160_pmu_time[t].min, bmi160_pmu_time[t].max);
+
+	return 0;
+}
+
+static
+int bmi160_set_scale(struct bmi160_data *data, enum bmi160_sensor_type t,
+		     int uscale)
+{
+	int i;
+
+	for (i = 0; i < bmi160_scale_table[t].num; i++)
+		if (bmi160_scale_table[t].tbl[i].uscale == uscale)
+			break;
+
+	if (i == bmi160_scale_table[t].num)
+		return -EINVAL;
+
+	return regmap_write(data->regmap, bmi160_regs[t].range,
+			    bmi160_scale_table[t].tbl[i].bits);
+}
+
+static
+int bmi160_get_scale(struct bmi160_data *data, enum bmi160_sensor_type t,
+		     int *uscale)
+{
+	int i, ret, val;
+
+	ret = regmap_read(data->regmap, bmi160_regs[t].range, &val);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < bmi160_scale_table[t].num; i++)
+		if (bmi160_scale_table[t].tbl[i].bits == val) {
+			*uscale = bmi160_scale_table[t].tbl[i].uscale;
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+static int bmi160_get_data(struct bmi160_data *data, int chan_type,
+			   int axis, int *val)
+{
+	u8 reg;
+	int ret;
+	__le16 sample;
+	enum bmi160_sensor_type t = bmi160_to_sensor(chan_type);
+
+	reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(__le16);
+
+	ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(__le16));
+	if (ret < 0)
+		return ret;
+
+	*val = sign_extend32(le16_to_cpu(sample), 15);
+
+	return 0;
+}
+
+static
+int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t,
+		   int odr, int uodr)
+{
+	int i;
+
+	for (i = 0; i < bmi160_odr_table[t].num; i++)
+		if (bmi160_odr_table[t].tbl[i].odr == odr &&
+		    bmi160_odr_table[t].tbl[i].uodr == uodr)
+			break;
+
+	if (i >= bmi160_odr_table[t].num)
+		return -EINVAL;
+
+	return regmap_update_bits(data->regmap,
+				  bmi160_regs[t].config,
+				  bmi160_regs[t].config_odr_mask,
+				  bmi160_odr_table[t].tbl[i].bits);
+}
+
+static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t,
+			  int *odr, int *uodr)
+{
+	int i, val, ret;
+
+	ret = regmap_read(data->regmap, bmi160_regs[t].config, &val);
+	if (ret < 0)
+		return ret;
+
+	val &= bmi160_regs[t].config_odr_mask;
+
+	for (i = 0; i < bmi160_odr_table[t].num; i++)
+		if (val == bmi160_odr_table[t].tbl[i].bits)
+			break;
+
+	if (i >= bmi160_odr_table[t].num)
+		return -EINVAL;
+
+	*odr = bmi160_odr_table[t].tbl[i].odr;
+	*uodr = bmi160_odr_table[t].tbl[i].uodr;
+
+	return 0;
+}
+
+static irqreturn_t bmi160_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct bmi160_data *data = iio_priv(indio_dev);
+	s16 buf[16]; /* 3 sens x 3 axis x s16 + 3 x s16 pad + 4 x s16 tstamp */
+	int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L;
+	__le16 sample;
+
+	for_each_set_bit(i, indio_dev->active_scan_mask,
+			 indio_dev->masklength) {
+		ret = regmap_bulk_read(data->regmap, base + i * sizeof(__le16),
+				       &sample, sizeof(__le16));
+		if (ret < 0)
+			goto done;
+		buf[j++] = sample;
+	}
+
+	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+					   iio_get_time_ns(indio_dev));
+done:
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+}
+
+static int bmi160_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	int ret;
+	struct bmi160_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = bmi160_get_data(data, chan->type, chan->channel2, val);
+		if (ret < 0)
+			return ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		ret = bmi160_get_scale(data,
+				       bmi160_to_sensor(chan->type), val2);
+		return ret < 0 ? ret : IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = bmi160_get_odr(data, bmi160_to_sensor(chan->type),
+				     val, val2);
+		return ret < 0 ? ret : IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bmi160_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	struct bmi160_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return bmi160_set_scale(data,
+					bmi160_to_sensor(chan->type), val2);
+		break;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return bmi160_set_odr(data, bmi160_to_sensor(chan->type),
+				      val, val2);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static
+IIO_CONST_ATTR(in_accel_sampling_frequency_available,
+	       "0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600");
+static
+IIO_CONST_ATTR(in_anglvel_sampling_frequency_available,
+	       "25 50 100 200 400 800 1600 3200");
+static
+IIO_CONST_ATTR(in_accel_scale_available,
+	       "0.000598 0.001197 0.002394 0.004788");
+static
+IIO_CONST_ATTR(in_anglvel_scale_available,
+	       "0.001065 0.000532 0.000266 0.000133 0.000066");
+
+static struct attribute *bmi160_attrs[] = {
+	&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
+	&iio_const_attr_in_anglvel_sampling_frequency_available.dev_attr.attr,
+	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
+	&iio_const_attr_in_anglvel_scale_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group bmi160_attrs_group = {
+	.attrs = bmi160_attrs,
+};
+
+static const struct iio_info bmi160_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = bmi160_read_raw,
+	.write_raw = bmi160_write_raw,
+	.attrs = &bmi160_attrs_group,
+};
+
+static const char *bmi160_match_acpi_device(struct device *dev)
+{
+	const struct acpi_device_id *id;
+
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return NULL;
+
+	return dev_name(dev);
+}
+
+static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
+{
+	int ret;
+	unsigned int val;
+	struct device *dev = regmap_get_device(data->regmap);
+
+	ret = regmap_write(data->regmap, BMI160_REG_CMD, BMI160_CMD_SOFTRESET);
+	if (ret < 0)
+		return ret;
+
+	usleep_range(BMI160_SOFTRESET_USLEEP, BMI160_SOFTRESET_USLEEP + 1);
+
+	/*
+	 * CS rising edge is needed before starting SPI, so do a dummy read
+	 * See Section 3.2.1, page 86 of the datasheet
+	 */
+	if (use_spi) {
+		ret = regmap_read(data->regmap, BMI160_REG_DUMMY, &val);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = regmap_read(data->regmap, BMI160_REG_CHIP_ID, &val);
+	if (ret < 0) {
+		dev_err(dev, "Error reading chip id\n");
+		return ret;
+	}
+	if (val != BMI160_CHIP_ID_VAL) {
+		dev_err(dev, "Wrong chip id, got %x expected %x\n",
+			val, BMI160_CHIP_ID_VAL);
+		return -ENODEV;
+	}
+
+	ret = bmi160_set_mode(data, BMI160_ACCEL, true);
+	if (ret < 0)
+		return ret;
+
+	ret = bmi160_set_mode(data, BMI160_GYRO, true);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void bmi160_chip_uninit(struct bmi160_data *data)
+{
+	bmi160_set_mode(data, BMI160_GYRO, false);
+	bmi160_set_mode(data, BMI160_ACCEL, false);
+}
+
+int bmi160_core_probe(struct device *dev, struct regmap *regmap,
+		      const char *name, bool use_spi)
+{
+	struct iio_dev *indio_dev;
+	struct bmi160_data *data;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	dev_set_drvdata(dev, indio_dev);
+	data->regmap = regmap;
+
+	ret = bmi160_chip_init(data, use_spi);
+	if (ret < 0)
+		return ret;
+
+	if (!name && ACPI_HANDLE(dev))
+		name = bmi160_match_acpi_device(dev);
+
+	indio_dev->dev.parent = dev;
+	indio_dev->channels = bmi160_channels;
+	indio_dev->num_channels = ARRAY_SIZE(bmi160_channels);
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &bmi160_info;
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+					 bmi160_trigger_handler, NULL);
+	if (ret < 0)
+		goto uninit;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		goto buffer_cleanup;
+
+	return 0;
+buffer_cleanup:
+	iio_triggered_buffer_cleanup(indio_dev);
+uninit:
+	bmi160_chip_uninit(data);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bmi160_core_probe);
+
+void bmi160_core_remove(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct bmi160_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	bmi160_chip_uninit(data);
+}
+EXPORT_SYMBOL_GPL(bmi160_core_remove);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
+MODULE_DESCRIPTION("Bosch BMI160 driver");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c
new file mode 100644
index 0000000..07a179d
--- /dev/null
+++ b/drivers/iio/imu/bmi160/bmi160_i2c.c
@@ -0,0 +1,72 @@
+/*
+ * BMI160 - Bosch IMU, I2C bits
+ *
+ * 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 slave address is:
+ *      - 0x68 if SDO is pulled to GND
+ *      - 0x69 if SDO is pulled to VDDIO
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/acpi.h>
+
+#include "bmi160.h"
+
+static int bmi160_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	const char *name = NULL;
+
+	regmap = devm_regmap_init_i2c(client, &bmi160_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);
+	}
+
+	if (id)
+		name = id->name;
+
+	return bmi160_core_probe(&client->dev, regmap, name, false);
+}
+
+static int bmi160_i2c_remove(struct i2c_client *client)
+{
+	bmi160_core_remove(&client->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id bmi160_i2c_id[] = {
+	{"bmi160", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id);
+
+static const struct acpi_device_id bmi160_acpi_match[] = {
+	{"BMI0160", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
+
+static struct i2c_driver bmi160_i2c_driver = {
+	.driver = {
+		.name			= "bmi160_i2c",
+		.acpi_match_table	= ACPI_PTR(bmi160_acpi_match),
+	},
+	.probe		= bmi160_i2c_probe,
+	.remove		= bmi160_i2c_remove,
+	.id_table	= bmi160_i2c_id,
+};
+module_i2c_driver(bmi160_i2c_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
+MODULE_DESCRIPTION("BMI160 I2C driver");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c
new file mode 100644
index 0000000..1ec8b12
--- /dev/null
+++ b/drivers/iio/imu/bmi160/bmi160_spi.c
@@ -0,0 +1,63 @@
+/*
+ * BMI160 - Bosch IMU, SPI bits
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/acpi.h>
+
+#include "bmi160.h"
+
+static int bmi160_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+	const struct spi_device_id *id = spi_get_device_id(spi);
+
+	regmap = devm_regmap_init_spi(spi, &bmi160_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 bmi160_core_probe(&spi->dev, regmap, id->name, true);
+}
+
+static int bmi160_spi_remove(struct spi_device *spi)
+{
+	bmi160_core_remove(&spi->dev);
+
+	return 0;
+}
+
+static const struct spi_device_id bmi160_spi_id[] = {
+	{"bmi160", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, bmi160_spi_id);
+
+static const struct acpi_device_id bmi160_acpi_match[] = {
+	{"BMI0160", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
+
+static struct spi_driver bmi160_spi_driver = {
+	.probe		= bmi160_spi_probe,
+	.remove		= bmi160_spi_remove,
+	.id_table	= bmi160_spi_id,
+	.driver = {
+		.acpi_match_table = ACPI_PTR(bmi160_acpi_match),
+		.name	= "bmi160_spi",
+	},
+};
+module_spi_driver(bmi160_spi_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
+MODULE_DESCRIPTION("Bosch BMI160 SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
index 847455a..5483b2e 100644
--- a/drivers/iio/imu/inv_mpu6050/Kconfig
+++ b/drivers/iio/imu/inv_mpu6050/Kconfig
@@ -13,10 +13,8 @@ config INV_MPU6050_I2C
 	select INV_MPU6050_IIO
 	select REGMAP_I2C
 	help
-	  This driver supports the Invensense MPU6050 devices.
-	  This driver can also support MPU6500 in MPU6050 compatibility mode
-	  and also in MPU6500 mode with some limitations.
-	  It is a gyroscope/accelerometer combo device.
+	  This driver supports the Invensense MPU6050/6500/9150 and ICM20608
+	  motion tracking devices over I2C.
 	  This driver can be built as a module. The module will be called
 	  inv-mpu6050-i2c.
 
@@ -26,7 +24,7 @@ config INV_MPU6050_SPI
 	select INV_MPU6050_IIO
 	select REGMAP_SPI
 	help
-	  This driver supports the Invensense MPU6050 devices.
-	  It is a gyroscope/accelerometer combo device.
+	  This driver supports the Invensense MPU6050/6500/9150 and ICM20608
+	  motion tracking devices over SPI.
 	  This driver can be built as a module. The module will be called
 	  inv-mpu6050-spi.
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
index 2771106..dd6fc6d 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
@@ -56,6 +56,7 @@ static int asus_acpi_get_sensor_info(struct acpi_device *adev,
 	int i;
 	acpi_status status;
 	union acpi_object *cpm;
+	int ret;
 
 	status = acpi_evaluate_object(adev->handle, "CNF0", NULL, &buffer);
 	if (ACPI_FAILURE(status))
@@ -82,10 +83,10 @@ static int asus_acpi_get_sensor_info(struct acpi_device *adev,
 			}
 		}
 	}
-
+	ret = cpm->package.count;
 	kfree(buffer.pointer);
 
-	return cpm->package.count;
+	return ret;
 }
 
 static int acpi_i2c_check_resource(struct acpi_resource *ares, void *data)
@@ -183,7 +184,7 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
 			} else
 				return 0; /* no secondary addr, which is OK */
 		}
-		st->mux_client = i2c_new_device(st->mux_adapter, &info);
+		st->mux_client = i2c_new_device(st->muxc->adapter[0], &info);
 		if (!st->mux_client)
 			return -ENODEV;
 	}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index d192953..b9fcbf1 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -23,7 +23,6 @@
 #include <linux/kfifo.h>
 #include <linux/spinlock.h>
 #include <linux/iio/iio.h>
-#include <linux/i2c-mux.h>
 #include <linux/acpi.h>
 #include "inv_mpu_iio.h"
 
@@ -88,19 +87,38 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = {
 	.accl_fs = INV_MPU6050_FS_02G,
 };
 
+/* Indexed by enum inv_devices */
 static const struct inv_mpu6050_hw hw_info[] = {
 	{
-		.num_reg = 117,
+		.whoami = INV_MPU6050_WHOAMI_VALUE,
+		.name = "MPU6050",
+		.reg = &reg_set_6050,
+		.config = &chip_config_6050,
+	},
+	{
+		.whoami = INV_MPU6500_WHOAMI_VALUE,
 		.name = "MPU6500",
 		.reg = &reg_set_6500,
 		.config = &chip_config_6050,
 	},
 	{
-		.num_reg = 117,
-		.name = "MPU6050",
+		.whoami = INV_MPU6000_WHOAMI_VALUE,
+		.name = "MPU6000",
 		.reg = &reg_set_6050,
 		.config = &chip_config_6050,
 	},
+	{
+		.whoami = INV_MPU9150_WHOAMI_VALUE,
+		.name = "MPU9150",
+		.reg = &reg_set_6050,
+		.config = &chip_config_6050,
+	},
+	{
+		.whoami = INV_ICM20608_WHOAMI_VALUE,
+		.name = "ICM20608",
+		.reg = &reg_set_6500,
+		.config = &chip_config_6050,
+	},
 };
 
 int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
@@ -600,6 +618,10 @@ inv_fifo_rate_show(struct device *dev, struct device_attribute *attr,
 /**
  * inv_attr_show() - calling this function will show current
  *                    parameters.
+ *
+ * Deprecated in favor of IIO mounting matrix API.
+ *
+ * See inv_get_mount_matrix()
  */
 static ssize_t inv_attr_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
@@ -644,6 +666,18 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
 	return 0;
 }
 
+static const struct iio_mount_matrix *
+inv_get_mount_matrix(const struct iio_dev *indio_dev,
+		     const struct iio_chan_spec *chan)
+{
+	return &((struct inv_mpu6050_state *)iio_priv(indio_dev))->orientation;
+}
+
+static const struct iio_chan_spec_ext_info inv_ext_info[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix),
+	{ },
+};
+
 #define INV_MPU6050_CHAN(_type, _channel2, _index)                    \
 	{                                                             \
 		.type = _type,                                        \
@@ -660,6 +694,7 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
 				.shift = 0,                           \
 				.endianness = IIO_BE,                 \
 			     },                                       \
+		.ext_info = inv_ext_info,                             \
 	}
 
 static const struct iio_chan_spec inv_mpu_channels[] = {
@@ -692,14 +727,16 @@ static IIO_CONST_ATTR(in_accel_scale_available,
 					  "0.000598 0.001196 0.002392 0.004785");
 static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show,
 	inv_mpu6050_fifo_rate_store);
+
+/* Deprecated: kept for userspace backward compatibility. */
 static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL,
 	ATTR_GYRO_MATRIX);
 static IIO_DEVICE_ATTR(in_accel_matrix, S_IRUGO, inv_attr_show, NULL,
 	ATTR_ACCL_MATRIX);
 
 static struct attribute *inv_attributes[] = {
-	&iio_dev_attr_in_gyro_matrix.dev_attr.attr,
-	&iio_dev_attr_in_accel_matrix.dev_attr.attr,
+	&iio_dev_attr_in_gyro_matrix.dev_attr.attr,  /* deprecated */
+	&iio_dev_attr_in_accel_matrix.dev_attr.attr, /* deprecated */
 	&iio_dev_attr_sampling_frequency.dev_attr.attr,
 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
 	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
@@ -726,6 +763,7 @@ static const struct iio_info mpu_info = {
 static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
 {
 	int result;
+	unsigned int regval;
 
 	st->hw  = &hw_info[st->chip_type];
 	st->reg = hw_info[st->chip_type].reg;
@@ -736,6 +774,17 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
 	if (result)
 		return result;
 	msleep(INV_MPU6050_POWER_UP_TIME);
+
+	/* check chip self-identification */
+	result = regmap_read(st->map, INV_MPU6050_REG_WHOAMI, &regval);
+	if (result)
+		return result;
+	if (regval != st->hw->whoami) {
+		dev_warn(regmap_get_device(st->map),
+				"whoami mismatch got %#02x expected %#02hhx for %s\n",
+				regval, st->hw->whoami, st->hw->name);
+	}
+
 	/*
 	 * toggle power state. After reset, the sleep bit could be on
 	 * or off depending on the OTP settings. Toggling power would
@@ -774,14 +823,31 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
 	if (!indio_dev)
 		return -ENOMEM;
 
+	BUILD_BUG_ON(ARRAY_SIZE(hw_info) != INV_NUM_PARTS);
+	if (chip_type < 0 || chip_type >= INV_NUM_PARTS) {
+		dev_err(dev, "Bad invensense chip_type=%d name=%s\n",
+				chip_type, name);
+		return -ENODEV;
+	}
 	st = iio_priv(indio_dev);
 	st->chip_type = chip_type;
 	st->powerup_count = 0;
 	st->irq = irq;
 	st->map = regmap;
+
 	pdata = dev_get_platdata(dev);
-	if (pdata)
+	if (!pdata) {
+		result = of_iio_read_mount_matrix(dev, "mount-matrix",
+						  &st->orientation);
+		if (result) {
+			dev_err(dev, "Failed to retrieve mounting matrix %d\n",
+				result);
+			return result;
+		}
+	} else {
 		st->plat_data = *pdata;
+	}
+
 	/* power is turned on inside check chip type*/
 	result = inv_check_and_setup_chip(st);
 	if (result)
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
index 5ee4e0d..19580d1 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
@@ -15,7 +15,6 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
-#include <linux/i2c-mux.h>
 #include <linux/iio/iio.h>
 #include <linux/module.h>
 #include "inv_mpu_iio.h"
@@ -25,46 +24,16 @@ static const struct regmap_config inv_mpu_regmap_config = {
 	.val_bits = 8,
 };
 
-/*
- * The i2c read/write needs to happen in unlocked mode. As the parent
- * adapter is common. If we use locked versions, it will fail as
- * the mux adapter will lock the parent i2c adapter, while calling
- * select/deselect functions.
- */
-static int inv_mpu6050_write_reg_unlocked(struct i2c_client *client,
-					  u8 reg, u8 d)
+static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	int ret;
-	u8 buf[2] = {reg, d};
-	struct i2c_msg msg[1] = {
-		{
-			.addr = client->addr,
-			.flags = 0,
-			.len = sizeof(buf),
-			.buf = buf,
-		}
-	};
-
-	ret = __i2c_transfer(client->adapter, msg, 1);
-	if (ret != 1)
-		return ret;
-
-	return 0;
-}
-
-static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
-				     u32 chan_id)
-{
-	struct i2c_client *client = mux_priv;
-	struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
+	struct iio_dev *indio_dev = i2c_mux_priv(muxc);
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 	int ret = 0;
 
 	/* Use the same mutex which was used everywhere to protect power-op */
 	mutex_lock(&indio_dev->mlock);
 	if (!st->powerup_count) {
-		ret = inv_mpu6050_write_reg_unlocked(client,
-						     st->reg->pwr_mgmt_1, 0);
+		ret = regmap_write(st->map, st->reg->pwr_mgmt_1, 0);
 		if (ret)
 			goto write_error;
 
@@ -73,10 +42,9 @@ static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
 	}
 	if (!ret) {
 		st->powerup_count++;
-		ret = inv_mpu6050_write_reg_unlocked(client,
-						     st->reg->int_pin_cfg,
-						     INV_MPU6050_INT_PIN_CFG |
-						     INV_MPU6050_BIT_BYPASS_EN);
+		ret = regmap_write(st->map, st->reg->int_pin_cfg,
+				   INV_MPU6050_INT_PIN_CFG |
+				   INV_MPU6050_BIT_BYPASS_EN);
 	}
 write_error:
 	mutex_unlock(&indio_dev->mlock);
@@ -84,21 +52,18 @@ write_error:
 	return ret;
 }
 
-static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
-				       void *mux_priv, u32 chan_id)
+static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id)
 {
-	struct i2c_client *client = mux_priv;
-	struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
+	struct iio_dev *indio_dev = i2c_mux_priv(muxc);
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 
 	mutex_lock(&indio_dev->mlock);
 	/* It doesn't really mattter, if any of the calls fails */
-	inv_mpu6050_write_reg_unlocked(client, st->reg->int_pin_cfg,
-				       INV_MPU6050_INT_PIN_CFG);
+	regmap_write(st->map, st->reg->int_pin_cfg, INV_MPU6050_INT_PIN_CFG);
 	st->powerup_count--;
 	if (!st->powerup_count)
-		inv_mpu6050_write_reg_unlocked(client, st->reg->pwr_mgmt_1,
-					       INV_MPU6050_BIT_SLEEP);
+		regmap_write(st->map, st->reg->pwr_mgmt_1,
+			     INV_MPU6050_BIT_SLEEP);
 	mutex_unlock(&indio_dev->mlock);
 
 	return 0;
@@ -160,16 +125,18 @@ static int inv_mpu_probe(struct i2c_client *client,
 		return result;
 
 	st = iio_priv(dev_get_drvdata(&client->dev));
-	st->mux_adapter = i2c_add_mux_adapter(client->adapter,
-					      &client->dev,
-					      client,
-					      0, 0, 0,
-					      inv_mpu6050_select_bypass,
-					      inv_mpu6050_deselect_bypass);
-	if (!st->mux_adapter) {
-		result = -ENODEV;
+	st->muxc = i2c_mux_alloc(client->adapter, &client->dev,
+				 1, 0, I2C_MUX_LOCKED,
+				 inv_mpu6050_select_bypass,
+				 inv_mpu6050_deselect_bypass);
+	if (!st->muxc) {
+		result = -ENOMEM;
 		goto out_unreg_device;
 	}
+	st->muxc->priv = dev_get_drvdata(&client->dev);
+	result = i2c_mux_add_adapter(st->muxc, 0, 0, 0);
+	if (result)
+		goto out_unreg_device;
 
 	result = inv_mpu_acpi_create_mux_client(client);
 	if (result)
@@ -178,7 +145,7 @@ static int inv_mpu_probe(struct i2c_client *client,
 	return 0;
 
 out_del_mux:
-	i2c_del_mux_adapter(st->mux_adapter);
+	i2c_mux_del_adapters(st->muxc);
 out_unreg_device:
 	inv_mpu_core_remove(&client->dev);
 	return result;
@@ -190,7 +157,7 @@ static int inv_mpu_remove(struct i2c_client *client)
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 
 	inv_mpu_acpi_delete_mux_client(client);
-	i2c_del_mux_adapter(st->mux_adapter);
+	i2c_mux_del_adapters(st->muxc);
 
 	return inv_mpu_core_remove(&client->dev);
 }
@@ -202,13 +169,15 @@ static int inv_mpu_remove(struct i2c_client *client)
 static const struct i2c_device_id inv_mpu_id[] = {
 	{"mpu6050", INV_MPU6050},
 	{"mpu6500", INV_MPU6500},
+	{"mpu9150", INV_MPU9150},
+	{"icm20608", INV_ICM20608},
 	{}
 };
 
 MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
 
 static const struct acpi_device_id inv_acpi_match[] = {
-	{"INVN6500", 0},
+	{"INVN6500", INV_MPU6500},
 	{ },
 };
 
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index e302a49..f0e8c5d 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -11,6 +11,7 @@
 * GNU General Public License for more details.
 */
 #include <linux/i2c.h>
+#include <linux/i2c-mux.h>
 #include <linux/kfifo.h>
 #include <linux/spinlock.h>
 #include <linux/iio/iio.h>
@@ -68,6 +69,8 @@ enum inv_devices {
 	INV_MPU6050,
 	INV_MPU6500,
 	INV_MPU6000,
+	INV_MPU9150,
+	INV_ICM20608,
 	INV_NUM_PARTS
 };
 
@@ -93,13 +96,13 @@ struct inv_mpu6050_chip_config {
 
 /**
  *  struct inv_mpu6050_hw - Other important hardware information.
- *  @num_reg:	Number of registers on device.
+ *  @whoami:	Self identification byte from WHO_AM_I register
  *  @name:      name of the chip.
  *  @reg:   register map of the chip.
  *  @config:    configuration of the chip.
  */
 struct inv_mpu6050_hw {
-	u8 num_reg;
+	u8 whoami;
 	u8 *name;
 	const struct inv_mpu6050_reg_map *reg;
 	const struct inv_mpu6050_chip_config *config;
@@ -114,7 +117,8 @@ struct inv_mpu6050_hw {
  *  @hw:		Other hardware-specific information.
  *  @chip_type:		chip type.
  *  @time_stamp_lock:	spin lock to time stamp.
- *  @plat_data:		platform data.
+ *  @plat_data:		platform data (deprecated in favor of @orientation).
+ *  @orientation:	sensor chip orientation relative to main hardware.
  *  @timestamps:        kfifo queue to store time stamp.
  *  @map		regmap pointer.
  *  @irq		interrupt number.
@@ -127,10 +131,11 @@ struct inv_mpu6050_state {
 	const struct inv_mpu6050_hw *hw;
 	enum   inv_devices chip_type;
 	spinlock_t time_stamp_lock;
-	struct i2c_adapter *mux_adapter;
+	struct i2c_mux_core *muxc;
 	struct i2c_client *mux_client;
 	unsigned int powerup_count;
 	struct inv_mpu6050_platform_data plat_data;
+	struct iio_mount_matrix orientation;
 	DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
 	struct regmap *map;
 	int irq;
@@ -215,6 +220,14 @@ struct inv_mpu6050_state {
 #define INV_MPU6050_MIN_FIFO_RATE            4
 #define INV_MPU6050_ONE_K_HZ                 1000
 
+#define INV_MPU6050_REG_WHOAMI			117
+
+#define INV_MPU6000_WHOAMI_VALUE		0x68
+#define INV_MPU6050_WHOAMI_VALUE		0x68
+#define INV_MPU6500_WHOAMI_VALUE		0x70
+#define INV_MPU9150_WHOAMI_VALUE		0x68
+#define INV_ICM20608_WHOAMI_VALUE		0xAF
+
 /* scan element definition */
 enum inv_mpu6050_scan {
 	INV_MPU6050_SCAN_ACCL_X,
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
index d070062..3a9f3ea 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
@@ -107,7 +107,7 @@ irqreturn_t inv_mpu6050_irq_handler(int irq, void *p)
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 	s64 timestamp;
 
-	timestamp = iio_get_time_ns();
+	timestamp = iio_get_time_ns(indio_dev);
 	kfifo_in_spinlocked(&st->timestamps, &timestamp, 1,
 			    &st->time_stamp_lock);
 
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
index 7bcb8d8..6e6476d 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
@@ -44,9 +44,19 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev)
 static int inv_mpu_probe(struct spi_device *spi)
 {
 	struct regmap *regmap;
-	const struct spi_device_id *id = spi_get_device_id(spi);
-	const char *name = id ? id->name : NULL;
-	const int chip_type = id ? id->driver_data : 0;
+	const struct spi_device_id *spi_id;
+	const struct acpi_device_id *acpi_id;
+	const char *name = NULL;
+	enum inv_devices chip_type;
+
+	if ((spi_id = spi_get_device_id(spi))) {
+		chip_type = (enum inv_devices)spi_id->driver_data;
+		name = spi_id->name;
+	} else if ((acpi_id = acpi_match_device(spi->dev.driver->acpi_match_table, &spi->dev))) {
+		chip_type = (enum inv_devices)acpi_id->driver_data;
+	} else {
+		return -ENODEV;
+	}
 
 	regmap = devm_regmap_init_spi(spi, &inv_mpu_regmap_config);
 	if (IS_ERR(regmap)) {
@@ -70,13 +80,16 @@ static int inv_mpu_remove(struct spi_device *spi)
  */
 static const struct spi_device_id inv_mpu_id[] = {
 	{"mpu6000", INV_MPU6000},
+	{"mpu6500", INV_MPU6500},
+	{"mpu9150", INV_MPU9150},
+	{"icm20608", INV_ICM20608},
 	{}
 };
 
 MODULE_DEVICE_TABLE(spi, inv_mpu_id);
 
 static const struct acpi_device_id inv_acpi_match[] = {
-	{"INVN6000", 0},
+	{"INVN6000", INV_MPU6000},
 	{ },
 };
 MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index e5306b4..2e7dd57 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 70cb7eb..f914d5d 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/anon_inodes.h>
 #include <linux/debugfs.h>
+#include <linux/mutex.h>
 #include <linux/iio/iio.h>
 #include "iio_core.h"
 #include "iio_core_trigger.h"
@@ -78,6 +79,8 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_CONCENTRATION] = "concentration",
 	[IIO_RESISTANCE] = "resistance",
 	[IIO_PH] = "ph",
+	[IIO_UVINDEX] = "uvindex",
+	[IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity",
 };
 
 static const char * const iio_modifier_names[] = {
@@ -100,6 +103,7 @@ static const char * const iio_modifier_names[] = {
 	[IIO_MOD_LIGHT_RED] = "red",
 	[IIO_MOD_LIGHT_GREEN] = "green",
 	[IIO_MOD_LIGHT_BLUE] = "blue",
+	[IIO_MOD_LIGHT_UV] = "uv",
 	[IIO_MOD_QUATERNION] = "quaternion",
 	[IIO_MOD_TEMP_AMBIENT] = "ambient",
 	[IIO_MOD_TEMP_OBJECT] = "object",
@@ -174,6 +178,86 @@ ssize_t iio_read_const_attr(struct device *dev,
 }
 EXPORT_SYMBOL(iio_read_const_attr);
 
+static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
+{
+	int ret;
+	const struct iio_event_interface *ev_int = indio_dev->event_interface;
+
+	ret = mutex_lock_interruptible(&indio_dev->mlock);
+	if (ret)
+		return ret;
+	if ((ev_int && iio_event_enabled(ev_int)) ||
+	    iio_buffer_enabled(indio_dev)) {
+		mutex_unlock(&indio_dev->mlock);
+		return -EBUSY;
+	}
+	indio_dev->clock_id = clock_id;
+	mutex_unlock(&indio_dev->mlock);
+
+	return 0;
+}
+
+/**
+ * iio_get_time_ns() - utility function to get a time stamp for events etc
+ * @indio_dev: device
+ */
+s64 iio_get_time_ns(const struct iio_dev *indio_dev)
+{
+	struct timespec tp;
+
+	switch (iio_device_get_clock(indio_dev)) {
+	case CLOCK_REALTIME:
+		ktime_get_real_ts(&tp);
+		break;
+	case CLOCK_MONOTONIC:
+		ktime_get_ts(&tp);
+		break;
+	case CLOCK_MONOTONIC_RAW:
+		getrawmonotonic(&tp);
+		break;
+	case CLOCK_REALTIME_COARSE:
+		tp = current_kernel_time();
+		break;
+	case CLOCK_MONOTONIC_COARSE:
+		tp = get_monotonic_coarse();
+		break;
+	case CLOCK_BOOTTIME:
+		get_monotonic_boottime(&tp);
+		break;
+	case CLOCK_TAI:
+		timekeeping_clocktai(&tp);
+		break;
+	default:
+		BUG();
+	}
+
+	return timespec_to_ns(&tp);
+}
+EXPORT_SYMBOL(iio_get_time_ns);
+
+/**
+ * iio_get_time_res() - utility function to get time stamp clock resolution in
+ *                      nano seconds.
+ * @indio_dev: device
+ */
+unsigned int iio_get_time_res(const struct iio_dev *indio_dev)
+{
+	switch (iio_device_get_clock(indio_dev)) {
+	case CLOCK_REALTIME:
+	case CLOCK_MONOTONIC:
+	case CLOCK_MONOTONIC_RAW:
+	case CLOCK_BOOTTIME:
+	case CLOCK_TAI:
+		return hrtimer_resolution;
+	case CLOCK_REALTIME_COARSE:
+	case CLOCK_MONOTONIC_COARSE:
+		return LOW_RES_NSEC;
+	default:
+		BUG();
+	}
+}
+EXPORT_SYMBOL(iio_get_time_res);
+
 static int __init iio_init(void)
 {
 	int ret;
@@ -409,6 +493,88 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
 }
 EXPORT_SYMBOL_GPL(iio_enum_write);
 
+static const struct iio_mount_matrix iio_mount_idmatrix = {
+	.rotation = {
+		"1", "0", "0",
+		"0", "1", "0",
+		"0", "0", "1"
+	}
+};
+
+static int iio_setup_mount_idmatrix(const struct device *dev,
+				    struct iio_mount_matrix *matrix)
+{
+	*matrix = iio_mount_idmatrix;
+	dev_info(dev, "mounting matrix not found: using identity...\n");
+	return 0;
+}
+
+ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv,
+			      const struct iio_chan_spec *chan, char *buf)
+{
+	const struct iio_mount_matrix *mtx = ((iio_get_mount_matrix_t *)
+					      priv)(indio_dev, chan);
+
+	if (IS_ERR(mtx))
+		return PTR_ERR(mtx);
+
+	if (!mtx)
+		mtx = &iio_mount_idmatrix;
+
+	return snprintf(buf, PAGE_SIZE, "%s, %s, %s; %s, %s, %s; %s, %s, %s\n",
+			mtx->rotation[0], mtx->rotation[1], mtx->rotation[2],
+			mtx->rotation[3], mtx->rotation[4], mtx->rotation[5],
+			mtx->rotation[6], mtx->rotation[7], mtx->rotation[8]);
+}
+EXPORT_SYMBOL_GPL(iio_show_mount_matrix);
+
+/**
+ * of_iio_read_mount_matrix() - retrieve iio device mounting matrix from
+ *                              device-tree "mount-matrix" property
+ * @dev:	device the mounting matrix property is assigned to
+ * @propname:	device specific mounting matrix property name
+ * @matrix:	where to store retrieved matrix
+ *
+ * If device is assigned no mounting matrix property, a default 3x3 identity
+ * matrix will be filled in.
+ *
+ * Return: 0 if success, or a negative error code on failure.
+ */
+#ifdef CONFIG_OF
+int of_iio_read_mount_matrix(const struct device *dev,
+			     const char *propname,
+			     struct iio_mount_matrix *matrix)
+{
+	if (dev->of_node) {
+		int err = of_property_read_string_array(dev->of_node,
+				propname, matrix->rotation,
+				ARRAY_SIZE(iio_mount_idmatrix.rotation));
+
+		if (err == ARRAY_SIZE(iio_mount_idmatrix.rotation))
+			return 0;
+
+		if (err >= 0)
+			/* Invalid number of matrix entries. */
+			return -EINVAL;
+
+		if (err != -EINVAL)
+			/* Invalid matrix declaration format. */
+			return err;
+	}
+
+	/* Matrix was not declared at all: fallback to identity. */
+	return iio_setup_mount_idmatrix(dev, matrix);
+}
+#else
+int of_iio_read_mount_matrix(const struct device *dev,
+			     const char *propname,
+			     struct iio_mount_matrix *matrix)
+{
+	return iio_setup_mount_idmatrix(dev, matrix);
+}
+#endif
+EXPORT_SYMBOL(of_iio_read_mount_matrix);
+
 /**
  * iio_format_value() - Formats a IIO value into its string representation
  * @buf:	The buffer to which the formatted value gets written
@@ -904,11 +1070,91 @@ static ssize_t iio_show_dev_name(struct device *dev,
 
 static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
 
+static ssize_t iio_show_timestamp_clock(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	const struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	const clockid_t clk = iio_device_get_clock(indio_dev);
+	const char *name;
+	ssize_t sz;
+
+	switch (clk) {
+	case CLOCK_REALTIME:
+		name = "realtime\n";
+		sz = sizeof("realtime\n");
+		break;
+	case CLOCK_MONOTONIC:
+		name = "monotonic\n";
+		sz = sizeof("monotonic\n");
+		break;
+	case CLOCK_MONOTONIC_RAW:
+		name = "monotonic_raw\n";
+		sz = sizeof("monotonic_raw\n");
+		break;
+	case CLOCK_REALTIME_COARSE:
+		name = "realtime_coarse\n";
+		sz = sizeof("realtime_coarse\n");
+		break;
+	case CLOCK_MONOTONIC_COARSE:
+		name = "monotonic_coarse\n";
+		sz = sizeof("monotonic_coarse\n");
+		break;
+	case CLOCK_BOOTTIME:
+		name = "boottime\n";
+		sz = sizeof("boottime\n");
+		break;
+	case CLOCK_TAI:
+		name = "tai\n";
+		sz = sizeof("tai\n");
+		break;
+	default:
+		BUG();
+	}
+
+	memcpy(buf, name, sz);
+	return sz;
+}
+
+static ssize_t iio_store_timestamp_clock(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t len)
+{
+	clockid_t clk;
+	int ret;
+
+	if (sysfs_streq(buf, "realtime"))
+		clk = CLOCK_REALTIME;
+	else if (sysfs_streq(buf, "monotonic"))
+		clk = CLOCK_MONOTONIC;
+	else if (sysfs_streq(buf, "monotonic_raw"))
+		clk = CLOCK_MONOTONIC_RAW;
+	else if (sysfs_streq(buf, "realtime_coarse"))
+		clk = CLOCK_REALTIME_COARSE;
+	else if (sysfs_streq(buf, "monotonic_coarse"))
+		clk = CLOCK_MONOTONIC_COARSE;
+	else if (sysfs_streq(buf, "boottime"))
+		clk = CLOCK_BOOTTIME;
+	else if (sysfs_streq(buf, "tai"))
+		clk = CLOCK_TAI;
+	else
+		return -EINVAL;
+
+	ret = iio_device_set_clock(dev_to_iio_dev(dev), clk);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
+static DEVICE_ATTR(current_timestamp_clock, S_IRUGO | S_IWUSR,
+		   iio_show_timestamp_clock, iio_store_timestamp_clock);
+
 static int iio_device_register_sysfs(struct iio_dev *indio_dev)
 {
 	int i, ret = 0, attrcount, attrn, attrcount_orig = 0;
 	struct iio_dev_attr *p;
-	struct attribute **attr;
+	struct attribute **attr, *clk = NULL;
 
 	/* First count elements in any existing group */
 	if (indio_dev->info->attrs) {
@@ -923,16 +1169,25 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
 	 */
 	if (indio_dev->channels)
 		for (i = 0; i < indio_dev->num_channels; i++) {
-			ret = iio_device_add_channel_sysfs(indio_dev,
-							   &indio_dev
-							   ->channels[i]);
+			const struct iio_chan_spec *chan =
+				&indio_dev->channels[i];
+
+			if (chan->type == IIO_TIMESTAMP)
+				clk = &dev_attr_current_timestamp_clock.attr;
+
+			ret = iio_device_add_channel_sysfs(indio_dev, chan);
 			if (ret < 0)
 				goto error_clear_attrs;
 			attrcount += ret;
 		}
 
+	if (indio_dev->event_interface)
+		clk = &dev_attr_current_timestamp_clock.attr;
+
 	if (indio_dev->name)
 		attrcount++;
+	if (clk)
+		attrcount++;
 
 	indio_dev->chan_attr_group.attrs = kcalloc(attrcount + 1,
 						   sizeof(indio_dev->chan_attr_group.attrs[0]),
@@ -953,6 +1208,8 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
 		indio_dev->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr;
 	if (indio_dev->name)
 		indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr;
+	if (clk)
+		indio_dev->chan_attr_group.attrs[attrn++] = clk;
 
 	indio_dev->groups[indio_dev->groupcounter++] =
 		&indio_dev->chan_attr_group;
@@ -1375,6 +1632,44 @@ void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev)
 }
 EXPORT_SYMBOL_GPL(devm_iio_device_unregister);
 
+/**
+ * iio_device_claim_direct_mode - Keep device in direct mode
+ * @indio_dev:	the iio_dev associated with the device
+ *
+ * If the device is in direct mode it is guaranteed to stay
+ * that way until iio_device_release_direct_mode() is called.
+ *
+ * Use with iio_device_release_direct_mode()
+ *
+ * Returns: 0 on success, -EBUSY on failure
+ */
+int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
+{
+	mutex_lock(&indio_dev->mlock);
+
+	if (iio_buffer_enabled(indio_dev)) {
+		mutex_unlock(&indio_dev->mlock);
+		return -EBUSY;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode);
+
+/**
+ * iio_device_release_direct_mode - releases claim on direct mode
+ * @indio_dev:	the iio_dev associated with the device
+ *
+ * Release the claim. Device is no longer guaranteed to stay
+ * in direct mode.
+ *
+ * Use with iio_device_claim_direct_mode()
+ */
+void iio_device_release_direct_mode(struct iio_dev *indio_dev)
+{
+	mutex_unlock(&indio_dev->mlock);
+}
+EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
+
 subsys_initcall(iio_init);
 module_exit(iio_exit);
 
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index cae332b..0ebfc92 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -44,6 +44,11 @@ struct iio_event_interface {
 	struct mutex		read_lock;
 };
 
+bool iio_event_enabled(const struct iio_event_interface *ev_int)
+{
+	return !!test_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
+}
+
 /**
  * iio_push_event() - try to add event to the list for userspace reading
  * @indio_dev:		IIO device structure
@@ -60,7 +65,7 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
 	int copied;
 
 	/* Does anyone care? */
-	if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
+	if (iio_event_enabled(ev_int)) {
 
 		ev.id = ev_code;
 		ev.timestamp = timestamp;
@@ -180,8 +185,14 @@ int iio_event_getfd(struct iio_dev *indio_dev)
 	if (ev_int == NULL)
 		return -ENODEV;
 
-	if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags))
-		return -EBUSY;
+	fd = mutex_lock_interruptible(&indio_dev->mlock);
+	if (fd)
+		return fd;
+
+	if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
+		fd = -EBUSY;
+		goto unlock;
+	}
 
 	iio_device_get(indio_dev);
 
@@ -194,6 +205,8 @@ int iio_event_getfd(struct iio_dev *indio_dev)
 		kfifo_reset_out(&ev_int->det_events);
 	}
 
+unlock:
+	mutex_unlock(&indio_dev->mlock);
 	return fd;
 }
 
diff --git b/drivers/iio/industrialio-sw-device.c b/drivers/iio/industrialio-sw-device.c
new file mode 100644
index 0000000..81b49cf
--- /dev/null
+++ b/drivers/iio/industrialio-sw-device.c
@@ -0,0 +1,182 @@
+/*
+ * The Industrial I/O core, software IIO devices functions
+ *
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * 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/init.h>
+#include <linux/kmod.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include <linux/iio/sw_device.h>
+#include <linux/iio/configfs.h>
+#include <linux/configfs.h>
+
+static struct config_group *iio_devices_group;
+static struct config_item_type iio_device_type_group_type;
+
+static struct config_item_type iio_devices_group_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+static LIST_HEAD(iio_device_types_list);
+static DEFINE_MUTEX(iio_device_types_lock);
+
+static
+struct iio_sw_device_type *__iio_find_sw_device_type(const char *name,
+						     unsigned len)
+{
+	struct iio_sw_device_type *d = NULL, *iter;
+
+	list_for_each_entry(iter, &iio_device_types_list, list)
+		if (!strcmp(iter->name, name)) {
+			d = iter;
+			break;
+		}
+
+	return d;
+}
+
+int iio_register_sw_device_type(struct iio_sw_device_type *d)
+{
+	struct iio_sw_device_type *iter;
+	int ret = 0;
+
+	mutex_lock(&iio_device_types_lock);
+	iter = __iio_find_sw_device_type(d->name, strlen(d->name));
+	if (iter)
+		ret = -EBUSY;
+	else
+		list_add_tail(&d->list, &iio_device_types_list);
+	mutex_unlock(&iio_device_types_lock);
+
+	if (ret)
+		return ret;
+
+	d->group = configfs_register_default_group(iio_devices_group, d->name,
+						&iio_device_type_group_type);
+	if (IS_ERR(d->group))
+		ret = PTR_ERR(d->group);
+
+	return ret;
+}
+EXPORT_SYMBOL(iio_register_sw_device_type);
+
+void iio_unregister_sw_device_type(struct iio_sw_device_type *dt)
+{
+	struct iio_sw_device_type *iter;
+
+	mutex_lock(&iio_device_types_lock);
+	iter = __iio_find_sw_device_type(dt->name, strlen(dt->name));
+	if (iter)
+		list_del(&dt->list);
+	mutex_unlock(&iio_device_types_lock);
+
+	configfs_unregister_default_group(dt->group);
+}
+EXPORT_SYMBOL(iio_unregister_sw_device_type);
+
+static
+struct iio_sw_device_type *iio_get_sw_device_type(const char *name)
+{
+	struct iio_sw_device_type *dt;
+
+	mutex_lock(&iio_device_types_lock);
+	dt = __iio_find_sw_device_type(name, strlen(name));
+	if (dt && !try_module_get(dt->owner))
+		dt = NULL;
+	mutex_unlock(&iio_device_types_lock);
+
+	return dt;
+}
+
+struct iio_sw_device *iio_sw_device_create(const char *type, const char *name)
+{
+	struct iio_sw_device *d;
+	struct iio_sw_device_type *dt;
+
+	dt = iio_get_sw_device_type(type);
+	if (!dt) {
+		pr_err("Invalid device type: %s\n", type);
+		return ERR_PTR(-EINVAL);
+	}
+	d = dt->ops->probe(name);
+	if (IS_ERR(d))
+		goto out_module_put;
+
+	d->device_type = dt;
+
+	return d;
+out_module_put:
+	module_put(dt->owner);
+	return d;
+}
+EXPORT_SYMBOL(iio_sw_device_create);
+
+void iio_sw_device_destroy(struct iio_sw_device *d)
+{
+	struct iio_sw_device_type *dt = d->device_type;
+
+	dt->ops->remove(d);
+	module_put(dt->owner);
+}
+EXPORT_SYMBOL(iio_sw_device_destroy);
+
+static struct config_group *device_make_group(struct config_group *group,
+					      const char *name)
+{
+	struct iio_sw_device *d;
+
+	d = iio_sw_device_create(group->cg_item.ci_name, name);
+	if (IS_ERR(d))
+		return ERR_CAST(d);
+
+	config_item_set_name(&d->group.cg_item, "%s", name);
+
+	return &d->group;
+}
+
+static void device_drop_group(struct config_group *group,
+			      struct config_item *item)
+{
+	struct iio_sw_device *d = to_iio_sw_device(item);
+
+	iio_sw_device_destroy(d);
+	config_item_put(item);
+}
+
+static struct configfs_group_operations device_ops = {
+	.make_group	= &device_make_group,
+	.drop_item	= &device_drop_group,
+};
+
+static struct config_item_type iio_device_type_group_type = {
+	.ct_group_ops = &device_ops,
+	.ct_owner       = THIS_MODULE,
+};
+
+static int __init iio_sw_device_init(void)
+{
+	iio_devices_group =
+		configfs_register_default_group(&iio_configfs_subsys.su_group,
+						"devices",
+						&iio_devices_group_type);
+	return PTR_ERR_OR_ZERO(iio_devices_group);
+}
+module_init(iio_sw_device_init);
+
+static void __exit iio_sw_device_exit(void)
+{
+	configfs_unregister_default_group(iio_devices_group);
+}
+module_exit(iio_sw_device_exit);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
+MODULE_DESCRIPTION("Industrial I/O software devices support");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 0c52dfe..7ad82fd 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -64,10 +64,16 @@ static struct attribute *iio_trig_dev_attrs[] = {
 };
 ATTRIBUTE_GROUPS(iio_trig_dev);
 
+static struct iio_trigger *__iio_trigger_find_by_name(const char *name);
+
 int iio_trigger_register(struct iio_trigger *trig_info)
 {
 	int ret;
 
+	/* trig_info->ops is required for the module member */
+	if (!trig_info->ops)
+		return -EINVAL;
+
 	trig_info->id = ida_simple_get(&iio_trigger_ida, 0, 0, GFP_KERNEL);
 	if (trig_info->id < 0)
 		return trig_info->id;
@@ -82,11 +88,19 @@ int iio_trigger_register(struct iio_trigger *trig_info)
 
 	/* Add to list of available triggers held by the IIO core */
 	mutex_lock(&iio_trigger_list_lock);
+	if (__iio_trigger_find_by_name(trig_info->name)) {
+		pr_err("Duplicate trigger name '%s'\n", trig_info->name);
+		ret = -EEXIST;
+		goto error_device_del;
+	}
 	list_add_tail(&trig_info->list, &iio_trigger_list);
 	mutex_unlock(&iio_trigger_list_lock);
 
 	return 0;
 
+error_device_del:
+	mutex_unlock(&iio_trigger_list_lock);
+	device_del(&trig_info->dev);
 error_unregister_id:
 	ida_simple_remove(&iio_trigger_ida, trig_info->id);
 	return ret;
@@ -105,6 +119,18 @@ void iio_trigger_unregister(struct iio_trigger *trig_info)
 }
 EXPORT_SYMBOL(iio_trigger_unregister);
 
+/* Search for trigger by name, assuming iio_trigger_list_lock held */
+static struct iio_trigger *__iio_trigger_find_by_name(const char *name)
+{
+	struct iio_trigger *iter;
+
+	list_for_each_entry(iter, &iio_trigger_list, list)
+		if (!strcmp(iter->name, name))
+			return iter;
+
+	return NULL;
+}
+
 static struct iio_trigger *iio_trigger_find_by_name(const char *name,
 						    size_t len)
 {
@@ -164,8 +190,7 @@ EXPORT_SYMBOL(iio_trigger_poll_chained);
 
 void iio_trigger_notify_done(struct iio_trigger *trig)
 {
-	if (atomic_dec_and_test(&trig->use_count) && trig->ops &&
-		trig->ops->try_reenable)
+	if (atomic_dec_and_test(&trig->use_count) && trig->ops->try_reenable)
 		if (trig->ops->try_reenable(trig))
 			/* Missed an interrupt so launch new poll now */
 			iio_trigger_poll(trig);
@@ -224,7 +249,7 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
 		goto out_put_irq;
 
 	/* Enable trigger in driver */
-	if (trig->ops && trig->ops->set_trigger_state && notinuse) {
+	if (trig->ops->set_trigger_state && notinuse) {
 		ret = trig->ops->set_trigger_state(trig, true);
 		if (ret < 0)
 			goto out_free_irq;
@@ -249,7 +274,7 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
 		= (bitmap_weight(trig->pool,
 				 CONFIG_IIO_CONSUMERS_PER_TRIGGER)
 		   == 1);
-	if (trig->ops && trig->ops->set_trigger_state && no_other_users) {
+	if (trig->ops->set_trigger_state && no_other_users) {
 		ret = trig->ops->set_trigger_state(trig, false);
 		if (ret)
 			return ret;
@@ -264,7 +289,7 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
 irqreturn_t iio_pollfunc_store_time(int irq, void *p)
 {
 	struct iio_poll_func *pf = p;
-	pf->timestamp = iio_get_time_ns();
+	pf->timestamp = iio_get_time_ns(pf->indio_dev);
 	return IRQ_WAKE_THREAD;
 }
 EXPORT_SYMBOL(iio_pollfunc_store_time);
@@ -371,7 +396,7 @@ static ssize_t iio_trigger_write_current(struct device *dev,
 			return ret;
 	}
 
-	if (trig && trig->ops && trig->ops->validate_device) {
+	if (trig && trig->ops->validate_device) {
 		ret = trig->ops->validate_device(trig, indio_dev);
 		if (ret)
 			return ret;
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 734a004..c4757e6 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -356,6 +356,54 @@ void iio_channel_release(struct iio_channel *channel)
 }
 EXPORT_SYMBOL_GPL(iio_channel_release);
 
+static void devm_iio_channel_free(struct device *dev, void *res)
+{
+	struct iio_channel *channel = *(struct iio_channel **)res;
+
+	iio_channel_release(channel);
+}
+
+static int devm_iio_channel_match(struct device *dev, void *res, void *data)
+{
+	struct iio_channel **r = res;
+
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+
+	return *r == data;
+}
+
+struct iio_channel *devm_iio_channel_get(struct device *dev,
+					 const char *channel_name)
+{
+	struct iio_channel **ptr, *channel;
+
+	ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	channel = iio_channel_get(dev, channel_name);
+	if (IS_ERR(channel)) {
+		devres_free(ptr);
+		return channel;
+	}
+
+	*ptr = channel;
+	devres_add(dev, ptr);
+
+	return channel;
+}
+EXPORT_SYMBOL_GPL(devm_iio_channel_get);
+
+void devm_iio_channel_release(struct device *dev, struct iio_channel *channel)
+{
+	WARN_ON(devres_release(dev, devm_iio_channel_free,
+			       devm_iio_channel_match, channel));
+}
+EXPORT_SYMBOL_GPL(devm_iio_channel_release);
+
 struct iio_channel *iio_channel_get_all(struct device *dev)
 {
 	const char *name;
@@ -441,6 +489,42 @@ void iio_channel_release_all(struct iio_channel *channels)
 }
 EXPORT_SYMBOL_GPL(iio_channel_release_all);
 
+static void devm_iio_channel_free_all(struct device *dev, void *res)
+{
+	struct iio_channel *channels = *(struct iio_channel **)res;
+
+	iio_channel_release_all(channels);
+}
+
+struct iio_channel *devm_iio_channel_get_all(struct device *dev)
+{
+	struct iio_channel **ptr, *channels;
+
+	ptr = devres_alloc(devm_iio_channel_free_all, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	channels = iio_channel_get_all(dev);
+	if (IS_ERR(channels)) {
+		devres_free(ptr);
+		return channels;
+	}
+
+	*ptr = channels;
+	devres_add(dev, ptr);
+
+	return channels;
+}
+EXPORT_SYMBOL_GPL(devm_iio_channel_get_all);
+
+void devm_iio_channel_release_all(struct device *dev,
+				  struct iio_channel *channels)
+{
+	WARN_ON(devres_release(dev, devm_iio_channel_free_all,
+			       devm_iio_channel_match, channels));
+}
+EXPORT_SYMBOL_GPL(devm_iio_channel_release_all);
+
 static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
 	enum iio_chan_info_enum info)
 {
@@ -452,7 +536,7 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
 	if (val2 == NULL)
 		val2 = &unused;
 
-	if(!iio_channel_has_info(chan->channel, info))
+	if (!iio_channel_has_info(chan->channel, info))
 		return -EINVAL;
 
 	if (chan->indio_dev->info->read_raw_multi) {
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index cfd3df8..7c566f5 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -73,6 +73,17 @@ config BH1750
 	 To compile this driver as a module, choose M here: the module will
 	 be called bh1750.
 
+config BH1780
+	tristate "ROHM BH1780 ambient light sensor"
+	depends on I2C
+	depends on !SENSORS_BH1780
+	help
+	 Say Y here to build support for the ROHM BH1780GLI ambient
+	 light sensor.
+
+	 To compile this driver as a module, choose M here: the module will
+	 be called bh1780.
+
 config CM32181
 	depends on I2C
 	tristate "CM32181 driver"
@@ -223,6 +234,17 @@ config LTR501
 	 This driver can also be built as a module.  If so, the module
          will be called ltr501.
 
+config MAX44000
+	tristate "MAX44000 Ambient and Infrared Proximity Sensor"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	 Say Y here if you want to build support for Maxim Integrated's
+	 MAX44000 ambient and infrared proximity sensor device.
+
+	 To compile this driver as a module, choose M here:
+	 the module will be called max44000.
+
 config OPT3001
 	tristate "Texas Instruments OPT3001 Light Sensor"
 	depends on I2C
@@ -320,4 +342,14 @@ config VCNL4000
 	 To compile this driver as a module, choose M here: the
 	 module will be called vcnl4000.
 
+config VEML6070
+	tristate "VEML6070 UV A light sensor"
+	depends on I2C
+	help
+	 Say Y here if you want to build a driver for the Vishay VEML6070 UV A
+	 light sensor.
+
+	 To compile this driver as a module, choose M here: the
+	 module will be called veml6070.
+
 endmenu
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index b2c3105..6f2a3c6 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_AL3320A)		+= al3320a.o
 obj-$(CONFIG_APDS9300)		+= apds9300.o
 obj-$(CONFIG_APDS9960)		+= apds9960.o
 obj-$(CONFIG_BH1750)		+= bh1750.o
+obj-$(CONFIG_BH1780)		+= bh1780.o
 obj-$(CONFIG_CM32181)		+= cm32181.o
 obj-$(CONFIG_CM3232)		+= cm3232.o
 obj-$(CONFIG_CM3323)		+= cm3323.o
@@ -20,6 +21,7 @@ obj-$(CONFIG_ISL29125)		+= isl29125.o
 obj-$(CONFIG_JSA1212)		+= jsa1212.o
 obj-$(CONFIG_SENSORS_LM3533)	+= lm3533-als.o
 obj-$(CONFIG_LTR501)		+= ltr501.o
+obj-$(CONFIG_MAX44000)		+= max44000.o
 obj-$(CONFIG_OPT3001)		+= opt3001.o
 obj-$(CONFIG_PA12203001)	+= pa12203001.o
 obj-$(CONFIG_RPR0521)		+= rpr0521.o
@@ -30,3 +32,4 @@ obj-$(CONFIG_TCS3472)		+= tcs3472.o
 obj-$(CONFIG_TSL4531)		+= tsl4531.o
 obj-$(CONFIG_US5182D)		+= us5182d.o
 obj-$(CONFIG_VCNL4000)		+= vcnl4000.o
+obj-$(CONFIG_VEML6070)		+= veml6070.o
diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c
index 53201d9..f0b47c5 100644
--- a/drivers/iio/light/acpi-als.c
+++ b/drivers/iio/light/acpi-als.c
@@ -118,7 +118,7 @@ static void acpi_als_notify(struct acpi_device *device, u32 event)
 	struct iio_dev *indio_dev = acpi_driver_data(device);
 	struct acpi_als *als = iio_priv(indio_dev);
 	s32 *buffer = als->evt_buffer;
-	s64 time_ns = iio_get_time_ns();
+	s64 time_ns = iio_get_time_ns(indio_dev);
 	s32 val;
 	int ret;
 
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 09ad5f1..0113fc8 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -118,7 +118,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
 	struct iio_poll_func *pf = p;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct adjd_s311_data *data = iio_priv(indio_dev);
-	s64 time_ns = iio_get_time_ns();
+	s64 time_ns = iio_get_time_ns(indio_dev);
 	int i, j = 0;
 
 	int ret = adjd_s311_req_data(indio_dev);
diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c
index e1b9fa5..649b26f 100644
--- a/drivers/iio/light/apds9300.c
+++ b/drivers/iio/light/apds9300.c
@@ -396,7 +396,7 @@ static irqreturn_t apds9300_interrupt_handler(int irq, void *private)
 		       IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
 					    IIO_EV_TYPE_THRESH,
 					    IIO_EV_DIR_EITHER),
-		       iio_get_time_ns());
+		       iio_get_time_ns(dev_info));
 
 	apds9300_clear_intr(data);
 
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index 6443aad..a4304ed 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -321,8 +321,12 @@ static const struct iio_chan_spec apds9960_channels[] = {
 };
 
 /* integration time in us */
-static const int apds9960_int_time[][2] =
-	{ {28000, 246}, {100000, 219}, {200000, 182}, {700000, 0} };
+static const int apds9960_int_time[][2] = {
+	{ 28000, 246},
+	{100000, 219},
+	{200000, 182},
+	{700000,   0}
+};
 
 /* gain mapping */
 static const int apds9960_pxs_gain_map[] = {1, 2, 4, 8};
@@ -491,9 +495,10 @@ static int apds9960_read_raw(struct iio_dev *indio_dev,
 		case IIO_INTENSITY:
 			ret = regmap_bulk_read(data->regmap, chan->address,
 					       &buf, 2);
-			if (!ret)
+			if (!ret) {
 				ret = IIO_VAL_INT;
-			*val = le16_to_cpu(buf);
+				*val = le16_to_cpu(buf);
+			}
 			break;
 		default:
 			ret = -EINVAL;
@@ -802,7 +807,7 @@ static irqreturn_t apds9960_interrupt_handler(int irq, void *private)
 			       IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
 						    IIO_EV_TYPE_THRESH,
 						    IIO_EV_DIR_EITHER),
-			       iio_get_time_ns());
+			       iio_get_time_ns(indio_dev));
 		regmap_write(data->regmap, APDS9960_REG_CICLEAR, 1);
 	}
 
@@ -811,7 +816,7 @@ static irqreturn_t apds9960_interrupt_handler(int irq, void *private)
 			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
 						    IIO_EV_TYPE_THRESH,
 						    IIO_EV_DIR_EITHER),
-			       iio_get_time_ns());
+			       iio_get_time_ns(indio_dev));
 		regmap_write(data->regmap, APDS9960_REG_PICLEAR, 1);
 	}
 
diff --git b/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
new file mode 100644
index 0000000..b54dcba
--- /dev/null
+++ b/drivers/iio/light/bh1780.c
@@ -0,0 +1,299 @@
+/*
+ * ROHM 1780GLI Ambient Light Sensor Driver
+ *
+ * Copyright (C) 2016 Linaro Ltd.
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ * Loosely based on the previous BH1780 ALS misc driver
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.com>
+ */
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/bitops.h>
+
+#define BH1780_CMD_BIT		BIT(7)
+#define BH1780_REG_CONTROL	0x00
+#define BH1780_REG_PARTID	0x0A
+#define BH1780_REG_MANFID	0x0B
+#define BH1780_REG_DLOW		0x0C
+#define BH1780_REG_DHIGH	0x0D
+
+#define BH1780_REVMASK		GENMASK(3,0)
+#define BH1780_POWMASK		GENMASK(1,0)
+#define BH1780_POFF		(0x0)
+#define BH1780_PON		(0x3)
+
+/* power on settling time in ms */
+#define BH1780_PON_DELAY	2
+/* max time before value available in ms */
+#define BH1780_INTERVAL		250
+
+struct bh1780_data {
+	struct i2c_client *client;
+};
+
+static int bh1780_write(struct bh1780_data *bh1780, u8 reg, u8 val)
+{
+	int ret = i2c_smbus_write_byte_data(bh1780->client,
+					    BH1780_CMD_BIT | reg,
+					    val);
+	if (ret < 0)
+		dev_err(&bh1780->client->dev,
+			"i2c_smbus_write_byte_data failed error "
+			"%d, register %01x\n",
+			ret, reg);
+	return ret;
+}
+
+static int bh1780_read(struct bh1780_data *bh1780, u8 reg)
+{
+	int ret = i2c_smbus_read_byte_data(bh1780->client,
+					   BH1780_CMD_BIT | reg);
+	if (ret < 0)
+		dev_err(&bh1780->client->dev,
+			"i2c_smbus_read_byte_data failed error "
+			"%d, register %01x\n",
+			ret, reg);
+	return ret;
+}
+
+static int bh1780_read_word(struct bh1780_data *bh1780, u8 reg)
+{
+	int ret = i2c_smbus_read_word_data(bh1780->client,
+					   BH1780_CMD_BIT | reg);
+	if (ret < 0)
+		dev_err(&bh1780->client->dev,
+			"i2c_smbus_read_word_data failed error "
+			"%d, register %01x\n",
+			ret, reg);
+	return ret;
+}
+
+static int bh1780_debugfs_reg_access(struct iio_dev *indio_dev,
+			      unsigned int reg, unsigned int writeval,
+			      unsigned int *readval)
+{
+	struct bh1780_data *bh1780 = iio_priv(indio_dev);
+	int ret;
+
+	if (!readval)
+		return bh1780_write(bh1780, (u8)reg, (u8)writeval);
+
+	ret = bh1780_read(bh1780, (u8)reg);
+	if (ret < 0)
+		return ret;
+
+	*readval = ret;
+
+	return 0;
+}
+
+static int bh1780_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	struct bh1780_data *bh1780 = iio_priv(indio_dev);
+	int value;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_LIGHT:
+			pm_runtime_get_sync(&bh1780->client->dev);
+			value = bh1780_read_word(bh1780, BH1780_REG_DLOW);
+			if (value < 0)
+				return value;
+			pm_runtime_mark_last_busy(&bh1780->client->dev);
+			pm_runtime_put_autosuspend(&bh1780->client->dev);
+			*val = value;
+
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_INT_TIME:
+		*val = 0;
+		*val2 = BH1780_INTERVAL * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info bh1780_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = bh1780_read_raw,
+	.debugfs_reg_access = bh1780_debugfs_reg_access,
+};
+
+static const struct iio_chan_spec bh1780_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_INT_TIME)
+	}
+};
+
+static int bh1780_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int ret;
+	struct bh1780_data *bh1780;
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct iio_dev *indio_dev;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+		return -EIO;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*bh1780));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	bh1780 = iio_priv(indio_dev);
+	bh1780->client = client;
+	i2c_set_clientdata(client, indio_dev);
+
+	/* Power up the device */
+	ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON);
+	if (ret < 0)
+		return ret;
+	msleep(BH1780_PON_DELAY);
+	pm_runtime_get_noresume(&client->dev);
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_enable(&client->dev);
+
+	ret = bh1780_read(bh1780, BH1780_REG_PARTID);
+	if (ret < 0)
+		goto out_disable_pm;
+	dev_info(&client->dev,
+		 "Ambient Light Sensor, Rev : %lu\n",
+		 (ret & BH1780_REVMASK));
+
+	/*
+	 * As the device takes 250 ms to even come up with a fresh
+	 * measurement after power-on, do not shut it down unnecessarily.
+	 * Set autosuspend to a five seconds.
+	 */
+	pm_runtime_set_autosuspend_delay(&client->dev, 5000);
+	pm_runtime_use_autosuspend(&client->dev);
+	pm_runtime_put(&client->dev);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &bh1780_info;
+	indio_dev->name = "bh1780";
+	indio_dev->channels = bh1780_channels;
+	indio_dev->num_channels = ARRAY_SIZE(bh1780_channels);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto out_disable_pm;
+	return 0;
+
+out_disable_pm:
+	pm_runtime_put_noidle(&client->dev);
+	pm_runtime_disable(&client->dev);
+	return ret;
+}
+
+static int bh1780_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct bh1780_data *bh1780 = iio_priv(indio_dev);
+	int ret;
+
+	iio_device_unregister(indio_dev);
+	pm_runtime_get_sync(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+	pm_runtime_disable(&client->dev);
+	ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to power off\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bh1780_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct bh1780_data *bh1780 = iio_priv(indio_dev);
+	int ret;
+
+	ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF);
+	if (ret < 0) {
+		dev_err(dev, "failed to runtime suspend\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int bh1780_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct bh1780_data *bh1780 = iio_priv(indio_dev);
+	int ret;
+
+	ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON);
+	if (ret < 0) {
+		dev_err(dev, "failed to runtime resume\n");
+		return ret;
+	}
+
+	/* Wait for power on, then for a value to be available */
+	msleep(BH1780_PON_DELAY + BH1780_INTERVAL);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops bh1780_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+	SET_RUNTIME_PM_OPS(bh1780_runtime_suspend,
+			   bh1780_runtime_resume, NULL)
+};
+
+static const struct i2c_device_id bh1780_id[] = {
+	{ "bh1780", 0 },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, bh1780_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_bh1780_match[] = {
+	{ .compatible = "rohm,bh1780gli", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_bh1780_match);
+#endif
+
+static struct i2c_driver bh1780_driver = {
+	.probe		= bh1780_probe,
+	.remove		= bh1780_remove,
+	.id_table	= bh1780_id,
+	.driver = {
+		.name = "bh1780",
+		.pm = &bh1780_dev_pm_ops,
+		.of_match_table = of_match_ptr(of_bh1780_match),
+	},
+};
+
+module_i2c_driver(bh1780_driver);
+
+MODULE_DESCRIPTION("ROHM BH1780GLI Ambient Light Sensor Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c
index c8d7b5e..9d66e89 100644
--- a/drivers/iio/light/cm36651.c
+++ b/drivers/iio/light/cm36651.c
@@ -268,7 +268,7 @@ static irqreturn_t cm36651_irq_handler(int irq, void *data)
 				CM36651_CMD_READ_RAW_PROXIMITY,
 				IIO_EV_TYPE_THRESH, ev_dir);
 
-	iio_push_event(indio_dev, ev_code, iio_get_time_ns());
+	iio_push_event(indio_dev, ev_code, iio_get_time_ns(indio_dev));
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c
index 6d41086..6ada914 100644
--- a/drivers/iio/light/gp2ap020a00f.c
+++ b/drivers/iio/light/gp2ap020a00f.c
@@ -851,7 +851,7 @@ static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data)
 				    GP2AP020A00F_SCAN_MODE_PROXIMITY,
 				    IIO_EV_TYPE_ROC,
 				    IIO_EV_DIR_RISING),
-			       iio_get_time_ns());
+			       iio_get_time_ns(indio_dev));
 		} else {
 			iio_push_event(indio_dev,
 			       IIO_UNMOD_EVENT_CODE(
@@ -859,7 +859,7 @@ static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data)
 				    GP2AP020A00F_SCAN_MODE_PROXIMITY,
 				    IIO_EV_TYPE_ROC,
 				    IIO_EV_DIR_FALLING),
-			       iio_get_time_ns());
+			       iio_get_time_ns(indio_dev));
 		}
 	}
 
@@ -925,7 +925,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data)
 					    IIO_MOD_LIGHT_CLEAR,
 					    IIO_EV_TYPE_THRESH,
 					    IIO_EV_DIR_RISING),
-				       iio_get_time_ns());
+				       iio_get_time_ns(indio_dev));
 		}
 
 		if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &priv->flags)) {
@@ -939,7 +939,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data)
 					    IIO_MOD_LIGHT_CLEAR,
 					    IIO_EV_TYPE_THRESH,
 					    IIO_EV_DIR_FALLING),
-				       iio_get_time_ns());
+				       iio_get_time_ns(indio_dev));
 		}
 	}
 
@@ -1287,22 +1287,14 @@ static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev,
 	struct gp2ap020a00f_data *data = iio_priv(indio_dev);
 	int err = -EINVAL;
 
-	mutex_lock(&data->lock);
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		if (iio_buffer_enabled(indio_dev)) {
-			err = -EBUSY;
-			goto error_unlock;
-		}
+	if (mask == IIO_CHAN_INFO_RAW) {
+		err = iio_device_claim_direct_mode(indio_dev);
+		if (err)
+			return err;
 
 		err = gp2ap020a00f_read_channel(data, chan, val);
-		break;
+		iio_device_release_direct_mode(indio_dev);
 	}
-
-error_unlock:
-	mutex_unlock(&data->lock);
-
 	return err < 0 ? err : IIO_VAL_INT;
 }
 
diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c
index e2945a2..1d2c0c8 100644
--- a/drivers/iio/light/isl29125.c
+++ b/drivers/iio/light/isl29125.c
@@ -44,13 +44,15 @@
 #define ISL29125_MODE_B 0x3
 #define ISL29125_MODE_RGB 0x5
 
+#define ISL29125_SENSING_RANGE_0 5722   /* 375 lux full range */
+#define ISL29125_SENSING_RANGE_1 152590 /* 10k lux full range */
+
 #define ISL29125_MODE_RANGE BIT(3)
 
 #define ISL29125_STATUS_CONV BIT(1)
 
 struct isl29125_data {
 	struct i2c_client *client;
-	struct mutex lock;
 	u8 conf1;
 	u16 buffer[8]; /* 3x 16-bit, padding, 8 bytes timestamp */
 };
@@ -128,11 +130,11 @@ static int isl29125_read_raw(struct iio_dev *indio_dev,
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		if (iio_buffer_enabled(indio_dev))
-			return -EBUSY;
-		mutex_lock(&data->lock);
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret)
+			return ret;
 		ret = isl29125_read_data(data, chan->scan_index);
-		mutex_unlock(&data->lock);
+		iio_device_release_direct_mode(indio_dev);
 		if (ret < 0)
 			return ret;
 		*val = ret;
@@ -140,9 +142,9 @@ static int isl29125_read_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_SCALE:
 		*val = 0;
 		if (data->conf1 & ISL29125_MODE_RANGE)
-			*val2 = 152590; /* 10k lux full range */
+			*val2 = ISL29125_SENSING_RANGE_1; /*10k lux full range*/
 		else
-			*val2 = 5722; /* 375 lux full range */
+			*val2 = ISL29125_SENSING_RANGE_0; /*375 lux full range*/
 		return IIO_VAL_INT_PLUS_MICRO;
 	}
 	return -EINVAL;
@@ -158,9 +160,9 @@ static int isl29125_write_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_SCALE:
 		if (val != 0)
 			return -EINVAL;
-		if (val2 == 152590)
+		if (val2 == ISL29125_SENSING_RANGE_1)
 			data->conf1 |= ISL29125_MODE_RANGE;
-		else if (val2 == 5722)
+		else if (val2 == ISL29125_SENSING_RANGE_0)
 			data->conf1 &= ~ISL29125_MODE_RANGE;
 		else
 			return -EINVAL;
@@ -189,7 +191,7 @@ static irqreturn_t isl29125_trigger_handler(int irq, void *p)
 	}
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
-		iio_get_time_ns());
+		iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -259,7 +261,6 @@ static int isl29125_probe(struct i2c_client *client,
 	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->info = &isl29125_info;
diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c
index 99a6281..e8a8931 100644
--- a/drivers/iio/light/jsa1212.c
+++ b/drivers/iio/light/jsa1212.c
@@ -325,9 +325,6 @@ static int jsa1212_probe(struct i2c_client *client,
 	struct regmap *regmap;
 	int ret;
 
-	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return -EOPNOTSUPP;
-
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 	if (!indio_dev)
 		return -ENOMEM;
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index e56937c..f409c20 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -267,7 +267,7 @@ static irqreturn_t lm3533_als_isr(int irq, void *dev_id)
 					    0,
 					    IIO_EV_TYPE_THRESH,
 					    IIO_EV_DIR_EITHER),
-		       iio_get_time_ns());
+		       iio_get_time_ns(indio_dev));
 out:
 	return IRQ_HANDLED;
 }
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
index 6bf89d8..3afc53a 100644
--- a/drivers/iio/light/ltr501.c
+++ b/drivers/iio/light/ltr501.c
@@ -1256,7 +1256,8 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
 		buf[j++] = psdata & LTR501_PS_DATA_MASK;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
+	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+					   iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -1282,14 +1283,14 @@ static irqreturn_t ltr501_interrupt_handler(int irq, void *private)
 			       IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
 						    IIO_EV_TYPE_THRESH,
 						    IIO_EV_DIR_EITHER),
-			       iio_get_time_ns());
+			       iio_get_time_ns(indio_dev));
 
 	if (status & LTR501_STATUS_PS_INTR)
 		iio_push_event(indio_dev,
 			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
 						    IIO_EV_TYPE_THRESH,
 						    IIO_EV_DIR_EITHER),
-			       iio_get_time_ns());
+			       iio_get_time_ns(indio_dev));
 
 	return IRQ_HANDLED;
 }
diff --git b/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c
new file mode 100644
index 0000000..6511b20
--- /dev/null
+++ b/drivers/iio/light/max44000.c
@@ -0,0 +1,639 @@
+/*
+ * MAX44000 Ambient and Infrared Proximity Sensor
+ *
+ * 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.
+ *
+ * Data sheet: https://datasheets.maximintegrated.com/en/ds/MAX44000.pdf
+ *
+ * 7-bit I2C slave address 0x4a
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/util_macros.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>
+#include <linux/acpi.h>
+
+#define MAX44000_DRV_NAME		"max44000"
+
+/* Registers in datasheet order */
+#define MAX44000_REG_STATUS		0x00
+#define MAX44000_REG_CFG_MAIN		0x01
+#define MAX44000_REG_CFG_RX		0x02
+#define MAX44000_REG_CFG_TX		0x03
+#define MAX44000_REG_ALS_DATA_HI	0x04
+#define MAX44000_REG_ALS_DATA_LO	0x05
+#define MAX44000_REG_PRX_DATA		0x16
+#define MAX44000_REG_ALS_UPTHR_HI	0x06
+#define MAX44000_REG_ALS_UPTHR_LO	0x07
+#define MAX44000_REG_ALS_LOTHR_HI	0x08
+#define MAX44000_REG_ALS_LOTHR_LO	0x09
+#define MAX44000_REG_PST		0x0a
+#define MAX44000_REG_PRX_IND		0x0b
+#define MAX44000_REG_PRX_THR		0x0c
+#define MAX44000_REG_TRIM_GAIN_GREEN	0x0f
+#define MAX44000_REG_TRIM_GAIN_IR	0x10
+
+/* REG_CFG bits */
+#define MAX44000_CFG_ALSINTE            0x01
+#define MAX44000_CFG_PRXINTE            0x02
+#define MAX44000_CFG_MASK               0x1c
+#define MAX44000_CFG_MODE_SHUTDOWN      0x00
+#define MAX44000_CFG_MODE_ALS_GIR       0x04
+#define MAX44000_CFG_MODE_ALS_G         0x08
+#define MAX44000_CFG_MODE_ALS_IR        0x0c
+#define MAX44000_CFG_MODE_ALS_PRX       0x10
+#define MAX44000_CFG_MODE_PRX           0x14
+#define MAX44000_CFG_TRIM               0x20
+
+/*
+ * Upper 4 bits are not documented but start as 1 on powerup
+ * Setting them to 0 causes proximity to misbehave so set them to 1
+ */
+#define MAX44000_REG_CFG_RX_DEFAULT 0xf0
+
+/* REG_RX bits */
+#define MAX44000_CFG_RX_ALSTIM_MASK	0x0c
+#define MAX44000_CFG_RX_ALSTIM_SHIFT	2
+#define MAX44000_CFG_RX_ALSPGA_MASK	0x03
+#define MAX44000_CFG_RX_ALSPGA_SHIFT	0
+
+/* REG_TX bits */
+#define MAX44000_LED_CURRENT_MASK	0xf
+#define MAX44000_LED_CURRENT_MAX	11
+#define MAX44000_LED_CURRENT_DEFAULT	6
+
+#define MAX44000_ALSDATA_OVERFLOW	0x4000
+
+struct max44000_data {
+	struct mutex lock;
+	struct regmap *regmap;
+};
+
+/* Default scale is set to the minimum of 0.03125 or 1 / (1 << 5) lux */
+#define MAX44000_ALS_TO_LUX_DEFAULT_FRACTION_LOG2 5
+
+/* Scale can be multiplied by up to 128x via ALSPGA for measurement gain */
+static const int max44000_alspga_shift[] = {0, 2, 4, 7};
+#define MAX44000_ALSPGA_MAX_SHIFT 7
+
+/*
+ * Scale can be multiplied by up to 64x via ALSTIM because of lost resolution
+ *
+ * This scaling factor is hidden from userspace and instead accounted for when
+ * reading raw values from the device.
+ *
+ * This makes it possible to cleanly expose ALSPGA as IIO_CHAN_INFO_SCALE and
+ * ALSTIM as IIO_CHAN_INFO_INT_TIME without the values affecting each other.
+ *
+ * Handling this internally is also required for buffer support because the
+ * channel's scan_type can't be modified dynamically.
+ */
+static const int max44000_alstim_shift[] = {0, 2, 4, 6};
+#define MAX44000_ALSTIM_SHIFT(alstim) (2 * (alstim))
+
+/* Available integration times with pretty manual alignment: */
+static const int max44000_int_time_avail_ns_array[] = {
+	   100000000,
+	    25000000,
+	     6250000,
+	     1562500,
+};
+static const char max44000_int_time_avail_str[] =
+	"0.100 "
+	"0.025 "
+	"0.00625 "
+	"0.001625";
+
+/* Available scales (internal to ulux) with pretty manual alignment: */
+static const int max44000_scale_avail_ulux_array[] = {
+	    31250,
+	   125000,
+	   500000,
+	  4000000,
+};
+static const char max44000_scale_avail_str[] =
+	"0.03125 "
+	"0.125 "
+	"0.5 "
+	 "4";
+
+#define MAX44000_SCAN_INDEX_ALS 0
+#define MAX44000_SCAN_INDEX_PRX 1
+
+static const struct iio_chan_spec max44000_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+					    BIT(IIO_CHAN_INFO_INT_TIME),
+		.scan_index = MAX44000_SCAN_INDEX_ALS,
+		.scan_type = {
+			.sign		= 'u',
+			.realbits	= 14,
+			.storagebits	= 16,
+		}
+	},
+	{
+		.type = IIO_PROXIMITY,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.scan_index = MAX44000_SCAN_INDEX_PRX,
+		.scan_type = {
+			.sign		= 'u',
+			.realbits	= 8,
+			.storagebits	= 16,
+		}
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(2),
+	{
+		.type = IIO_CURRENT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+		.extend_name = "led",
+		.output = 1,
+		.scan_index = -1,
+	},
+};
+
+static int max44000_read_alstim(struct max44000_data *data)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(data->regmap, MAX44000_REG_CFG_RX, &val);
+	if (ret < 0)
+		return ret;
+	return (val & MAX44000_CFG_RX_ALSTIM_MASK) >> MAX44000_CFG_RX_ALSTIM_SHIFT;
+}
+
+static int max44000_write_alstim(struct max44000_data *data, int val)
+{
+	return regmap_write_bits(data->regmap, MAX44000_REG_CFG_RX,
+				 MAX44000_CFG_RX_ALSTIM_MASK,
+				 val << MAX44000_CFG_RX_ALSTIM_SHIFT);
+}
+
+static int max44000_read_alspga(struct max44000_data *data)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(data->regmap, MAX44000_REG_CFG_RX, &val);
+	if (ret < 0)
+		return ret;
+	return (val & MAX44000_CFG_RX_ALSPGA_MASK) >> MAX44000_CFG_RX_ALSPGA_SHIFT;
+}
+
+static int max44000_write_alspga(struct max44000_data *data, int val)
+{
+	return regmap_write_bits(data->regmap, MAX44000_REG_CFG_RX,
+				 MAX44000_CFG_RX_ALSPGA_MASK,
+				 val << MAX44000_CFG_RX_ALSPGA_SHIFT);
+}
+
+static int max44000_read_alsval(struct max44000_data *data)
+{
+	u16 regval;
+	int alstim, ret;
+
+	ret = regmap_bulk_read(data->regmap, MAX44000_REG_ALS_DATA_HI,
+			       &regval, sizeof(regval));
+	if (ret < 0)
+		return ret;
+	alstim = ret = max44000_read_alstim(data);
+	if (ret < 0)
+		return ret;
+
+	regval = be16_to_cpu(regval);
+
+	/*
+	 * Overflow is explained on datasheet page 17.
+	 *
+	 * It's a warning that either the G or IR channel has become saturated
+	 * and that the value in the register is likely incorrect.
+	 *
+	 * The recommendation is to change the scale (ALSPGA).
+	 * The driver just returns the max representable value.
+	 */
+	if (regval & MAX44000_ALSDATA_OVERFLOW)
+		return 0x3FFF;
+
+	return regval << MAX44000_ALSTIM_SHIFT(alstim);
+}
+
+static int max44000_write_led_current_raw(struct max44000_data *data, int val)
+{
+	/* Maybe we should clamp the value instead? */
+	if (val < 0 || val > MAX44000_LED_CURRENT_MAX)
+		return -ERANGE;
+	if (val >= 8)
+		val += 4;
+	return regmap_write_bits(data->regmap, MAX44000_REG_CFG_TX,
+				 MAX44000_LED_CURRENT_MASK, val);
+}
+
+static int max44000_read_led_current_raw(struct max44000_data *data)
+{
+	unsigned int regval;
+	int ret;
+
+	ret = regmap_read(data->regmap, MAX44000_REG_CFG_TX, &regval);
+	if (ret < 0)
+		return ret;
+	regval &= MAX44000_LED_CURRENT_MASK;
+	if (regval >= 8)
+		regval -= 4;
+	return regval;
+}
+
+static int max44000_read_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int *val, int *val2, long mask)
+{
+	struct max44000_data *data = iio_priv(indio_dev);
+	int alstim, alspga;
+	unsigned int regval;
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_LIGHT:
+			mutex_lock(&data->lock);
+			ret = max44000_read_alsval(data);
+			mutex_unlock(&data->lock);
+			if (ret < 0)
+				return ret;
+			*val = ret;
+			return IIO_VAL_INT;
+
+		case IIO_PROXIMITY:
+			mutex_lock(&data->lock);
+			ret = regmap_read(data->regmap, MAX44000_REG_PRX_DATA, &regval);
+			mutex_unlock(&data->lock);
+			if (ret < 0)
+				return ret;
+			*val = regval;
+			return IIO_VAL_INT;
+
+		case IIO_CURRENT:
+			mutex_lock(&data->lock);
+			ret = max44000_read_led_current_raw(data);
+			mutex_unlock(&data->lock);
+			if (ret < 0)
+				return ret;
+			*val = ret;
+			return IIO_VAL_INT;
+
+		default:
+			return -EINVAL;
+		}
+
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_CURRENT:
+			/* Output register is in 10s of miliamps */
+			*val = 10;
+			return IIO_VAL_INT;
+
+		case IIO_LIGHT:
+			mutex_lock(&data->lock);
+			alspga = ret = max44000_read_alspga(data);
+			mutex_unlock(&data->lock);
+			if (ret < 0)
+				return ret;
+
+			/* Avoid negative shifts */
+			*val = (1 << MAX44000_ALSPGA_MAX_SHIFT);
+			*val2 = MAX44000_ALS_TO_LUX_DEFAULT_FRACTION_LOG2
+					+ MAX44000_ALSPGA_MAX_SHIFT
+					- max44000_alspga_shift[alspga];
+			return IIO_VAL_FRACTIONAL_LOG2;
+
+		default:
+			return -EINVAL;
+		}
+
+	case IIO_CHAN_INFO_INT_TIME:
+		mutex_lock(&data->lock);
+		alstim = ret = max44000_read_alstim(data);
+		mutex_unlock(&data->lock);
+
+		if (ret < 0)
+			return ret;
+		*val = 0;
+		*val2 = max44000_int_time_avail_ns_array[alstim];
+		return IIO_VAL_INT_PLUS_NANO;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int max44000_write_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      int val, int val2, long mask)
+{
+	struct max44000_data *data = iio_priv(indio_dev);
+	int ret;
+
+	if (mask == IIO_CHAN_INFO_RAW && chan->type == IIO_CURRENT) {
+		mutex_lock(&data->lock);
+		ret = max44000_write_led_current_raw(data, val);
+		mutex_unlock(&data->lock);
+		return ret;
+	} else if (mask == IIO_CHAN_INFO_INT_TIME && chan->type == IIO_LIGHT) {
+		s64 valns = val * NSEC_PER_SEC + val2;
+		int alstim = find_closest_descending(valns,
+				max44000_int_time_avail_ns_array,
+				ARRAY_SIZE(max44000_int_time_avail_ns_array));
+		mutex_lock(&data->lock);
+		ret = max44000_write_alstim(data, alstim);
+		mutex_unlock(&data->lock);
+		return ret;
+	} else if (mask == IIO_CHAN_INFO_SCALE && chan->type == IIO_LIGHT) {
+		s64 valus = val * USEC_PER_SEC + val2;
+		int alspga = find_closest(valus,
+				max44000_scale_avail_ulux_array,
+				ARRAY_SIZE(max44000_scale_avail_ulux_array));
+		mutex_lock(&data->lock);
+		ret = max44000_write_alspga(data, alspga);
+		mutex_unlock(&data->lock);
+		return ret;
+	}
+
+	return -EINVAL;
+}
+
+static int max44000_write_raw_get_fmt(struct iio_dev *indio_dev,
+				      struct iio_chan_spec const *chan,
+				      long mask)
+{
+	if (mask == IIO_CHAN_INFO_INT_TIME && chan->type == IIO_LIGHT)
+		return IIO_VAL_INT_PLUS_NANO;
+	else if (mask == IIO_CHAN_INFO_SCALE && chan->type == IIO_LIGHT)
+		return IIO_VAL_INT_PLUS_MICRO;
+	else
+		return IIO_VAL_INT;
+}
+
+static IIO_CONST_ATTR(illuminance_integration_time_available, max44000_int_time_avail_str);
+static IIO_CONST_ATTR(illuminance_scale_available, max44000_scale_avail_str);
+
+static struct attribute *max44000_attributes[] = {
+	&iio_const_attr_illuminance_integration_time_available.dev_attr.attr,
+	&iio_const_attr_illuminance_scale_available.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group max44000_attribute_group = {
+	.attrs = max44000_attributes,
+};
+
+static const struct iio_info max44000_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= max44000_read_raw,
+	.write_raw		= max44000_write_raw,
+	.write_raw_get_fmt	= max44000_write_raw_get_fmt,
+	.attrs			= &max44000_attribute_group,
+};
+
+static bool max44000_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX44000_REG_STATUS:
+	case MAX44000_REG_CFG_MAIN:
+	case MAX44000_REG_CFG_RX:
+	case MAX44000_REG_CFG_TX:
+	case MAX44000_REG_ALS_DATA_HI:
+	case MAX44000_REG_ALS_DATA_LO:
+	case MAX44000_REG_PRX_DATA:
+	case MAX44000_REG_ALS_UPTHR_HI:
+	case MAX44000_REG_ALS_UPTHR_LO:
+	case MAX44000_REG_ALS_LOTHR_HI:
+	case MAX44000_REG_ALS_LOTHR_LO:
+	case MAX44000_REG_PST:
+	case MAX44000_REG_PRX_IND:
+	case MAX44000_REG_PRX_THR:
+	case MAX44000_REG_TRIM_GAIN_GREEN:
+	case MAX44000_REG_TRIM_GAIN_IR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max44000_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX44000_REG_CFG_MAIN:
+	case MAX44000_REG_CFG_RX:
+	case MAX44000_REG_CFG_TX:
+	case MAX44000_REG_ALS_UPTHR_HI:
+	case MAX44000_REG_ALS_UPTHR_LO:
+	case MAX44000_REG_ALS_LOTHR_HI:
+	case MAX44000_REG_ALS_LOTHR_LO:
+	case MAX44000_REG_PST:
+	case MAX44000_REG_PRX_IND:
+	case MAX44000_REG_PRX_THR:
+	case MAX44000_REG_TRIM_GAIN_GREEN:
+	case MAX44000_REG_TRIM_GAIN_IR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max44000_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MAX44000_REG_STATUS:
+	case MAX44000_REG_ALS_DATA_HI:
+	case MAX44000_REG_ALS_DATA_LO:
+	case MAX44000_REG_PRX_DATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool max44000_precious_reg(struct device *dev, unsigned int reg)
+{
+	return reg == MAX44000_REG_STATUS;
+}
+
+static const struct regmap_config max44000_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+
+	.max_register	= MAX44000_REG_PRX_DATA,
+	.readable_reg	= max44000_readable_reg,
+	.writeable_reg	= max44000_writeable_reg,
+	.volatile_reg	= max44000_volatile_reg,
+	.precious_reg	= max44000_precious_reg,
+
+	.use_single_rw	= 1,
+	.cache_type	= REGCACHE_RBTREE,
+};
+
+static irqreturn_t max44000_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct max44000_data *data = iio_priv(indio_dev);
+	u16 buf[8]; /* 2x u16 + padding + 8 bytes timestamp */
+	int index = 0;
+	unsigned int regval;
+	int ret;
+
+	mutex_lock(&data->lock);
+	if (test_bit(MAX44000_SCAN_INDEX_ALS, indio_dev->active_scan_mask)) {
+		ret = max44000_read_alsval(data);
+		if (ret < 0)
+			goto out_unlock;
+		buf[index++] = ret;
+	}
+	if (test_bit(MAX44000_SCAN_INDEX_PRX, indio_dev->active_scan_mask)) {
+		ret = regmap_read(data->regmap, MAX44000_REG_PRX_DATA, &regval);
+		if (ret < 0)
+			goto out_unlock;
+		buf[index] = regval;
+	}
+	mutex_unlock(&data->lock);
+
+	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+					   iio_get_time_ns(indio_dev));
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+
+out_unlock:
+	mutex_unlock(&data->lock);
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+}
+
+static int max44000_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct max44000_data *data;
+	struct iio_dev *indio_dev;
+	int ret, reg;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+	data = iio_priv(indio_dev);
+	data->regmap = devm_regmap_init_i2c(client, &max44000_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		dev_err(&client->dev, "regmap_init failed!\n");
+		return PTR_ERR(data->regmap);
+	}
+
+	i2c_set_clientdata(client, indio_dev);
+	mutex_init(&data->lock);
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &max44000_info;
+	indio_dev->name = MAX44000_DRV_NAME;
+	indio_dev->channels = max44000_channels;
+	indio_dev->num_channels = ARRAY_SIZE(max44000_channels);
+
+	/*
+	 * The device doesn't have a reset function so we just clear some
+	 * important bits at probe time to ensure sane operation.
+	 *
+	 * Since we don't support interrupts/events the threshold values are
+	 * not important. We also don't touch trim values.
+	 */
+
+	/* Reset ALS scaling bits */
+	ret = regmap_write(data->regmap, MAX44000_REG_CFG_RX,
+			   MAX44000_REG_CFG_RX_DEFAULT);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to write default CFG_RX: %d\n",
+			ret);
+		return ret;
+	}
+
+	/*
+	 * By default the LED pulse used for the proximity sensor is disabled.
+	 * Set a middle value so that we get some sort of valid data by default.
+	 */
+	ret = max44000_write_led_current_raw(data, MAX44000_LED_CURRENT_DEFAULT);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to write init config: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset CFG bits to ALS_PRX mode which allows easy reading of both values. */
+	reg = MAX44000_CFG_TRIM | MAX44000_CFG_MODE_ALS_PRX;
+	ret = regmap_write(data->regmap, MAX44000_REG_CFG_MAIN, reg);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to write init config: %d\n", ret);
+		return ret;
+	}
+
+	/* Read status at least once to clear any stale interrupt bits. */
+	ret = regmap_read(data->regmap, MAX44000_REG_STATUS, &reg);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to read init status: %d\n", ret);
+		return ret;
+	}
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL, max44000_trigger_handler, NULL);
+	if (ret < 0) {
+		dev_err(&client->dev, "iio triggered buffer setup failed\n");
+		return ret;
+	}
+
+	return iio_device_register(indio_dev);
+}
+
+static int max44000_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 max44000_id[] = {
+	{"max44000", 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max44000_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max44000_acpi_match[] = {
+	{"MAX44000", 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, max44000_acpi_match);
+#endif
+
+static struct i2c_driver max44000_driver = {
+	.driver = {
+		.name	= MAX44000_DRV_NAME,
+		.acpi_match_table = ACPI_PTR(max44000_acpi_match),
+	},
+	.probe		= max44000_probe,
+	.remove		= max44000_remove,
+	.id_table	= max44000_id,
+};
+
+module_i2c_driver(max44000_driver);
+
+MODULE_AUTHOR("Crestez Dan Leonard <leonard.crestez@intel.com>");
+MODULE_DESCRIPTION("MAX44000 Ambient and Infrared Proximity Sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
index b776c8e..78c9b3a 100644
--- a/drivers/iio/light/opt3001.c
+++ b/drivers/iio/light/opt3001.c
@@ -713,13 +713,13 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
 					IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
 							IIO_EV_TYPE_THRESH,
 							IIO_EV_DIR_RISING),
-					iio_get_time_ns());
+					iio_get_time_ns(iio));
 		if (ret & OPT3001_CONFIGURATION_FL)
 			iio_push_event(iio,
 					IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
 							IIO_EV_TYPE_THRESH,
 							IIO_EV_DIR_FALLING),
-					iio_get_time_ns());
+					iio_get_time_ns(iio));
 	} else if (ret & OPT3001_CONFIGURATION_CRF) {
 		ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT);
 		if (ret < 0) {
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index 42d334b..45cf8b0 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
-#include <linux/gpio/consumer.h>
 #include <linux/iio/events.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -529,7 +528,7 @@ static irqreturn_t stk3310_irq_handler(int irq, void *private)
 	struct iio_dev *indio_dev = private;
 	struct stk3310_data *data = iio_priv(indio_dev);
 
-	data->timestamp = iio_get_time_ns();
+	data->timestamp = iio_get_time_ns(indio_dev);
 
 	return IRQ_WAKE_THREAD;
 }
diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c
index f90f8c5..a795afb 100644
--- a/drivers/iio/light/tcs3414.c
+++ b/drivers/iio/light/tcs3414.c
@@ -53,7 +53,6 @@
 
 struct tcs3414_data {
 	struct i2c_client *client;
-	struct mutex lock;
 	u8 control;
 	u8 gain;
 	u8 timing;
@@ -134,16 +133,16 @@ static int tcs3414_read_raw(struct iio_dev *indio_dev,
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		if (iio_buffer_enabled(indio_dev))
-			return -EBUSY;
-		mutex_lock(&data->lock);
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret)
+			return ret;
 		ret = tcs3414_req_data(data);
 		if (ret < 0) {
-			mutex_unlock(&data->lock);
+			iio_device_release_direct_mode(indio_dev);
 			return ret;
 		}
 		ret = i2c_smbus_read_word_data(data->client, chan->address);
-		mutex_unlock(&data->lock);
+		iio_device_release_direct_mode(indio_dev);
 		if (ret < 0)
 			return ret;
 		*val = ret;
@@ -217,7 +216,7 @@ static irqreturn_t tcs3414_trigger_handler(int irq, void *p)
 	}
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
-		iio_get_time_ns());
+		iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -288,7 +287,6 @@ static int tcs3414_probe(struct i2c_client *client,
 	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->info = &tcs3414_info;
diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c
index 1b530bf..3aa71e3 100644
--- a/drivers/iio/light/tcs3472.c
+++ b/drivers/iio/light/tcs3472.c
@@ -52,7 +52,6 @@
 
 struct tcs3472_data {
 	struct i2c_client *client;
-	struct mutex lock;
 	u8 enable;
 	u8 control;
 	u8 atime;
@@ -117,17 +116,16 @@ static int tcs3472_read_raw(struct iio_dev *indio_dev,
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		if (iio_buffer_enabled(indio_dev))
-			return -EBUSY;
-
-		mutex_lock(&data->lock);
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret)
+			return ret;
 		ret = tcs3472_req_data(data);
 		if (ret < 0) {
-			mutex_unlock(&data->lock);
+			iio_device_release_direct_mode(indio_dev);
 			return ret;
 		}
 		ret = i2c_smbus_read_word_data(data->client, chan->address);
-		mutex_unlock(&data->lock);
+		iio_device_release_direct_mode(indio_dev);
 		if (ret < 0)
 			return ret;
 		*val = ret;
@@ -204,7 +202,7 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p)
 	}
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
-		iio_get_time_ns());
+		iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -263,7 +261,6 @@ static int tcs3472_probe(struct i2c_client *client,
 	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->info = &tcs3472_info;
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index 12731d6..04598ae 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -630,7 +630,7 @@ static irqreturn_t tsl2563_event_handler(int irq, void *private)
 					    0,
 					    IIO_EV_TYPE_THRESH,
 					    IIO_EV_DIR_EITHER),
-		       iio_get_time_ns());
+		       iio_get_time_ns(dev_info));
 
 	/* clear the interrupt and push the event */
 	i2c_smbus_write_byte(chip->client, TSL2563_CMD | TSL2563_CLEARINT);
@@ -806,8 +806,7 @@ static int tsl2563_probe(struct i2c_client *client,
 	return 0;
 
 fail:
-	cancel_delayed_work(&chip->poweroff_work);
-	flush_scheduled_work();
+	cancel_delayed_work_sync(&chip->poweroff_work);
 	return err;
 }
 
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index 45bc2f7..20c40f7 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -833,7 +833,7 @@ static irqreturn_t us5182d_irq_thread_handler(int irq, void *private)
 	dir = ret & US5182D_CFG0_PROX ? IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
 	ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, IIO_EV_TYPE_THRESH, dir);
 
-	iio_push_event(indio_dev, ev, iio_get_time_ns());
+	iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));
 
 	ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0,
 					ret & ~US5182D_CFG0_PX_IRQ);
diff --git b/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c
new file mode 100644
index 0000000..bc1c4cb
--- /dev/null
+++ b/drivers/iio/light/veml6070.c
@@ -0,0 +1,218 @@
+/*
+ * veml6070.c - Support for Vishay VEML6070 UV A light sensor
+ *
+ * Copyright 2016 Peter Meerwald-Stadler <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.
+ *
+ * IIO driver for VEML6070 (7-bit I2C slave addresses 0x38 and 0x39)
+ *
+ * TODO: integration time, ACK signal
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define VEML6070_DRV_NAME "veml6070"
+
+#define VEML6070_ADDR_CONFIG_DATA_MSB 0x38 /* read: MSB data, write: config */
+#define VEML6070_ADDR_DATA_LSB	0x39 /* LSB data */
+
+#define VEML6070_COMMAND_ACK	BIT(5) /* raise interrupt when over threshold */
+#define VEML6070_COMMAND_IT	GENMASK(3, 2) /* bit mask integration time */
+#define VEML6070_COMMAND_RSRVD	BIT(1) /* reserved, set to 1 */
+#define VEML6070_COMMAND_SD	BIT(0) /* shutdown mode when set */
+
+#define VEML6070_IT_10	0x04 /* integration time 1x */
+
+struct veml6070_data {
+	struct i2c_client *client1;
+	struct i2c_client *client2;
+	u8 config;
+	struct mutex lock;
+};
+
+static int veml6070_read(struct veml6070_data *data)
+{
+	int ret;
+	u8 msb, lsb;
+
+	mutex_lock(&data->lock);
+
+	/* disable shutdown */
+	ret = i2c_smbus_write_byte(data->client1,
+	    data->config & ~VEML6070_COMMAND_SD);
+	if (ret < 0)
+		goto out;
+
+	msleep(125 + 10); /* measurement takes up to 125 ms for IT 1x */
+
+	ret = i2c_smbus_read_byte(data->client2); /* read MSB, address 0x39 */
+	if (ret < 0)
+		goto out;
+	msb = ret;
+
+	ret = i2c_smbus_read_byte(data->client1); /* read LSB, address 0x38 */
+	if (ret < 0)
+		goto out;
+	lsb = ret;
+
+	/* shutdown again */
+	ret = i2c_smbus_write_byte(data->client1, data->config);
+	if (ret < 0)
+		goto out;
+
+	ret = (msb << 8) | lsb;
+
+out:
+	mutex_unlock(&data->lock);
+	return ret;
+}
+
+static const struct iio_chan_spec veml6070_channels[] = {
+	{
+		.type = IIO_INTENSITY,
+		.modified = 1,
+		.channel2 = IIO_MOD_LIGHT_UV,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+	},
+	{
+		.type = IIO_UVINDEX,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+	}
+};
+
+static int veml6070_to_uv_index(unsigned val)
+{
+	/*
+	 * conversion of raw UV intensity values to UV index depends on
+	 * integration time (IT) and value of the resistor connected to
+	 * the RSET pin (default: 270 KOhm)
+	 */
+	unsigned uvi[11] = {
+		187, 373, 560, /* low */
+		746, 933, 1120, /* moderate */
+		1308, 1494, /* high */
+		1681, 1868, 2054}; /* very high */
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(uvi); i++)
+		if (val <= uvi[i])
+			return i;
+
+	return 11; /* extreme */
+}
+
+static int veml6070_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct veml6070_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_PROCESSED:
+		ret = veml6070_read(data);
+		if (ret < 0)
+			return ret;
+		if (mask == IIO_CHAN_INFO_PROCESSED)
+			*val = veml6070_to_uv_index(ret);
+		else
+			*val = ret;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info veml6070_info = {
+	.read_raw = veml6070_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int veml6070_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct veml6070_data *data;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	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->client1 = client;
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &veml6070_info;
+	indio_dev->channels = veml6070_channels;
+	indio_dev->num_channels = ARRAY_SIZE(veml6070_channels);
+	indio_dev->name = VEML6070_DRV_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	data->client2 = i2c_new_dummy(client->adapter, VEML6070_ADDR_DATA_LSB);
+	if (!data->client2) {
+		dev_err(&client->dev, "i2c device for second chip address failed\n");
+		return -ENODEV;
+	}
+
+	data->config = VEML6070_IT_10 | VEML6070_COMMAND_RSRVD |
+		VEML6070_COMMAND_SD;
+	ret = i2c_smbus_write_byte(data->client1, data->config);
+	if (ret < 0)
+		goto fail;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		goto fail;
+
+	return ret;
+
+fail:
+	i2c_unregister_device(data->client2);
+	return ret;
+}
+
+static int veml6070_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct veml6070_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	i2c_unregister_device(data->client2);
+
+	return 0;
+}
+
+static const struct i2c_device_id veml6070_id[] = {
+	{ "veml6070", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, veml6070_id);
+
+static struct i2c_driver veml6070_driver = {
+	.driver = {
+		.name   = VEML6070_DRV_NAME,
+	},
+	.probe  = veml6070_probe,
+	.remove  = veml6070_remove,
+	.id_table = veml6070_id,
+};
+
+module_i2c_driver(veml6070_driver);
+
+MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("Vishay VEML6070 UV A light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index 021dc53..1f842ab 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -9,6 +9,8 @@ config AK8975
 	tristate "Asahi Kasei AK 3-Axis Magnetometer"
 	depends on I2C
 	depends on GPIOLIB || COMPILE_TEST
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
 	  AK09911 or AK09912 3-Axis Magnetometer.
@@ -25,22 +27,43 @@ config AK09911
 	  Deprecated: AK09911 is now supported by AK8975 driver.
 
 config BMC150_MAGN
-	tristate "Bosch BMC150 Magnetometer Driver"
-	depends on I2C
-	select REGMAP_I2C
+	tristate
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
+
+config BMC150_MAGN_I2C
+	tristate "Bosch BMC150 I2C Magnetometer Driver"
+	depends on I2C
+	select BMC150_MAGN
+	select REGMAP_I2C
 	help
-	  Say yes here to build support for the BMC150 magnetometer.
+	  Say yes here to build support for the BMC150 magnetometer with
+	  I2C interface.
 
-	  Currently this only supports the device via an i2c interface.
+	  This is a combo module with both accelerometer and magnetometer.
+	  This driver is only implementing magnetometer part, which has
+	  its own address and register map.
+
+	  This driver also supports I2C Bosch BMC156 and BMM150 chips.
+	  To compile this driver as a module, choose M here: the module will be
+	  called bmc150_magn_i2c.
+
+config BMC150_MAGN_SPI
+	tristate "Bosch BMC150 SPI Magnetometer Driver"
+	depends on SPI
+	select BMC150_MAGN
+	select REGMAP_SPI
+	help
+	  Say yes here to build support for the BMC150 magnetometer with
+	  SPI interface.
 
 	  This is a combo module with both accelerometer and magnetometer.
 	  This driver is only implementing magnetometer part, which has
 	  its own address and register map.
 
+	  This driver also supports SPI Bosch BMC156 and BMM150 chips.
 	  To compile this driver as a module, choose M here: the module will be
-	  called bmc150_magn.
+	  called bmc150_magn_spi.
 
 config MAG3110
 	tristate "Freescale MAG3110 3-Axis Magnetometer"
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index dd03fe5..92a745c 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -5,6 +5,9 @@
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AK8975)	+= ak8975.o
 obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
+obj-$(CONFIG_BMC150_MAGN_I2C) += bmc150_magn_i2c.o
+obj-$(CONFIG_BMC150_MAGN_SPI) += bmc150_magn_spi.o
+
 obj-$(CONFIG_MAG3110)	+= mag3110.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
 obj-$(CONFIG_MMC35240)	+= mmc35240.o
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index 0e931a9..af8606c 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -32,9 +32,18 @@
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 #include <linux/acpi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include <linux/iio/magnetometer/ak8975.h>
+
 /*
  * Register definitions, as well as various shifts and masks to get at the
  * individual fields of the registers.
@@ -361,7 +370,6 @@ static const struct ak_def ak_def_array[AK_MAX_TYPE] = {
 struct ak8975_data {
 	struct i2c_client	*client;
 	const struct ak_def	*def;
-	struct attribute_group	attrs;
 	struct mutex		lock;
 	u8			asa[3];
 	long			raw_to_gauss[3];
@@ -370,8 +378,44 @@ struct ak8975_data {
 	wait_queue_head_t	data_ready_queue;
 	unsigned long		flags;
 	u8			cntl_cache;
+	struct iio_mount_matrix orientation;
+	struct regulator	*vdd;
+	struct regulator	*vid;
 };
 
+/* Enable attached power regulator if any. */
+static int ak8975_power_on(const struct ak8975_data *data)
+{
+	int ret;
+
+	ret = regulator_enable(data->vdd);
+	if (ret) {
+		dev_warn(&data->client->dev,
+			 "Failed to enable specified Vdd supply\n");
+		return ret;
+	}
+	ret = regulator_enable(data->vid);
+	if (ret) {
+		dev_warn(&data->client->dev,
+			 "Failed to enable specified Vid supply\n");
+		return ret;
+	}
+	/*
+	 * According to the datasheet the power supply rise time i 200us
+	 * and the minimum wait time before mode setting is 100us, in
+	 * total 300 us. Add some margin and say minimum 500us here.
+	 */
+	usleep_range(500, 1000);
+	return 0;
+}
+
+/* Disable attached power regulator if any. */
+static void ak8975_power_off(const struct ak8975_data *data)
+{
+	regulator_disable(data->vid);
+	regulator_disable(data->vdd);
+}
+
 /*
  * Return 0 if the i2c device is the one we expect.
  * return a negative error number otherwise
@@ -390,8 +434,8 @@ static int ak8975_who_i_am(struct i2c_client *client,
 	 * AK8975   |  DEVICE_ID |  NA
 	 * AK8963   |  DEVICE_ID |  NA
 	 */
-	ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
-					    2, wia_val);
+	ret = i2c_smbus_read_i2c_block_data_or_emulated(
+			client, AK09912_REG_WIA1, 2, wia_val);
 	if (ret < 0) {
 		dev_err(&client->dev, "Error reading WIA\n");
 		return ret;
@@ -503,9 +547,9 @@ static int ak8975_setup(struct i2c_client *client)
 	}
 
 	/* Get asa data and store in the device data. */
-	ret = i2c_smbus_read_i2c_block_data(client,
-					    data->def->ctrl_regs[ASA_BASE],
-					    3, data->asa);
+	ret = i2c_smbus_read_i2c_block_data_or_emulated(
+			client, data->def->ctrl_regs[ASA_BASE],
+			3, data->asa);
 	if (ret < 0) {
 		dev_err(&client->dev, "Not able to read asa data\n");
 		return ret;
@@ -601,22 +645,15 @@ static int wait_conversion_complete_interrupt(struct ak8975_data *data)
 	return ret > 0 ? 0 : -ETIME;
 }
 
-/*
- * Emits the raw flux value for the x, y, or z axis.
- */
-static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
+static int ak8975_start_read_axis(struct ak8975_data *data,
+				  const struct i2c_client *client)
 {
-	struct ak8975_data *data = iio_priv(indio_dev);
-	struct i2c_client *client = data->client;
-	int ret;
-
-	mutex_lock(&data->lock);
-
 	/* Set up the device for taking a sample. */
-	ret = ak8975_set_mode(data, MODE_ONCE);
+	int ret = ak8975_set_mode(data, MODE_ONCE);
+
 	if (ret < 0) {
 		dev_err(&client->dev, "Error in setting operating mode\n");
-		goto exit;
+		return ret;
 	}
 
 	/* Wait for the conversion to complete. */
@@ -627,7 +664,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 	else
 		ret = wait_conversion_complete_polled(data);
 	if (ret < 0)
-		goto exit;
+		return ret;
 
 	/* This will be executed only for non-interrupt based waiting case */
 	if (ret & data->def->ctrl_masks[ST1_DRDY]) {
@@ -635,32 +672,54 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 					       data->def->ctrl_regs[ST2]);
 		if (ret < 0) {
 			dev_err(&client->dev, "Error in reading ST2\n");
-			goto exit;
+			return ret;
 		}
 		if (ret & (data->def->ctrl_masks[ST2_DERR] |
 			   data->def->ctrl_masks[ST2_HOFL])) {
 			dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
-			ret = -EINVAL;
-			goto exit;
+			return -EINVAL;
 		}
 	}
 
-	/* Read the flux value from the appropriate register
-	   (the register is specified in the iio device attributes). */
-	ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
-	if (ret < 0) {
-		dev_err(&client->dev, "Read axis data fails\n");
+	return 0;
+}
+
+/* Retrieve raw flux value for one of the x, y, or z axis.  */
+static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
+{
+	struct ak8975_data *data = iio_priv(indio_dev);
+	const struct i2c_client *client = data->client;
+	const struct ak_def *def = data->def;
+	u16 buff;
+	int ret;
+
+	pm_runtime_get_sync(&data->client->dev);
+
+	mutex_lock(&data->lock);
+
+	ret = ak8975_start_read_axis(data, client);
+	if (ret)
+		goto exit;
+
+	ret = i2c_smbus_read_i2c_block_data_or_emulated(
+			client, def->data_regs[index],
+			sizeof(buff), (u8*)&buff);
+	if (ret < 0)
 		goto exit;
-	}
 
 	mutex_unlock(&data->lock);
 
-	/* Clamp to valid range. */
-	*val = clamp_t(s16, ret, -data->def->range, data->def->range);
+	pm_runtime_mark_last_busy(&data->client->dev);
+	pm_runtime_put_autosuspend(&data->client->dev);
+
+	/* Swap bytes and convert to valid range. */
+	buff = le16_to_cpu(buff);
+	*val = clamp_t(s16, buff, -def->range, def->range);
 	return IIO_VAL_INT;
 
 exit:
 	mutex_unlock(&data->lock);
+	dev_err(&client->dev, "Error in reading axis\n");
 	return ret;
 }
 
@@ -682,6 +741,18 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
 	return -EINVAL;
 }
 
+static const struct iio_mount_matrix *
+ak8975_get_mount_matrix(const struct iio_dev *indio_dev,
+			const struct iio_chan_spec *chan)
+{
+	return &((struct ak8975_data *)iio_priv(indio_dev))->orientation;
+}
+
+static const struct iio_chan_spec_ext_info ak8975_ext_info[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, ak8975_get_mount_matrix),
+	{ },
+};
+
 #define AK8975_CHANNEL(axis, index)					\
 	{								\
 		.type = IIO_MAGN,					\
@@ -690,12 +761,23 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
 			     BIT(IIO_CHAN_INFO_SCALE),			\
 		.address = index,					\
+		.scan_index = index,					\
+		.scan_type = {						\
+			.sign = 's',					\
+			.realbits = 16,					\
+			.storagebits = 16,				\
+			.endianness = IIO_CPU				\
+		},							\
+		.ext_info = ak8975_ext_info,				\
 	}
 
 static const struct iio_chan_spec ak8975_channels[] = {
 	AK8975_CHANNEL(X, 0), AK8975_CHANNEL(Y, 1), AK8975_CHANNEL(Z, 2),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
+static const unsigned long ak8975_scan_masks[] = { 0x7, 0 };
+
 static const struct iio_info ak8975_info = {
 	.read_raw = &ak8975_read_raw,
 	.driver_module = THIS_MODULE,
@@ -724,6 +806,57 @@ static const char *ak8975_match_acpi_device(struct device *dev,
 	return dev_name(dev);
 }
 
+static void ak8975_fill_buffer(struct iio_dev *indio_dev)
+{
+	struct ak8975_data *data = iio_priv(indio_dev);
+	const struct i2c_client *client = data->client;
+	const struct ak_def *def = data->def;
+	int ret;
+	s16 buff[8]; /* 3 x 16 bits axis values + 1 aligned 64 bits timestamp */
+
+	mutex_lock(&data->lock);
+
+	ret = ak8975_start_read_axis(data, client);
+	if (ret)
+		goto unlock;
+
+	/*
+	 * For each axis, read the flux value from the appropriate register
+	 * (the register is specified in the iio device attributes).
+	 */
+	ret = i2c_smbus_read_i2c_block_data_or_emulated(client,
+							def->data_regs[0],
+							3 * sizeof(buff[0]),
+							(u8 *)buff);
+	if (ret < 0)
+		goto unlock;
+
+	mutex_unlock(&data->lock);
+
+	/* Clamp to valid range. */
+	buff[0] = clamp_t(s16, le16_to_cpu(buff[0]), -def->range, def->range);
+	buff[1] = clamp_t(s16, le16_to_cpu(buff[1]), -def->range, def->range);
+	buff[2] = clamp_t(s16, le16_to_cpu(buff[2]), -def->range, def->range);
+
+	iio_push_to_buffers_with_timestamp(indio_dev, buff,
+					   iio_get_time_ns(indio_dev));
+	return;
+
+unlock:
+	mutex_unlock(&data->lock);
+	dev_err(&client->dev, "Error in reading axes block\n");
+}
+
+static irqreturn_t ak8975_handle_trigger(int irq, void *p)
+{
+	const struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+
+	ak8975_fill_buffer(indio_dev);
+	iio_trigger_notify_done(indio_dev->trig);
+	return IRQ_HANDLED;
+}
+
 static int ak8975_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
@@ -733,10 +866,12 @@ static int ak8975_probe(struct i2c_client *client,
 	int err;
 	const char *name = NULL;
 	enum asahi_compass_chipset chipset = AK_MAX_TYPE;
+	const struct ak8975_platform_data *pdata =
+		dev_get_platdata(&client->dev);
 
 	/* Grab and set up the supplied GPIO. */
-	if (client->dev.platform_data)
-		eoc_gpio = *(int *)(client->dev.platform_data);
+	if (pdata)
+		eoc_gpio = pdata->eoc_gpio;
 	else if (client->dev.of_node)
 		eoc_gpio = of_get_gpio(client->dev.of_node, 0);
 	else
@@ -770,13 +905,24 @@ static int ak8975_probe(struct i2c_client *client,
 	data->eoc_gpio = eoc_gpio;
 	data->eoc_irq = 0;
 
+	if (!pdata) {
+		err = of_iio_read_mount_matrix(&client->dev,
+					       "mount-matrix",
+					       &data->orientation);
+		if (err)
+			return err;
+	} else
+		data->orientation = pdata->orientation;
+
 	/* id will be NULL when enumerated via ACPI */
 	if (id) {
 		chipset = (enum asahi_compass_chipset)(id->driver_data);
 		name = id->name;
-	} else if (ACPI_HANDLE(&client->dev))
+	} else if (ACPI_HANDLE(&client->dev)) {
 		name = ak8975_match_acpi_device(&client->dev, &chipset);
-	else
+		if (!name)
+			return -ENODEV;
+	} else
 		return -ENOSYS;
 
 	if (chipset >= AK_MAX_TYPE) {
@@ -786,10 +932,23 @@ static int ak8975_probe(struct i2c_client *client,
 	}
 
 	data->def = &ak_def_array[chipset];
+
+	/* Fetch the regulators */
+	data->vdd = devm_regulator_get(&client->dev, "vdd");
+	if (IS_ERR(data->vdd))
+		return PTR_ERR(data->vdd);
+	data->vid = devm_regulator_get(&client->dev, "vid");
+	if (IS_ERR(data->vid))
+		return PTR_ERR(data->vid);
+
+	err = ak8975_power_on(data);
+	if (err)
+		return err;
+
 	err = ak8975_who_i_am(client, data->def->type);
 	if (err < 0) {
 		dev_err(&client->dev, "Unexpected device\n");
-		return err;
+		goto power_off;
 	}
 	dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
 
@@ -797,7 +956,7 @@ static int ak8975_probe(struct i2c_client *client,
 	err = ak8975_setup(client);
 	if (err < 0) {
 		dev_err(&client->dev, "%s initialization fails\n", name);
-		return err;
+		goto power_off;
 	}
 
 	mutex_init(&data->lock);
@@ -805,11 +964,110 @@ static int ak8975_probe(struct i2c_client *client,
 	indio_dev->channels = ak8975_channels;
 	indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
 	indio_dev->info = &ak8975_info;
+	indio_dev->available_scan_masks = ak8975_scan_masks;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->name = name;
-	return devm_iio_device_register(&client->dev, indio_dev);
+
+	err = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger,
+					 NULL);
+	if (err) {
+		dev_err(&client->dev, "triggered buffer setup failed\n");
+		goto power_off;
+	}
+
+	err = iio_device_register(indio_dev);
+	if (err) {
+		dev_err(&client->dev, "device register failed\n");
+		goto cleanup_buffer;
+	}
+
+	/* Enable runtime PM */
+	pm_runtime_get_noresume(&client->dev);
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_enable(&client->dev);
+	/*
+	 * The device comes online in 500us, so add two orders of magnitude
+	 * of delay before autosuspending: 50 ms.
+	 */
+	pm_runtime_set_autosuspend_delay(&client->dev, 50);
+	pm_runtime_use_autosuspend(&client->dev);
+	pm_runtime_put(&client->dev);
+
+	return 0;
+
+cleanup_buffer:
+	iio_triggered_buffer_cleanup(indio_dev);
+power_off:
+	ak8975_power_off(data);
+	return err;
+}
+
+static int ak8975_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct ak8975_data *data = iio_priv(indio_dev);
+
+	pm_runtime_get_sync(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+	pm_runtime_disable(&client->dev);
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	ak8975_set_mode(data, POWER_DOWN);
+	ak8975_power_off(data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ak8975_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct ak8975_data *data = iio_priv(indio_dev);
+	int ret;
+
+	/* Set the device in power down if it wasn't already */
+	ret = ak8975_set_mode(data, POWER_DOWN);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error in setting power-down mode\n");
+		return ret;
+	}
+	/* Next cut the regulators */
+	ak8975_power_off(data);
+
+	return 0;
 }
 
+static int ak8975_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct ak8975_data *data = iio_priv(indio_dev);
+	int ret;
+
+	/* Take up the regulators */
+	ak8975_power_on(data);
+	/*
+	 * We come up in powered down mode, the reading routines will
+	 * put us in the mode to read values later.
+	 */
+	ret = ak8975_set_mode(data, POWER_DOWN);
+	if (ret < 0) {
+		dev_err(&client->dev, "Error in setting power-down mode\n");
+		return ret;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops ak8975_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+	SET_RUNTIME_PM_OPS(ak8975_runtime_suspend,
+			   ak8975_runtime_resume, NULL)
+};
+
 static const struct i2c_device_id ak8975_id[] = {
 	{"ak8975", AK8975},
 	{"ak8963", AK8963},
@@ -837,10 +1095,12 @@ MODULE_DEVICE_TABLE(of, ak8975_of_match);
 static struct i2c_driver ak8975_driver = {
 	.driver = {
 		.name	= "ak8975",
+		.pm = &ak8975_dev_pm_ops,
 		.of_match_table = of_match_ptr(ak8975_of_match),
 		.acpi_match_table = ACPI_PTR(ak_acpi_match),
 	},
 	.probe		= ak8975_probe,
+	.remove		= ak8975_remove,
 	.id_table	= ak8975_id,
 };
 module_i2c_driver(ak8975_driver);
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index ffcb75e..d104fb8 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/iio/iio.h>
@@ -35,6 +34,8 @@
 #include <linux/iio/triggered_buffer.h>
 #include <linux/regmap.h>
 
+#include "bmc150_magn.h"
+
 #define BMC150_MAGN_DRV_NAME			"bmc150_magn"
 #define BMC150_MAGN_IRQ_NAME			"bmc150_magn_event"
 
@@ -135,7 +136,7 @@ struct bmc150_magn_trim_regs {
 } __packed;
 
 struct bmc150_magn_data {
-	struct i2c_client *client;
+	struct device *dev;
 	/*
 	 * 1. Protect this structure.
 	 * 2. Serialize sequences that power on/off the device and access HW.
@@ -147,6 +148,7 @@ struct bmc150_magn_data {
 	struct iio_trigger *dready_trig;
 	bool dready_trigger_on;
 	int max_odr;
+	int irq;
 };
 
 static const struct {
@@ -216,7 +218,7 @@ static bool bmc150_magn_is_volatile_reg(struct device *dev, unsigned int reg)
 	}
 }
 
-static const struct regmap_config bmc150_magn_regmap_config = {
+const struct regmap_config bmc150_magn_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
 
@@ -226,6 +228,7 @@ static const struct regmap_config bmc150_magn_regmap_config = {
 	.writeable_reg = bmc150_magn_is_writeable_reg,
 	.volatile_reg = bmc150_magn_is_volatile_reg,
 };
+EXPORT_SYMBOL(bmc150_magn_regmap_config);
 
 static int bmc150_magn_set_power_mode(struct bmc150_magn_data *data,
 				      enum bmc150_magn_power_modes mode,
@@ -264,17 +267,17 @@ static int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on)
 	int ret;
 
 	if (on) {
-		ret = pm_runtime_get_sync(&data->client->dev);
+		ret = pm_runtime_get_sync(data->dev);
 	} else {
-		pm_runtime_mark_last_busy(&data->client->dev);
-		ret = pm_runtime_put_autosuspend(&data->client->dev);
+		pm_runtime_mark_last_busy(data->dev);
+		ret = pm_runtime_put_autosuspend(data->dev);
 	}
 
 	if (ret < 0) {
-		dev_err(&data->client->dev,
+		dev_err(data->dev,
 			"failed to change power state to %d\n", on);
 		if (on)
-			pm_runtime_put_noidle(&data->client->dev);
+			pm_runtime_put_noidle(data->dev);
 
 		return ret;
 	}
@@ -351,7 +354,7 @@ static int bmc150_magn_set_max_odr(struct bmc150_magn_data *data, int rep_xy,
 	/* the maximum selectable read-out frequency from datasheet */
 	max_odr = 1000000 / (145 * rep_xy + 500 * rep_z + 980);
 	if (odr > max_odr) {
-		dev_err(&data->client->dev,
+		dev_err(data->dev,
 			"Can't set oversampling with sampling freq %d\n",
 			odr);
 		return -EINVAL;
@@ -685,27 +688,27 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
 	ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND,
 					 false);
 	if (ret < 0) {
-		dev_err(&data->client->dev,
+		dev_err(data->dev,
 			"Failed to bring up device from suspend mode\n");
 		return ret;
 	}
 
 	ret = regmap_read(data->regmap, BMC150_MAGN_REG_CHIP_ID, &chip_id);
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Failed reading chip id\n");
+		dev_err(data->dev, "Failed reading chip id\n");
 		goto err_poweroff;
 	}
 	if (chip_id != BMC150_MAGN_CHIP_ID_VAL) {
-		dev_err(&data->client->dev, "Invalid chip id 0x%x\n", chip_id);
+		dev_err(data->dev, "Invalid chip id 0x%x\n", chip_id);
 		ret = -ENODEV;
 		goto err_poweroff;
 	}
-	dev_dbg(&data->client->dev, "Chip id %x\n", chip_id);
+	dev_dbg(data->dev, "Chip id %x\n", chip_id);
 
 	preset = bmc150_magn_presets_table[BMC150_MAGN_DEFAULT_PRESET];
 	ret = bmc150_magn_set_odr(data, preset.odr);
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Failed to set ODR to %d\n",
+		dev_err(data->dev, "Failed to set ODR to %d\n",
 			preset.odr);
 		goto err_poweroff;
 	}
@@ -713,7 +716,7 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
 	ret = regmap_write(data->regmap, BMC150_MAGN_REG_REP_XY,
 			   BMC150_MAGN_REPXY_TO_REGVAL(preset.rep_xy));
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Failed to set REP XY to %d\n",
+		dev_err(data->dev, "Failed to set REP XY to %d\n",
 			preset.rep_xy);
 		goto err_poweroff;
 	}
@@ -721,7 +724,7 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
 	ret = regmap_write(data->regmap, BMC150_MAGN_REG_REP_Z,
 			   BMC150_MAGN_REPZ_TO_REGVAL(preset.rep_z));
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Failed to set REP Z to %d\n",
+		dev_err(data->dev, "Failed to set REP Z to %d\n",
 			preset.rep_z);
 		goto err_poweroff;
 	}
@@ -734,7 +737,7 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
 	ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL,
 					 true);
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Failed to power on device\n");
+		dev_err(data->dev, "Failed to power on device\n");
 		goto err_poweroff;
 	}
 
@@ -843,41 +846,33 @@ static const char *bmc150_magn_match_acpi_device(struct device *dev)
 	return dev_name(dev);
 }
 
-static int bmc150_magn_probe(struct i2c_client *client,
-			     const struct i2c_device_id *id)
+int bmc150_magn_probe(struct device *dev, struct regmap *regmap,
+		      int irq, const char *name)
 {
 	struct bmc150_magn_data *data;
 	struct iio_dev *indio_dev;
-	const char *name = NULL;
 	int ret;
 
-	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
 	if (!indio_dev)
 		return -ENOMEM;
 
 	data = iio_priv(indio_dev);
-	i2c_set_clientdata(client, indio_dev);
-	data->client = client;
+	dev_set_drvdata(dev, indio_dev);
+	data->regmap = regmap;
+	data->irq = irq;
+	data->dev = dev;
 
-	if (id)
-		name = id->name;
-	else if (ACPI_HANDLE(&client->dev))
-		name = bmc150_magn_match_acpi_device(&client->dev);
-	else
-		return -ENOSYS;
+	if (!name && ACPI_HANDLE(dev))
+		name = bmc150_magn_match_acpi_device(dev);
 
 	mutex_init(&data->mutex);
-	data->regmap = devm_regmap_init_i2c(client, &bmc150_magn_regmap_config);
-	if (IS_ERR(data->regmap)) {
-		dev_err(&client->dev, "Failed to allocate register map\n");
-		return PTR_ERR(data->regmap);
-	}
 
 	ret = bmc150_magn_init(data);
 	if (ret < 0)
 		return ret;
 
-	indio_dev->dev.parent = &client->dev;
+	indio_dev->dev.parent = dev;
 	indio_dev->channels = bmc150_magn_channels;
 	indio_dev->num_channels = ARRAY_SIZE(bmc150_magn_channels);
 	indio_dev->available_scan_masks = bmc150_magn_scan_masks;
@@ -885,35 +880,34 @@ static int bmc150_magn_probe(struct i2c_client *client,
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &bmc150_magn_info;
 
-	if (client->irq > 0) {
-		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
+	if (irq > 0) {
+		data->dready_trig = devm_iio_trigger_alloc(dev,
 							   "%s-dev%d",
 							   indio_dev->name,
 							   indio_dev->id);
 		if (!data->dready_trig) {
 			ret = -ENOMEM;
-			dev_err(&client->dev, "iio trigger alloc failed\n");
+			dev_err(dev, "iio trigger alloc failed\n");
 			goto err_poweroff;
 		}
 
-		data->dready_trig->dev.parent = &client->dev;
+		data->dready_trig->dev.parent = dev;
 		data->dready_trig->ops = &bmc150_magn_trigger_ops;
 		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
 		ret = iio_trigger_register(data->dready_trig);
 		if (ret) {
-			dev_err(&client->dev, "iio trigger register failed\n");
+			dev_err(dev, "iio trigger register failed\n");
 			goto err_poweroff;
 		}
 
-		ret = request_threaded_irq(client->irq,
+		ret = request_threaded_irq(irq,
 					   iio_trigger_generic_data_rdy_poll,
 					   NULL,
 					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 					   BMC150_MAGN_IRQ_NAME,
 					   data->dready_trig);
 		if (ret < 0) {
-			dev_err(&client->dev, "request irq %d failed\n",
-				client->irq);
+			dev_err(dev, "request irq %d failed\n", irq);
 			goto err_trigger_unregister;
 		}
 	}
@@ -923,34 +917,33 @@ static int bmc150_magn_probe(struct i2c_client *client,
 					 bmc150_magn_trigger_handler,
 					 &bmc150_magn_buffer_setup_ops);
 	if (ret < 0) {
-		dev_err(&client->dev,
-			"iio triggered buffer setup failed\n");
+		dev_err(dev, "iio triggered buffer setup failed\n");
 		goto err_free_irq;
 	}
 
-	ret = pm_runtime_set_active(&client->dev);
+	ret = pm_runtime_set_active(dev);
 	if (ret)
 		goto err_buffer_cleanup;
 
-	pm_runtime_enable(&client->dev);
-	pm_runtime_set_autosuspend_delay(&client->dev,
+	pm_runtime_enable(dev);
+	pm_runtime_set_autosuspend_delay(dev,
 					 BMC150_MAGN_AUTO_SUSPEND_DELAY_MS);
-	pm_runtime_use_autosuspend(&client->dev);
+	pm_runtime_use_autosuspend(dev);
 
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
-		dev_err(&client->dev, "unable to register iio device\n");
+		dev_err(dev, "unable to register iio device\n");
 		goto err_buffer_cleanup;
 	}
 
-	dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
+	dev_dbg(dev, "Registered device %s\n", name);
 	return 0;
 
 err_buffer_cleanup:
 	iio_triggered_buffer_cleanup(indio_dev);
 err_free_irq:
-	if (client->irq > 0)
-		free_irq(client->irq, data->dready_trig);
+	if (irq > 0)
+		free_irq(irq, data->dready_trig);
 err_trigger_unregister:
 	if (data->dready_trig)
 		iio_trigger_unregister(data->dready_trig);
@@ -958,22 +951,23 @@ err_poweroff:
 	bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
 	return ret;
 }
+EXPORT_SYMBOL(bmc150_magn_probe);
 
-static int bmc150_magn_remove(struct i2c_client *client)
+int bmc150_magn_remove(struct device *dev)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmc150_magn_data *data = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
 
-	pm_runtime_disable(&client->dev);
-	pm_runtime_set_suspended(&client->dev);
-	pm_runtime_put_noidle(&client->dev);
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_put_noidle(dev);
 
 	iio_triggered_buffer_cleanup(indio_dev);
 
-	if (client->irq > 0)
-		free_irq(data->client->irq, data->dready_trig);
+	if (data->irq > 0)
+		free_irq(data->irq, data->dready_trig);
 
 	if (data->dready_trig)
 		iio_trigger_unregister(data->dready_trig);
@@ -984,11 +978,12 @@ static int bmc150_magn_remove(struct i2c_client *client)
 
 	return 0;
 }
+EXPORT_SYMBOL(bmc150_magn_remove);
 
 #ifdef CONFIG_PM
 static int bmc150_magn_runtime_suspend(struct device *dev)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmc150_magn_data *data = iio_priv(indio_dev);
 	int ret;
 
@@ -997,7 +992,7 @@ static int bmc150_magn_runtime_suspend(struct device *dev)
 					 true);
 	mutex_unlock(&data->mutex);
 	if (ret < 0) {
-		dev_err(&data->client->dev, "powering off device failed\n");
+		dev_err(dev, "powering off device failed\n");
 		return ret;
 	}
 	return 0;
@@ -1008,7 +1003,7 @@ static int bmc150_magn_runtime_suspend(struct device *dev)
  */
 static int bmc150_magn_runtime_resume(struct device *dev)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmc150_magn_data *data = iio_priv(indio_dev);
 
 	return bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL,
@@ -1019,7 +1014,7 @@ static int bmc150_magn_runtime_resume(struct device *dev)
 #ifdef CONFIG_PM_SLEEP
 static int bmc150_magn_suspend(struct device *dev)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmc150_magn_data *data = iio_priv(indio_dev);
 	int ret;
 
@@ -1033,7 +1028,7 @@ static int bmc150_magn_suspend(struct device *dev)
 
 static int bmc150_magn_resume(struct device *dev)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmc150_magn_data *data = iio_priv(indio_dev);
 	int ret;
 
@@ -1046,38 +1041,13 @@ static int bmc150_magn_resume(struct device *dev)
 }
 #endif
 
-static const struct dev_pm_ops bmc150_magn_pm_ops = {
+const struct dev_pm_ops bmc150_magn_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(bmc150_magn_suspend, bmc150_magn_resume)
 	SET_RUNTIME_PM_OPS(bmc150_magn_runtime_suspend,
 			   bmc150_magn_runtime_resume, NULL)
 };
-
-static const struct acpi_device_id bmc150_magn_acpi_match[] = {
-	{"BMC150B", 0},
-	{"BMC156B", 0},
-	{},
-};
-MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match);
-
-static const struct i2c_device_id bmc150_magn_id[] = {
-	{"bmc150_magn", 0},
-	{"bmc156_magn", 0},
-	{},
-};
-MODULE_DEVICE_TABLE(i2c, bmc150_magn_id);
-
-static struct i2c_driver bmc150_magn_driver = {
-	.driver = {
-		   .name = BMC150_MAGN_DRV_NAME,
-		   .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
-		   .pm = &bmc150_magn_pm_ops,
-		   },
-	.probe = bmc150_magn_probe,
-	.remove = bmc150_magn_remove,
-	.id_table = bmc150_magn_id,
-};
-module_i2c_driver(bmc150_magn_driver);
+EXPORT_SYMBOL(bmc150_magn_pm_ops);
 
 MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("BMC150 magnetometer driver");
+MODULE_DESCRIPTION("BMC150 magnetometer core driver");
diff --git b/drivers/iio/magnetometer/bmc150_magn.h b/drivers/iio/magnetometer/bmc150_magn.h
new file mode 100644
index 0000000..9a8e268
--- /dev/null
+++ b/drivers/iio/magnetometer/bmc150_magn.h
@@ -0,0 +1,11 @@
+#ifndef _BMC150_MAGN_H_
+#define _BMC150_MAGN_H_
+
+extern const struct regmap_config bmc150_magn_regmap_config;
+extern const struct dev_pm_ops bmc150_magn_pm_ops;
+
+int bmc150_magn_probe(struct device *dev, struct regmap *regmap, int irq,
+		      const char *name);
+int bmc150_magn_remove(struct device *dev);
+
+#endif /* _BMC150_MAGN_H_ */
diff --git b/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c
new file mode 100644
index 0000000..ee05722
--- /dev/null
+++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c
@@ -0,0 +1,80 @@
+/*
+ * 3-axis magnetometer driver supporting following I2C Bosch-Sensortec chips:
+ *  - BMC150
+ *  - BMC156
+ *  - BMM150
+ *
+ * Copyright (c) 2016, 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.
+ */
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+
+#include "bmc150_magn.h"
+
+static int bmc150_magn_i2c_probe(struct i2c_client *client,
+				 const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	const char *name = NULL;
+
+	regmap = devm_regmap_init_i2c(client, &bmc150_magn_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&client->dev, "Failed to initialize i2c regmap\n");
+		return PTR_ERR(regmap);
+	}
+
+	if (id)
+		name = id->name;
+
+	return bmc150_magn_probe(&client->dev, regmap, client->irq, name);
+}
+
+static int bmc150_magn_i2c_remove(struct i2c_client *client)
+{
+	return bmc150_magn_remove(&client->dev);
+}
+
+static const struct acpi_device_id bmc150_magn_acpi_match[] = {
+	{"BMC150B", 0},
+	{"BMC156B", 0},
+	{"BMM150B", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match);
+
+static const struct i2c_device_id bmc150_magn_i2c_id[] = {
+	{"bmc150_magn",	0},
+	{"bmc156_magn", 0},
+	{"bmm150_magn", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, bmc150_magn_i2c_id);
+
+static struct i2c_driver bmc150_magn_driver = {
+	.driver = {
+		.name	= "bmc150_magn_i2c",
+		.acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
+		.pm	= &bmc150_magn_pm_ops,
+	},
+	.probe		= bmc150_magn_i2c_probe,
+	.remove		= bmc150_magn_i2c_remove,
+	.id_table	= bmc150_magn_i2c_id,
+};
+module_i2c_driver(bmc150_magn_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMC150 I2C magnetometer driver");
diff --git b/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c
new file mode 100644
index 0000000..7d4152d
--- /dev/null
+++ b/drivers/iio/magnetometer/bmc150_magn_spi.c
@@ -0,0 +1,71 @@
+/*
+ * 3-axis magnetometer driver support following SPI Bosch-Sensortec chips:
+ *  - BMC150
+ *  - BMC156
+ *  - BMM150
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+
+#include "bmc150_magn.h"
+
+static int bmc150_magn_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+	const struct spi_device_id *id = spi_get_device_id(spi);
+
+	regmap = devm_regmap_init_spi(spi, &bmc150_magn_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 bmc150_magn_probe(&spi->dev, regmap, spi->irq, id->name);
+}
+
+static int bmc150_magn_spi_remove(struct spi_device *spi)
+{
+	bmc150_magn_remove(&spi->dev);
+
+	return 0;
+}
+
+static const struct spi_device_id bmc150_magn_spi_id[] = {
+	{"bmc150_magn", 0},
+	{"bmc156_magn", 0},
+	{"bmm150_magn", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, bmc150_magn_spi_id);
+
+static const struct acpi_device_id bmc150_magn_acpi_match[] = {
+	{"BMC150B", 0},
+	{"BMC156B", 0},
+	{"BMM150B", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match);
+
+static struct spi_driver bmc150_magn_spi_driver = {
+	.probe		= bmc150_magn_spi_probe,
+	.remove		= bmc150_magn_spi_remove,
+	.id_table	= bmc150_magn_spi_id,
+	.driver = {
+		.acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
+		.name	= "bmc150_magn_spi",
+	},
+};
+module_spi_driver(bmc150_magn_spi_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
+MODULE_DESCRIPTION("BMC150 magnetometer SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c
index 77882b4..ba3e2a3 100644
--- a/drivers/iio/magnetometer/hmc5843_core.c
+++ b/drivers/iio/magnetometer/hmc5843_core.c
@@ -451,7 +451,7 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p)
 		goto done;
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
-					   iio_get_time_ns());
+					   iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c
index 261d517..f2be4a0 100644
--- a/drivers/iio/magnetometer/mag3110.c
+++ b/drivers/iio/magnetometer/mag3110.c
@@ -261,7 +261,7 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p)
 	}
 
 	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
-		iio_get_time_ns());
+		iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c
index ecd3bd0..0a9e8fa 100644
--- a/drivers/iio/magnetometer/st_magn_buffer.c
+++ b/drivers/iio/magnetometer/st_magn_buffer.c
@@ -82,7 +82,7 @@ static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
 
 int st_magn_allocate_ring(struct iio_dev *indio_dev)
 {
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+	return iio_triggered_buffer_setup(indio_dev, NULL,
 		&st_sensors_trigger_handler, &st_magn_buffer_setup_ops);
 }
 
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index 501f858..3e1f06b 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -484,6 +484,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
 			.mask_int1 = ST_MAGN_3_DRDY_INT_MASK,
 			.addr_ihl = ST_MAGN_3_IHL_IRQ_ADDR,
 			.mask_ihl = ST_MAGN_3_IHL_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_MAGN_3_MULTIREAD_BIT,
 		.bootime = 2,
@@ -571,6 +572,7 @@ static const struct iio_info magn_info = {
 static const struct iio_trigger_ops st_magn_trigger_ops = {
 	.owner = THIS_MODULE,
 	.set_trigger_state = ST_MAGN_TRIGGER_SET_STATE,
+	.validate_device = st_sensors_validate_device,
 };
 #define ST_MAGN_TRIGGER_OPS (&st_magn_trigger_ops)
 #else
@@ -587,13 +589,15 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
 	indio_dev->info = &magn_info;
 	mutex_init(&mdata->tb.buf_lock);
 
-	st_sensors_power_enable(indio_dev);
+	err = st_sensors_power_enable(indio_dev);
+	if (err)
+		return err;
 
 	err = st_sensors_check_device_support(indio_dev,
 					ARRAY_SIZE(st_magn_sensors_settings),
 					st_magn_sensors_settings);
 	if (err < 0)
-		return err;
+		goto st_magn_power_off;
 
 	mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS;
 	mdata->multiread_bit = mdata->sensor_settings->multi_read_bit;
@@ -606,11 +610,11 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
 
 	err = st_sensors_init_sensor(indio_dev, NULL);
 	if (err < 0)
-		return err;
+		goto st_magn_power_off;
 
 	err = st_magn_allocate_ring(indio_dev);
 	if (err < 0)
-		return err;
+		goto st_magn_power_off;
 
 	if (irq > 0) {
 		err = st_sensors_allocate_trigger(indio_dev,
@@ -633,6 +637,8 @@ st_magn_device_register_error:
 		st_sensors_deallocate_trigger(indio_dev);
 st_magn_probe_trigger_error:
 	st_magn_deallocate_ring(indio_dev);
+st_magn_power_off:
+	st_sensors_power_disable(indio_dev);
 
 	return err;
 }
diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig
index ffc735c..2e9da1c 100644
--- a/drivers/iio/potentiometer/Kconfig
+++ b/drivers/iio/potentiometer/Kconfig
@@ -5,14 +5,55 @@
 
 menu "Digital potentiometers"
 
+config DS1803
+	tristate "Maxim Integrated DS1803 Digital Potentiometer driver"
+	depends on I2C
+	help
+	  Say yes here to build support for the Maxim Integrated DS1803
+	  digital potentiometer chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ds1803.
+
+config MAX5487
+        tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver"
+        depends on SPI
+        help
+          Say yes here to build support for the Maxim
+          MAX5487, MAX5488, MAX5489 digital potentiometer
+          chips.
+
+          To compile this driver as a module, choose M here: the
+          module will be called max5487.
+
+config MCP4131
+	tristate "Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer driver"
+	depends on SPI
+	help
+	  Say yes here to build support for the Microchip
+	  MCP4131, MCP4132,
+	  MCP4141, MCP4142,
+	  MCP4151, MCP4152,
+	  MCP4161, MCP4162,
+	  MCP4231, MCP4232,
+	  MCP4241, MCP4242,
+	  MCP4251, MCP4252,
+	  MCP4261, MCP4262,
+	  digital potentiometer chips.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mcp4131.
+
 config MCP4531
 	tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver"
 	depends on I2C
 	help
 	  Say yes here to build support for the Microchip
-	  MCP4531, MCP4532, MCP4551, MCP4552,
-	  MCP4631, MCP4632, MCP4651, MCP4652
-	  digital potentiomenter chips.
+	  MCP4531, MCP4532, MCP4541, MCP4542,
+	  MCP4551, MCP4552, MCP4561, MCP4562,
+	  MCP4631, MCP4632, MCP4641, MCP4642,
+	  MCP4651, MCP4652, MCP4661, MCP4662
+	  digital potentiometer chips.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called mcp4531.
diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile
index b563b49..8adb58f 100644
--- a/drivers/iio/potentiometer/Makefile
+++ b/drivers/iio/potentiometer/Makefile
@@ -3,5 +3,8 @@
 #
 
 # When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_DS1803) += ds1803.o
+obj-$(CONFIG_MAX5487) += max5487.o
+obj-$(CONFIG_MCP4131) += mcp4131.o
 obj-$(CONFIG_MCP4531) += mcp4531.o
 obj-$(CONFIG_TPL0102) += tpl0102.o
diff --git b/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c
new file mode 100644
index 0000000..fb9e2a3
--- /dev/null
+++ b/drivers/iio/potentiometer/ds1803.c
@@ -0,0 +1,173 @@
+/*
+ * Maxim Integrated DS1803 digital potentiometer driver
+ * Copyright (c) 2016 Slawomir Stepien
+ *
+ * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS1803.pdf
+ *
+ * DEVID	#Wipers	#Positions	Resistor Opts (kOhm)	i2c address
+ * ds1803	2	256		10, 50, 100		0101xxx
+ *
+ * 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/err.h>
+#include <linux/export.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#define DS1803_MAX_POS		255
+#define DS1803_WRITE(chan)	(0xa8 | ((chan) + 1))
+
+enum ds1803_type {
+	DS1803_010,
+	DS1803_050,
+	DS1803_100,
+};
+
+struct ds1803_cfg {
+	int kohms;
+};
+
+static const struct ds1803_cfg ds1803_cfg[] = {
+	[DS1803_010] = { .kohms =  10, },
+	[DS1803_050] = { .kohms =  50, },
+	[DS1803_100] = { .kohms = 100, },
+};
+
+struct ds1803_data {
+	struct i2c_client *client;
+	const struct ds1803_cfg *cfg;
+};
+
+#define DS1803_CHANNEL(ch) {					\
+	.type = IIO_RESISTANCE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.channel = (ch),					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+static const struct iio_chan_spec ds1803_channels[] = {
+	DS1803_CHANNEL(0),
+	DS1803_CHANNEL(1),
+};
+
+static int ds1803_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	struct ds1803_data *data = iio_priv(indio_dev);
+	int pot = chan->channel;
+	int ret;
+	u8 result[indio_dev->num_channels];
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = i2c_master_recv(data->client, result,
+				indio_dev->num_channels);
+		if (ret < 0)
+			return ret;
+
+		*val = result[pot];
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		*val = 1000 * data->cfg->kohms;
+		*val2 = DS1803_MAX_POS;
+		return IIO_VAL_FRACTIONAL;
+	}
+
+	return -EINVAL;
+}
+
+static int ds1803_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct ds1803_data *data = iio_priv(indio_dev);
+	int pot = chan->channel;
+
+	if (val2 != 0)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val > DS1803_MAX_POS || val < 0)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return i2c_smbus_write_byte_data(data->client, DS1803_WRITE(pot), val);
+}
+
+static const struct iio_info ds1803_info = {
+	.read_raw = ds1803_read_raw,
+	.write_raw = ds1803_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int ds1803_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct ds1803_data *data;
+	struct iio_dev *indio_dev;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, indio_dev);
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	data->cfg = &ds1803_cfg[id->driver_data];
+
+	indio_dev->dev.parent = dev;
+	indio_dev->info = &ds1803_info;
+	indio_dev->channels = ds1803_channels;
+	indio_dev->num_channels = ARRAY_SIZE(ds1803_channels);
+	indio_dev->name = client->name;
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id ds1803_dt_ids[] = {
+	{ .compatible = "maxim,ds1803-010", .data = &ds1803_cfg[DS1803_010] },
+	{ .compatible = "maxim,ds1803-050", .data = &ds1803_cfg[DS1803_050] },
+	{ .compatible = "maxim,ds1803-100", .data = &ds1803_cfg[DS1803_100] },
+	{}
+};
+MODULE_DEVICE_TABLE(of, ds1803_dt_ids);
+#endif /* CONFIG_OF */
+
+static const struct i2c_device_id ds1803_id[] = {
+	{ "ds1803-010", DS1803_010 },
+	{ "ds1803-050", DS1803_050 },
+	{ "ds1803-100", DS1803_100 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, ds1803_id);
+
+static struct i2c_driver ds1803_driver = {
+	.driver = {
+		.name	= "ds1803",
+		.of_match_table = of_match_ptr(ds1803_dt_ids),
+	},
+	.probe		= ds1803_probe,
+	.id_table	= ds1803_id,
+};
+
+module_i2c_driver(ds1803_driver);
+
+MODULE_AUTHOR("Slawomir Stepien <sst@poczta.fm>");
+MODULE_DESCRIPTION("DS1803 digital potentiometer");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c
new file mode 100644
index 0000000..6c50939
--- /dev/null
+++ b/drivers/iio/potentiometer/max5487.c
@@ -0,0 +1,161 @@
+/*
+ * max5487.c - Support for MAX5487, MAX5488, MAX5489 digital potentiometers
+ *
+ * Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com>
+ *
+ * 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/acpi.h>
+
+#include <linux/iio/sysfs.h>
+#include <linux/iio/iio.h>
+
+#define MAX5487_WRITE_WIPER_A	(0x01 << 8)
+#define MAX5487_WRITE_WIPER_B	(0x02 << 8)
+
+/* copy both wiper regs to NV regs */
+#define MAX5487_COPY_AB_TO_NV	(0x23 << 8)
+/* copy both NV regs to wiper regs */
+#define MAX5487_COPY_NV_TO_AB	(0x33 << 8)
+
+#define MAX5487_MAX_POS		255
+
+struct max5487_data {
+	struct spi_device *spi;
+	int kohms;
+};
+
+#define MAX5487_CHANNEL(ch, addr) {				\
+	.type = IIO_RESISTANCE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.channel = ch,						\
+	.address = addr,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+static const struct iio_chan_spec max5487_channels[] = {
+	MAX5487_CHANNEL(0, MAX5487_WRITE_WIPER_A),
+	MAX5487_CHANNEL(1, MAX5487_WRITE_WIPER_B),
+};
+
+static int max5487_write_cmd(struct spi_device *spi, u16 cmd)
+{
+	return spi_write(spi, (const void *) &cmd, sizeof(u16));
+}
+
+static int max5487_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	struct max5487_data *data = iio_priv(indio_dev);
+
+	if (mask != IIO_CHAN_INFO_SCALE)
+		return -EINVAL;
+
+	*val = 1000 * data->kohms;
+	*val2 = MAX5487_MAX_POS;
+
+	return IIO_VAL_FRACTIONAL;
+}
+
+static int max5487_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct max5487_data *data = iio_priv(indio_dev);
+
+	if (mask != IIO_CHAN_INFO_RAW)
+		return -EINVAL;
+
+	if (val < 0 || val > MAX5487_MAX_POS)
+		return -EINVAL;
+
+	return max5487_write_cmd(data->spi, chan->address | val);
+}
+
+static const struct iio_info max5487_info = {
+	.read_raw = max5487_read_raw,
+	.write_raw = max5487_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int max5487_spi_probe(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev;
+	struct max5487_data *data;
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(&spi->dev, indio_dev);
+	data = iio_priv(indio_dev);
+
+	data->spi = spi;
+	data->kohms = id->driver_data;
+
+	indio_dev->info = &max5487_info;
+	indio_dev->name = id->name;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = max5487_channels;
+	indio_dev->num_channels = ARRAY_SIZE(max5487_channels);
+
+	/* restore both wiper regs from NV regs */
+	ret = max5487_write_cmd(data->spi, MAX5487_COPY_NV_TO_AB);
+	if (ret < 0)
+		return ret;
+
+	return iio_device_register(indio_dev);
+}
+
+static int max5487_spi_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev);
+
+	iio_device_unregister(indio_dev);
+
+	/* save both wiper regs to NV regs */
+	return max5487_write_cmd(spi, MAX5487_COPY_AB_TO_NV);
+}
+
+static const struct spi_device_id max5487_id[] = {
+	{ "MAX5487", 10 },
+	{ "MAX5488", 50 },
+	{ "MAX5489", 100 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, max5487_id);
+
+static const struct acpi_device_id max5487_acpi_match[] = {
+	{ "MAX5487", 10 },
+	{ "MAX5488", 50 },
+	{ "MAX5489", 100 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, max5487_acpi_match);
+
+static struct spi_driver max5487_driver = {
+	.driver = {
+		.name = "max5487",
+		.owner = THIS_MODULE,
+		.acpi_match_table = ACPI_PTR(max5487_acpi_match),
+	},
+	.id_table = max5487_id,
+	.probe = max5487_spi_probe,
+	.remove = max5487_spi_remove
+};
+module_spi_driver(max5487_driver);
+
+MODULE_AUTHOR("Cristina-Gabriela Moraru <cristina.moraru09@gmail.com>");
+MODULE_DESCRIPTION("max5487 SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c
new file mode 100644
index 0000000..4e7e2c6
--- /dev/null
+++ b/drivers/iio/potentiometer/mcp4131.c
@@ -0,0 +1,494 @@
+/*
+ * Industrial I/O driver for Microchip digital potentiometers
+ *
+ * Copyright (c) 2016 Slawomir Stepien
+ * Based on: Peter Rosin's code from mcp4531.c
+ *
+ * Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf
+ *
+ * DEVID	#Wipers	#Positions	Resistor Opts (kOhm)
+ * mcp4131	1	129		5, 10, 50, 100
+ * mcp4132	1	129		5, 10, 50, 100
+ * mcp4141	1	129		5, 10, 50, 100
+ * mcp4142	1	129		5, 10, 50, 100
+ * mcp4151	1	257		5, 10, 50, 100
+ * mcp4152	1	257		5, 10, 50, 100
+ * mcp4161	1	257		5, 10, 50, 100
+ * mcp4162	1	257		5, 10, 50, 100
+ * mcp4231	2	129		5, 10, 50, 100
+ * mcp4232	2	129		5, 10, 50, 100
+ * mcp4241	2	129		5, 10, 50, 100
+ * mcp4242	2	129		5, 10, 50, 100
+ * mcp4251	2	257		5, 10, 50, 100
+ * mcp4252	2	257		5, 10, 50, 100
+ * mcp4261	2	257		5, 10, 50, 100
+ * mcp4262	2	257		5, 10, 50, 100
+ *
+ * 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.
+ */
+
+/*
+ * TODO:
+ * 1. Write wiper setting to EEPROM for EEPROM capable models.
+ */
+
+#include <linux/cache.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+#define MCP4131_WRITE		(0x00 << 2)
+#define MCP4131_READ		(0x03 << 2)
+
+#define MCP4131_WIPER_SHIFT	4
+#define MCP4131_CMDERR(r)	((r[0]) & 0x02)
+#define MCP4131_RAW(r)		((r[0]) == 0xff ? 0x100 : (r[1]))
+
+struct mcp4131_cfg {
+	int wipers;
+	int max_pos;
+	int kohms;
+};
+
+enum mcp4131_type {
+	MCP413x_502 = 0,
+	MCP413x_103,
+	MCP413x_503,
+	MCP413x_104,
+	MCP414x_502,
+	MCP414x_103,
+	MCP414x_503,
+	MCP414x_104,
+	MCP415x_502,
+	MCP415x_103,
+	MCP415x_503,
+	MCP415x_104,
+	MCP416x_502,
+	MCP416x_103,
+	MCP416x_503,
+	MCP416x_104,
+	MCP423x_502,
+	MCP423x_103,
+	MCP423x_503,
+	MCP423x_104,
+	MCP424x_502,
+	MCP424x_103,
+	MCP424x_503,
+	MCP424x_104,
+	MCP425x_502,
+	MCP425x_103,
+	MCP425x_503,
+	MCP425x_104,
+	MCP426x_502,
+	MCP426x_103,
+	MCP426x_503,
+	MCP426x_104,
+};
+
+static const struct mcp4131_cfg mcp4131_cfg[] = {
+	[MCP413x_502] = { .wipers = 1, .max_pos = 128, .kohms =   5, },
+	[MCP413x_103] = { .wipers = 1, .max_pos = 128, .kohms =  10, },
+	[MCP413x_503] = { .wipers = 1, .max_pos = 128, .kohms =  50, },
+	[MCP413x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
+	[MCP414x_502] = { .wipers = 1, .max_pos = 128, .kohms =   5, },
+	[MCP414x_103] = { .wipers = 1, .max_pos = 128, .kohms =  10, },
+	[MCP414x_503] = { .wipers = 1, .max_pos = 128, .kohms =  50, },
+	[MCP414x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
+	[MCP415x_502] = { .wipers = 1, .max_pos = 256, .kohms =   5, },
+	[MCP415x_103] = { .wipers = 1, .max_pos = 256, .kohms =  10, },
+	[MCP415x_503] = { .wipers = 1, .max_pos = 256, .kohms =  50, },
+	[MCP415x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
+	[MCP416x_502] = { .wipers = 1, .max_pos = 256, .kohms =   5, },
+	[MCP416x_103] = { .wipers = 1, .max_pos = 256, .kohms =  10, },
+	[MCP416x_503] = { .wipers = 1, .max_pos = 256, .kohms =  50, },
+	[MCP416x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
+	[MCP423x_502] = { .wipers = 2, .max_pos = 128, .kohms =   5, },
+	[MCP423x_103] = { .wipers = 2, .max_pos = 128, .kohms =  10, },
+	[MCP423x_503] = { .wipers = 2, .max_pos = 128, .kohms =  50, },
+	[MCP423x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
+	[MCP424x_502] = { .wipers = 2, .max_pos = 128, .kohms =   5, },
+	[MCP424x_103] = { .wipers = 2, .max_pos = 128, .kohms =  10, },
+	[MCP424x_503] = { .wipers = 2, .max_pos = 128, .kohms =  50, },
+	[MCP424x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
+	[MCP425x_502] = { .wipers = 2, .max_pos = 256, .kohms =   5, },
+	[MCP425x_103] = { .wipers = 2, .max_pos = 256, .kohms =  10, },
+	[MCP425x_503] = { .wipers = 2, .max_pos = 256, .kohms =  50, },
+	[MCP425x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
+	[MCP426x_502] = { .wipers = 2, .max_pos = 256, .kohms =   5, },
+	[MCP426x_103] = { .wipers = 2, .max_pos = 256, .kohms =  10, },
+	[MCP426x_503] = { .wipers = 2, .max_pos = 256, .kohms =  50, },
+	[MCP426x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
+};
+
+struct mcp4131_data {
+	struct spi_device *spi;
+	const struct mcp4131_cfg *cfg;
+	struct mutex lock;
+	u8 buf[2] ____cacheline_aligned;
+};
+
+#define MCP4131_CHANNEL(ch) {					\
+	.type = IIO_RESISTANCE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.channel = (ch),					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+static const struct iio_chan_spec mcp4131_channels[] = {
+	MCP4131_CHANNEL(0),
+	MCP4131_CHANNEL(1),
+};
+
+static int mcp4131_read(struct spi_device *spi, void *buf, size_t len)
+{
+	struct spi_transfer t = {
+		.tx_buf = buf, /* We need to send addr, cmd and 12 bits */
+		.rx_buf	= buf,
+		.len = len,
+	};
+	struct spi_message m;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+
+	return spi_sync(spi, &m);
+}
+
+static int mcp4131_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	int err;
+	struct mcp4131_data *data = iio_priv(indio_dev);
+	int address = chan->channel;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&data->lock);
+
+		data->buf[0] = (address << MCP4131_WIPER_SHIFT) | MCP4131_READ;
+		data->buf[1] = 0;
+
+		err = mcp4131_read(data->spi, data->buf, 2);
+		if (err) {
+			mutex_unlock(&data->lock);
+			return err;
+		}
+
+		/* Error, bad address/command combination */
+		if (!MCP4131_CMDERR(data->buf)) {
+			mutex_unlock(&data->lock);
+			return -EIO;
+		}
+
+		*val = MCP4131_RAW(data->buf);
+		mutex_unlock(&data->lock);
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		*val = 1000 * data->cfg->kohms;
+		*val2 = data->cfg->max_pos;
+		return IIO_VAL_FRACTIONAL;
+	}
+
+	return -EINVAL;
+}
+
+static int mcp4131_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	int err;
+	struct mcp4131_data *data = iio_priv(indio_dev);
+	int address = chan->channel << MCP4131_WIPER_SHIFT;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val > data->cfg->max_pos || val < 0)
+			return -EINVAL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->lock);
+
+	data->buf[0] = address << MCP4131_WIPER_SHIFT;
+	data->buf[0] |= MCP4131_WRITE | (val >> 8);
+	data->buf[1] = val & 0xFF; /* 8 bits here */
+
+	err = spi_write(data->spi, data->buf, 2);
+	mutex_unlock(&data->lock);
+
+	return err;
+}
+
+static const struct iio_info mcp4131_info = {
+	.read_raw = mcp4131_read_raw,
+	.write_raw = mcp4131_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int mcp4131_probe(struct spi_device *spi)
+{
+	int err;
+	struct device *dev = &spi->dev;
+	unsigned long devid = spi_get_device_id(spi)->driver_data;
+	struct mcp4131_data *data;
+	struct iio_dev *indio_dev;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+	data->spi = spi;
+	data->cfg = &mcp4131_cfg[devid];
+
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = dev;
+	indio_dev->info = &mcp4131_info;
+	indio_dev->channels = mcp4131_channels;
+	indio_dev->num_channels = data->cfg->wipers;
+	indio_dev->name = spi_get_device_id(spi)->name;
+
+	err = devm_iio_device_register(dev, indio_dev);
+	if (err) {
+		dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name);
+		return err;
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id mcp4131_dt_ids[] = {
+	{ .compatible = "microchip,mcp4131-502",
+		.data = &mcp4131_cfg[MCP413x_502] },
+	{ .compatible = "microchip,mcp4131-103",
+		.data = &mcp4131_cfg[MCP413x_103] },
+	{ .compatible = "microchip,mcp4131-503",
+		.data = &mcp4131_cfg[MCP413x_503] },
+	{ .compatible = "microchip,mcp4131-104",
+		.data = &mcp4131_cfg[MCP413x_104] },
+	{ .compatible = "microchip,mcp4132-502",
+		.data = &mcp4131_cfg[MCP413x_502] },
+	{ .compatible = "microchip,mcp4132-103",
+		.data = &mcp4131_cfg[MCP413x_103] },
+	{ .compatible = "microchip,mcp4132-503",
+		.data = &mcp4131_cfg[MCP413x_503] },
+	{ .compatible = "microchip,mcp4132-104",
+		.data = &mcp4131_cfg[MCP413x_104] },
+	{ .compatible = "microchip,mcp4141-502",
+		.data = &mcp4131_cfg[MCP414x_502] },
+	{ .compatible = "microchip,mcp4141-103",
+		.data = &mcp4131_cfg[MCP414x_103] },
+	{ .compatible = "microchip,mcp4141-503",
+		.data = &mcp4131_cfg[MCP414x_503] },
+	{ .compatible = "microchip,mcp4141-104",
+		.data = &mcp4131_cfg[MCP414x_104] },
+	{ .compatible = "microchip,mcp4142-502",
+		.data = &mcp4131_cfg[MCP414x_502] },
+	{ .compatible = "microchip,mcp4142-103",
+		.data = &mcp4131_cfg[MCP414x_103] },
+	{ .compatible = "microchip,mcp4142-503",
+		.data = &mcp4131_cfg[MCP414x_503] },
+	{ .compatible = "microchip,mcp4142-104",
+		.data = &mcp4131_cfg[MCP414x_104] },
+	{ .compatible = "microchip,mcp4151-502",
+		.data = &mcp4131_cfg[MCP415x_502] },
+	{ .compatible = "microchip,mcp4151-103",
+		.data = &mcp4131_cfg[MCP415x_103] },
+	{ .compatible = "microchip,mcp4151-503",
+		.data = &mcp4131_cfg[MCP415x_503] },
+	{ .compatible = "microchip,mcp4151-104",
+		.data = &mcp4131_cfg[MCP415x_104] },
+	{ .compatible = "microchip,mcp4152-502",
+		.data = &mcp4131_cfg[MCP415x_502] },
+	{ .compatible = "microchip,mcp4152-103",
+		.data = &mcp4131_cfg[MCP415x_103] },
+	{ .compatible = "microchip,mcp4152-503",
+		.data = &mcp4131_cfg[MCP415x_503] },
+	{ .compatible = "microchip,mcp4152-104",
+		.data = &mcp4131_cfg[MCP415x_104] },
+	{ .compatible = "microchip,mcp4161-502",
+		.data = &mcp4131_cfg[MCP416x_502] },
+	{ .compatible = "microchip,mcp4161-103",
+		.data = &mcp4131_cfg[MCP416x_103] },
+	{ .compatible = "microchip,mcp4161-503",
+		.data = &mcp4131_cfg[MCP416x_503] },
+	{ .compatible = "microchip,mcp4161-104",
+		.data = &mcp4131_cfg[MCP416x_104] },
+	{ .compatible = "microchip,mcp4162-502",
+		.data = &mcp4131_cfg[MCP416x_502] },
+	{ .compatible = "microchip,mcp4162-103",
+		.data = &mcp4131_cfg[MCP416x_103] },
+	{ .compatible = "microchip,mcp4162-503",
+		.data = &mcp4131_cfg[MCP416x_503] },
+	{ .compatible = "microchip,mcp4162-104",
+		.data = &mcp4131_cfg[MCP416x_104] },
+	{ .compatible = "microchip,mcp4231-502",
+		.data = &mcp4131_cfg[MCP423x_502] },
+	{ .compatible = "microchip,mcp4231-103",
+		.data = &mcp4131_cfg[MCP423x_103] },
+	{ .compatible = "microchip,mcp4231-503",
+		.data = &mcp4131_cfg[MCP423x_503] },
+	{ .compatible = "microchip,mcp4231-104",
+		.data = &mcp4131_cfg[MCP423x_104] },
+	{ .compatible = "microchip,mcp4232-502",
+		.data = &mcp4131_cfg[MCP423x_502] },
+	{ .compatible = "microchip,mcp4232-103",
+		.data = &mcp4131_cfg[MCP423x_103] },
+	{ .compatible = "microchip,mcp4232-503",
+		.data = &mcp4131_cfg[MCP423x_503] },
+	{ .compatible = "microchip,mcp4232-104",
+		.data = &mcp4131_cfg[MCP423x_104] },
+	{ .compatible = "microchip,mcp4241-502",
+		.data = &mcp4131_cfg[MCP424x_502] },
+	{ .compatible = "microchip,mcp4241-103",
+		.data = &mcp4131_cfg[MCP424x_103] },
+	{ .compatible = "microchip,mcp4241-503",
+		.data = &mcp4131_cfg[MCP424x_503] },
+	{ .compatible = "microchip,mcp4241-104",
+		.data = &mcp4131_cfg[MCP424x_104] },
+	{ .compatible = "microchip,mcp4242-502",
+		.data = &mcp4131_cfg[MCP424x_502] },
+	{ .compatible = "microchip,mcp4242-103",
+		.data = &mcp4131_cfg[MCP424x_103] },
+	{ .compatible = "microchip,mcp4242-503",
+		.data = &mcp4131_cfg[MCP424x_503] },
+	{ .compatible = "microchip,mcp4242-104",
+		.data = &mcp4131_cfg[MCP424x_104] },
+	{ .compatible = "microchip,mcp4251-502",
+		.data = &mcp4131_cfg[MCP425x_502] },
+	{ .compatible = "microchip,mcp4251-103",
+		.data = &mcp4131_cfg[MCP425x_103] },
+	{ .compatible = "microchip,mcp4251-503",
+		.data = &mcp4131_cfg[MCP425x_503] },
+	{ .compatible = "microchip,mcp4251-104",
+		.data = &mcp4131_cfg[MCP425x_104] },
+	{ .compatible = "microchip,mcp4252-502",
+		.data = &mcp4131_cfg[MCP425x_502] },
+	{ .compatible = "microchip,mcp4252-103",
+		.data = &mcp4131_cfg[MCP425x_103] },
+	{ .compatible = "microchip,mcp4252-503",
+		.data = &mcp4131_cfg[MCP425x_503] },
+	{ .compatible = "microchip,mcp4252-104",
+		.data = &mcp4131_cfg[MCP425x_104] },
+	{ .compatible = "microchip,mcp4261-502",
+		.data = &mcp4131_cfg[MCP426x_502] },
+	{ .compatible = "microchip,mcp4261-103",
+		.data = &mcp4131_cfg[MCP426x_103] },
+	{ .compatible = "microchip,mcp4261-503",
+		.data = &mcp4131_cfg[MCP426x_503] },
+	{ .compatible = "microchip,mcp4261-104",
+		.data = &mcp4131_cfg[MCP426x_104] },
+	{ .compatible = "microchip,mcp4262-502",
+		.data = &mcp4131_cfg[MCP426x_502] },
+	{ .compatible = "microchip,mcp4262-103",
+		.data = &mcp4131_cfg[MCP426x_103] },
+	{ .compatible = "microchip,mcp4262-503",
+		.data = &mcp4131_cfg[MCP426x_503] },
+	{ .compatible = "microchip,mcp4262-104",
+		.data = &mcp4131_cfg[MCP426x_104] },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mcp4131_dt_ids);
+#endif /* CONFIG_OF */
+
+static const struct spi_device_id mcp4131_id[] = {
+	{ "mcp4131-502", MCP413x_502 },
+	{ "mcp4131-103", MCP413x_103 },
+	{ "mcp4131-503", MCP413x_503 },
+	{ "mcp4131-104", MCP413x_104 },
+	{ "mcp4132-502", MCP413x_502 },
+	{ "mcp4132-103", MCP413x_103 },
+	{ "mcp4132-503", MCP413x_503 },
+	{ "mcp4132-104", MCP413x_104 },
+	{ "mcp4141-502", MCP414x_502 },
+	{ "mcp4141-103", MCP414x_103 },
+	{ "mcp4141-503", MCP414x_503 },
+	{ "mcp4141-104", MCP414x_104 },
+	{ "mcp4142-502", MCP414x_502 },
+	{ "mcp4142-103", MCP414x_103 },
+	{ "mcp4142-503", MCP414x_503 },
+	{ "mcp4142-104", MCP414x_104 },
+	{ "mcp4151-502", MCP415x_502 },
+	{ "mcp4151-103", MCP415x_103 },
+	{ "mcp4151-503", MCP415x_503 },
+	{ "mcp4151-104", MCP415x_104 },
+	{ "mcp4152-502", MCP415x_502 },
+	{ "mcp4152-103", MCP415x_103 },
+	{ "mcp4152-503", MCP415x_503 },
+	{ "mcp4152-104", MCP415x_104 },
+	{ "mcp4161-502", MCP416x_502 },
+	{ "mcp4161-103", MCP416x_103 },
+	{ "mcp4161-503", MCP416x_503 },
+	{ "mcp4161-104", MCP416x_104 },
+	{ "mcp4162-502", MCP416x_502 },
+	{ "mcp4162-103", MCP416x_103 },
+	{ "mcp4162-503", MCP416x_503 },
+	{ "mcp4162-104", MCP416x_104 },
+	{ "mcp4231-502", MCP423x_502 },
+	{ "mcp4231-103", MCP423x_103 },
+	{ "mcp4231-503", MCP423x_503 },
+	{ "mcp4231-104", MCP423x_104 },
+	{ "mcp4232-502", MCP423x_502 },
+	{ "mcp4232-103", MCP423x_103 },
+	{ "mcp4232-503", MCP423x_503 },
+	{ "mcp4232-104", MCP423x_104 },
+	{ "mcp4241-502", MCP424x_502 },
+	{ "mcp4241-103", MCP424x_103 },
+	{ "mcp4241-503", MCP424x_503 },
+	{ "mcp4241-104", MCP424x_104 },
+	{ "mcp4242-502", MCP424x_502 },
+	{ "mcp4242-103", MCP424x_103 },
+	{ "mcp4242-503", MCP424x_503 },
+	{ "mcp4242-104", MCP424x_104 },
+	{ "mcp4251-502", MCP425x_502 },
+	{ "mcp4251-103", MCP425x_103 },
+	{ "mcp4251-503", MCP425x_503 },
+	{ "mcp4251-104", MCP425x_104 },
+	{ "mcp4252-502", MCP425x_502 },
+	{ "mcp4252-103", MCP425x_103 },
+	{ "mcp4252-503", MCP425x_503 },
+	{ "mcp4252-104", MCP425x_104 },
+	{ "mcp4261-502", MCP426x_502 },
+	{ "mcp4261-103", MCP426x_103 },
+	{ "mcp4261-503", MCP426x_503 },
+	{ "mcp4261-104", MCP426x_104 },
+	{ "mcp4262-502", MCP426x_502 },
+	{ "mcp4262-103", MCP426x_103 },
+	{ "mcp4262-503", MCP426x_503 },
+	{ "mcp4262-104", MCP426x_104 },
+	{}
+};
+MODULE_DEVICE_TABLE(spi, mcp4131_id);
+
+static struct spi_driver mcp4131_driver = {
+	.driver = {
+		.name	= "mcp4131",
+		.of_match_table = of_match_ptr(mcp4131_dt_ids),
+	},
+	.probe		= mcp4131_probe,
+	.id_table	= mcp4131_id,
+};
+
+module_spi_driver(mcp4131_driver);
+
+MODULE_AUTHOR("Slawomir Stepien <sst@poczta.fm>");
+MODULE_DESCRIPTION("MCP4131 digital potentiometer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c
index 0db67fe..13b6ae2 100644
--- a/drivers/iio/potentiometer/mcp4531.c
+++ b/drivers/iio/potentiometer/mcp4531.c
@@ -8,12 +8,20 @@
  * DEVID	#Wipers	#Positions	Resistor Opts (kOhm)	i2c address
  * mcp4531	1	129		5, 10, 50, 100          010111x
  * mcp4532	1	129		5, 10, 50, 100          01011xx
+ * mcp4541	1	129		5, 10, 50, 100          010111x
+ * mcp4542	1	129		5, 10, 50, 100          01011xx
  * mcp4551	1	257		5, 10, 50, 100          010111x
  * mcp4552	1	257		5, 10, 50, 100          01011xx
+ * mcp4561	1	257		5, 10, 50, 100          010111x
+ * mcp4562	1	257		5, 10, 50, 100          01011xx
  * mcp4631	2	129		5, 10, 50, 100          0101xxx
  * mcp4632	2	129		5, 10, 50, 100          01011xx
+ * mcp4641	2	129		5, 10, 50, 100          0101xxx
+ * mcp4642	2	129		5, 10, 50, 100          01011xx
  * mcp4651	2	257		5, 10, 50, 100          0101xxx
  * mcp4652	2	257		5, 10, 50, 100          01011xx
+ * mcp4661	2	257		5, 10, 50, 100          0101xxx
+ * mcp4662	2	257		5, 10, 50, 100          01011xx
  *
  * 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
@@ -23,6 +31,8 @@
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/iio/iio.h>
 
@@ -37,18 +47,34 @@ enum mcp4531_type {
 	MCP453x_103,
 	MCP453x_503,
 	MCP453x_104,
+	MCP454x_502,
+	MCP454x_103,
+	MCP454x_503,
+	MCP454x_104,
 	MCP455x_502,
 	MCP455x_103,
 	MCP455x_503,
 	MCP455x_104,
+	MCP456x_502,
+	MCP456x_103,
+	MCP456x_503,
+	MCP456x_104,
 	MCP463x_502,
 	MCP463x_103,
 	MCP463x_503,
 	MCP463x_104,
+	MCP464x_502,
+	MCP464x_103,
+	MCP464x_503,
+	MCP464x_104,
 	MCP465x_502,
 	MCP465x_103,
 	MCP465x_503,
 	MCP465x_104,
+	MCP466x_502,
+	MCP466x_103,
+	MCP466x_503,
+	MCP466x_104,
 };
 
 static const struct mcp4531_cfg mcp4531_cfg[] = {
@@ -56,18 +82,34 @@ static const struct mcp4531_cfg mcp4531_cfg[] = {
 	[MCP453x_103] = { .wipers = 1, .max_pos = 128, .kohms =  10, },
 	[MCP453x_503] = { .wipers = 1, .max_pos = 128, .kohms =  50, },
 	[MCP453x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
+	[MCP454x_502] = { .wipers = 1, .max_pos = 128, .kohms =   5, },
+	[MCP454x_103] = { .wipers = 1, .max_pos = 128, .kohms =  10, },
+	[MCP454x_503] = { .wipers = 1, .max_pos = 128, .kohms =  50, },
+	[MCP454x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
 	[MCP455x_502] = { .wipers = 1, .max_pos = 256, .kohms =   5, },
 	[MCP455x_103] = { .wipers = 1, .max_pos = 256, .kohms =  10, },
 	[MCP455x_503] = { .wipers = 1, .max_pos = 256, .kohms =  50, },
 	[MCP455x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
+	[MCP456x_502] = { .wipers = 1, .max_pos = 256, .kohms =   5, },
+	[MCP456x_103] = { .wipers = 1, .max_pos = 256, .kohms =  10, },
+	[MCP456x_503] = { .wipers = 1, .max_pos = 256, .kohms =  50, },
+	[MCP456x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
 	[MCP463x_502] = { .wipers = 2, .max_pos = 128, .kohms =   5, },
 	[MCP463x_103] = { .wipers = 2, .max_pos = 128, .kohms =  10, },
 	[MCP463x_503] = { .wipers = 2, .max_pos = 128, .kohms =  50, },
 	[MCP463x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
+	[MCP464x_502] = { .wipers = 2, .max_pos = 128, .kohms =   5, },
+	[MCP464x_103] = { .wipers = 2, .max_pos = 128, .kohms =  10, },
+	[MCP464x_503] = { .wipers = 2, .max_pos = 128, .kohms =  50, },
+	[MCP464x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
 	[MCP465x_502] = { .wipers = 2, .max_pos = 256, .kohms =   5, },
 	[MCP465x_103] = { .wipers = 2, .max_pos = 256, .kohms =  10, },
 	[MCP465x_503] = { .wipers = 2, .max_pos = 256, .kohms =  50, },
 	[MCP465x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
+	[MCP466x_502] = { .wipers = 2, .max_pos = 256, .kohms =   5, },
+	[MCP466x_103] = { .wipers = 2, .max_pos = 256, .kohms =  10, },
+	[MCP466x_503] = { .wipers = 2, .max_pos = 256, .kohms =  50, },
+	[MCP466x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
 };
 
 #define MCP4531_WRITE (0 << 2)
@@ -79,7 +121,7 @@ static const struct mcp4531_cfg mcp4531_cfg[] = {
 
 struct mcp4531_data {
 	struct i2c_client *client;
-	unsigned long devid;
+	const struct mcp4531_cfg *cfg;
 };
 
 #define MCP4531_CHANNEL(ch) {					\
@@ -113,8 +155,8 @@ static int mcp4531_read_raw(struct iio_dev *indio_dev,
 		*val = ret;
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
-		*val = 1000 * mcp4531_cfg[data->devid].kohms;
-		*val2 = mcp4531_cfg[data->devid].max_pos;
+		*val = 1000 * data->cfg->kohms;
+		*val2 = data->cfg->max_pos;
 		return IIO_VAL_FRACTIONAL;
 	}
 
@@ -130,7 +172,7 @@ static int mcp4531_write_raw(struct iio_dev *indio_dev,
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		if (val > mcp4531_cfg[data->devid].max_pos || val < 0)
+		if (val > data->cfg->max_pos || val < 0)
 			return -EINVAL;
 		break;
 	default:
@@ -148,13 +190,89 @@ static const struct iio_info mcp4531_info = {
 	.driver_module = THIS_MODULE,
 };
 
+#ifdef CONFIG_OF
+
+#define MCP4531_COMPATIBLE(of_compatible, cfg) {	\
+			.compatible = of_compatible,	\
+			.data = &mcp4531_cfg[cfg],	\
+}
+
+static const struct of_device_id mcp4531_of_match[] = {
+	MCP4531_COMPATIBLE("microchip,mcp4531-502", MCP453x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4531-103", MCP453x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4531-503", MCP453x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4531-104", MCP453x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4532-502", MCP453x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4532-103", MCP453x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4532-503", MCP453x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4532-104", MCP453x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4541-502", MCP454x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4541-103", MCP454x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4541-503", MCP454x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4541-104", MCP454x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4542-502", MCP454x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4542-103", MCP454x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4542-503", MCP454x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4542-104", MCP454x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4551-502", MCP455x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4551-103", MCP455x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4551-503", MCP455x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4551-104", MCP455x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4552-502", MCP455x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4552-103", MCP455x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4552-503", MCP455x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4552-104", MCP455x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4561-502", MCP456x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4561-103", MCP456x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4561-503", MCP456x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4561-104", MCP456x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4562-502", MCP456x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4562-103", MCP456x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4562-503", MCP456x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4562-104", MCP456x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4631-502", MCP463x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4631-103", MCP463x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4631-503", MCP463x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4631-104", MCP463x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4632-502", MCP463x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4632-103", MCP463x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4632-503", MCP463x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4632-104", MCP463x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4641-502", MCP464x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4641-103", MCP464x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4641-503", MCP464x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4641-104", MCP464x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4642-502", MCP464x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4642-103", MCP464x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4642-503", MCP464x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4642-104", MCP464x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4651-502", MCP465x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4651-103", MCP465x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4651-503", MCP465x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4651-104", MCP465x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4652-502", MCP465x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4652-103", MCP465x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4652-503", MCP465x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4652-104", MCP465x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4661-502", MCP466x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4661-103", MCP466x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4661-503", MCP466x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4661-104", MCP466x_104),
+	MCP4531_COMPATIBLE("microchip,mcp4662-502", MCP466x_502),
+	MCP4531_COMPATIBLE("microchip,mcp4662-103", MCP466x_103),
+	MCP4531_COMPATIBLE("microchip,mcp4662-503", MCP466x_503),
+	MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104),
+	{ /* sentinel */ }
+};
+#endif
+
 static int mcp4531_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
 	struct device *dev = &client->dev;
-	unsigned long devid = id->driver_data;
 	struct mcp4531_data *data;
 	struct iio_dev *indio_dev;
+	const struct of_device_id *match;
 
 	if (!i2c_check_functionality(client->adapter,
 				     I2C_FUNC_SMBUS_WORD_DATA)) {
@@ -168,12 +286,17 @@ static int mcp4531_probe(struct i2c_client *client,
 	data = iio_priv(indio_dev);
 	i2c_set_clientdata(client, indio_dev);
 	data->client = client;
-	data->devid = devid;
+
+	match = of_match_device(of_match_ptr(mcp4531_of_match), dev);
+	if (match)
+		data->cfg = of_device_get_match_data(dev);
+	else
+		data->cfg = &mcp4531_cfg[id->driver_data];
 
 	indio_dev->dev.parent = dev;
 	indio_dev->info = &mcp4531_info;
 	indio_dev->channels = mcp4531_channels;
-	indio_dev->num_channels = mcp4531_cfg[devid].wipers;
+	indio_dev->num_channels = data->cfg->wipers;
 	indio_dev->name = client->name;
 
 	return devm_iio_device_register(dev, indio_dev);
@@ -188,6 +311,14 @@ static const struct i2c_device_id mcp4531_id[] = {
 	{ "mcp4532-103", MCP453x_103 },
 	{ "mcp4532-503", MCP453x_503 },
 	{ "mcp4532-104", MCP453x_104 },
+	{ "mcp4541-502", MCP454x_502 },
+	{ "mcp4541-103", MCP454x_103 },
+	{ "mcp4541-503", MCP454x_503 },
+	{ "mcp4541-104", MCP454x_104 },
+	{ "mcp4542-502", MCP454x_502 },
+	{ "mcp4542-103", MCP454x_103 },
+	{ "mcp4542-503", MCP454x_503 },
+	{ "mcp4542-104", MCP454x_104 },
 	{ "mcp4551-502", MCP455x_502 },
 	{ "mcp4551-103", MCP455x_103 },
 	{ "mcp4551-503", MCP455x_503 },
@@ -196,6 +327,14 @@ static const struct i2c_device_id mcp4531_id[] = {
 	{ "mcp4552-103", MCP455x_103 },
 	{ "mcp4552-503", MCP455x_503 },
 	{ "mcp4552-104", MCP455x_104 },
+	{ "mcp4561-502", MCP456x_502 },
+	{ "mcp4561-103", MCP456x_103 },
+	{ "mcp4561-503", MCP456x_503 },
+	{ "mcp4561-104", MCP456x_104 },
+	{ "mcp4562-502", MCP456x_502 },
+	{ "mcp4562-103", MCP456x_103 },
+	{ "mcp4562-503", MCP456x_503 },
+	{ "mcp4562-104", MCP456x_104 },
 	{ "mcp4631-502", MCP463x_502 },
 	{ "mcp4631-103", MCP463x_103 },
 	{ "mcp4631-503", MCP463x_503 },
@@ -204,6 +343,14 @@ static const struct i2c_device_id mcp4531_id[] = {
 	{ "mcp4632-103", MCP463x_103 },
 	{ "mcp4632-503", MCP463x_503 },
 	{ "mcp4632-104", MCP463x_104 },
+	{ "mcp4641-502", MCP464x_502 },
+	{ "mcp4641-103", MCP464x_103 },
+	{ "mcp4641-503", MCP464x_503 },
+	{ "mcp4641-104", MCP464x_104 },
+	{ "mcp4642-502", MCP464x_502 },
+	{ "mcp4642-103", MCP464x_103 },
+	{ "mcp4642-503", MCP464x_503 },
+	{ "mcp4642-104", MCP464x_104 },
 	{ "mcp4651-502", MCP465x_502 },
 	{ "mcp4651-103", MCP465x_103 },
 	{ "mcp4651-503", MCP465x_503 },
@@ -212,6 +359,14 @@ static const struct i2c_device_id mcp4531_id[] = {
 	{ "mcp4652-103", MCP465x_103 },
 	{ "mcp4652-503", MCP465x_503 },
 	{ "mcp4652-104", MCP465x_104 },
+	{ "mcp4661-502", MCP466x_502 },
+	{ "mcp4661-103", MCP466x_103 },
+	{ "mcp4661-503", MCP466x_503 },
+	{ "mcp4661-104", MCP466x_104 },
+	{ "mcp4662-502", MCP466x_502 },
+	{ "mcp4662-103", MCP466x_103 },
+	{ "mcp4662-503", MCP466x_503 },
+	{ "mcp4662-104", MCP466x_104 },
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, mcp4531_id);
@@ -219,6 +374,7 @@ MODULE_DEVICE_TABLE(i2c, mcp4531_id);
 static struct i2c_driver mcp4531_driver = {
 	.driver = {
 		.name	= "mcp4531",
+		.of_match_table = of_match_ptr(mcp4531_of_match),
 	},
 	.probe		= mcp4531_probe,
 	.id_table	= mcp4531_id,
diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c
index 313124b..7b6b545 100644
--- a/drivers/iio/potentiometer/tpl0102.c
+++ b/drivers/iio/potentiometer/tpl0102.c
@@ -116,10 +116,6 @@ static int tpl0102_probe(struct i2c_client *client,
 	struct tpl0102_data *data;
 	struct iio_dev *indio_dev;
 
-	if (!i2c_check_functionality(client->adapter,
-				     I2C_FUNC_SMBUS_WORD_DATA))
-		return -ENOTSUPP;
-
 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
 	if (!indio_dev)
 		return -ENOMEM;
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 31c0e1f..d130cdc 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -6,15 +6,33 @@
 menu "Pressure sensors"
 
 config BMP280
-	tristate "Bosch Sensortec BMP280 pressure sensor driver"
+	tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver"
+	depends on (I2C || SPI_MASTER)
+	depends on !(BMP085_I2C=y || BMP085_I2C=m)
+	depends on !(BMP085_SPI=y || BMP085_SPI=m)
+	select REGMAP
+	select BMP280_I2C if (I2C)
+	select BMP280_SPI if (SPI_MASTER)
+	help
+	  Say yes here to build support for Bosch Sensortec BMP180 and BMP280
+	  pressure and temperature sensors. Also supports the BE280 with
+	  an additional humidity sensor channel.
+
+	  To compile this driver as a module, choose M here: the core module
+	  will be called bmp280 and you will also get bmp280-i2c for I2C
+	  and/or bmp280-spi for SPI support.
+
+config BMP280_I2C
+	tristate
+	depends on BMP280
 	depends on I2C
 	select REGMAP_I2C
-	help
-	  Say yes here to build support for Bosch Sensortec BMP280
-	  pressure and temperature sensor.
 
-	  To compile this driver as a module, choose M here: the module
-	  will be called bmp280.
+config BMP280_SPI
+	tristate
+	depends on BMP280
+	depends on SPI_MASTER
+	select REGMAP
 
 config HID_SENSOR_PRESS
 	depends on HID_SENSOR_HUB
@@ -30,6 +48,17 @@ config HID_SENSOR_PRESS
 	  To compile this driver as a module, choose M here: the module
 	  will be called hid-sensor-press.
 
+config HP03
+	tristate "Hope RF HP03 temperature and pressure sensor driver"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Say yes here to build support for Hope RF HP03 pressure and
+	  temperature sensor.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called hp03.
+
 config MPL115
 	tristate
 
@@ -118,7 +147,7 @@ config IIO_ST_PRESS
 	select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
 	help
 	  Say yes here to build support for STMicroelectronics pressure
-	  sensors: LPS001WP, LPS25H, LPS331AP.
+	  sensors: LPS001WP, LPS25H, LPS331AP, LPS22HB.
 
 	  This driver can also be built as a module. If so, these modules
 	  will be created:
@@ -148,4 +177,14 @@ config T5403
 	  To compile this driver as a module, choose M here: the module
 	  will be called t5403.
 
+config HP206C
+	tristate "HOPERF HP206C precision barometer and altimeter sensor"
+	depends on I2C
+	help
+	  Say yes here to build support for the HOPREF HP206C precision
+	  barometer and altimeter sensor.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called hp206c.
+
 endmenu
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index d336af1..7f395be 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -4,7 +4,11 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_BMP280) += bmp280.o
+bmp280-objs := bmp280-core.o bmp280-regmap.o
+obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o
+obj-$(CONFIG_BMP280_SPI) += bmp280-spi.o
 obj-$(CONFIG_HID_SENSOR_PRESS)   += hid-sensor-press.o
+obj-$(CONFIG_HP03) += hp03.o
 obj-$(CONFIG_MPL115) += mpl115.o
 obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o
 obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o
@@ -17,6 +21,7 @@ obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
 st_pressure-y := st_pressure_core.o
 st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
 obj-$(CONFIG_T5403) += t5403.o
+obj-$(CONFIG_HP206C) += hp206c.o
 
 obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o
 obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o
diff --git b/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
new file mode 100644
index 0000000..6943688
--- /dev/null
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -0,0 +1,1117 @@
+/*
+ * Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com>
+ * Copyright (c) 2012 Bosch Sensortec GmbH
+ * Copyright (c) 2012 Unixphere AB
+ * Copyright (c) 2014 Intel Corporation
+ * Copyright (c) 2016 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor.
+ *
+ * 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.
+ *
+ * Datasheet:
+ * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf
+ * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP280-DS001-12.pdf
+ * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf
+ */
+
+#define pr_fmt(fmt) "bmp280: " fmt
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h> /* For irq_get_irq_data() */
+#include <linux/completion.h>
+#include <linux/pm_runtime.h>
+#include <linux/random.h>
+
+#include "bmp280.h"
+
+/*
+ * These enums are used for indexing into the array of calibration
+ * coefficients for BMP180.
+ */
+enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
+
+struct bmp180_calib {
+	s16 AC1;
+	s16 AC2;
+	s16 AC3;
+	u16 AC4;
+	u16 AC5;
+	u16 AC6;
+	s16 B1;
+	s16 B2;
+	s16 MB;
+	s16 MC;
+	s16 MD;
+};
+
+struct bmp280_data {
+	struct device *dev;
+	struct mutex lock;
+	struct regmap *regmap;
+	struct completion done;
+	bool use_eoc;
+	const struct bmp280_chip_info *chip_info;
+	struct bmp180_calib calib;
+	struct regulator *vddd;
+	struct regulator *vdda;
+	unsigned int start_up_time; /* in milliseconds */
+
+	/* log of base 2 of oversampling rate */
+	u8 oversampling_press;
+	u8 oversampling_temp;
+	u8 oversampling_humid;
+
+	/*
+	 * Carryover value from temperature conversion, used in pressure
+	 * calculation.
+	 */
+	s32 t_fine;
+};
+
+struct bmp280_chip_info {
+	const int *oversampling_temp_avail;
+	int num_oversampling_temp_avail;
+
+	const int *oversampling_press_avail;
+	int num_oversampling_press_avail;
+
+	const int *oversampling_humid_avail;
+	int num_oversampling_humid_avail;
+
+	int (*chip_config)(struct bmp280_data *);
+	int (*read_temp)(struct bmp280_data *, int *);
+	int (*read_press)(struct bmp280_data *, int *, int *);
+	int (*read_humid)(struct bmp280_data *, int *, int *);
+};
+
+/*
+ * These enums are used for indexing into the array of compensation
+ * parameters for BMP280.
+ */
+enum { T1, T2, T3 };
+enum { P1, P2, P3, P4, P5, P6, P7, P8, P9 };
+
+static const struct iio_chan_spec bmp280_channels[] = {
+	{
+		.type = IIO_PRESSURE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+	},
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+	},
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+	},
+};
+
+/*
+ * Returns humidity in percent, resolution is 0.01 percent. Output value of
+ * "47445" represents 47445/1024 = 46.333 %RH.
+ *
+ * Taken from BME280 datasheet, Section 4.2.3, "Compensation formula".
+ */
+
+static u32 bmp280_compensate_humidity(struct bmp280_data *data,
+				      s32 adc_humidity)
+{
+	struct device *dev = data->dev;
+	unsigned int H1, H3, tmp;
+	int H2, H4, H5, H6, ret, var;
+
+	ret = regmap_read(data->regmap, BMP280_REG_COMP_H1, &H1);
+	if (ret < 0) {
+		dev_err(dev, "failed to read H1 comp value\n");
+		return ret;
+	}
+
+	ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &tmp, 2);
+	if (ret < 0) {
+		dev_err(dev, "failed to read H2 comp value\n");
+		return ret;
+	}
+	H2 = sign_extend32(le16_to_cpu(tmp), 15);
+
+	ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &H3);
+	if (ret < 0) {
+		dev_err(dev, "failed to read H3 comp value\n");
+		return ret;
+	}
+
+	ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &tmp, 2);
+	if (ret < 0) {
+		dev_err(dev, "failed to read H4 comp value\n");
+		return ret;
+	}
+	H4 = sign_extend32(((be16_to_cpu(tmp) >> 4) & 0xff0) |
+			  (be16_to_cpu(tmp) & 0xf), 11);
+
+	ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &tmp, 2);
+	if (ret < 0) {
+		dev_err(dev, "failed to read H5 comp value\n");
+		return ret;
+	}
+	H5 = sign_extend32(((le16_to_cpu(tmp) >> 4) & 0xfff), 11);
+
+	ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp);
+	if (ret < 0) {
+		dev_err(dev, "failed to read H6 comp value\n");
+		return ret;
+	}
+	H6 = sign_extend32(tmp, 7);
+
+	var = ((s32)data->t_fine) - 76800;
+	var = ((((adc_humidity << 14) - (H4 << 20) - (H5 * var)) + 16384) >> 15)
+		* (((((((var * H6) >> 10) * (((var * H3) >> 11) + 32768)) >> 10)
+		+ 2097152) * H2 + 8192) >> 14);
+	var -= ((((var >> 15) * (var >> 15)) >> 7) * H1) >> 4;
+
+	return var >> 12;
+};
+
+/*
+ * Returns temperature in DegC, resolution is 0.01 DegC.  Output value of
+ * "5123" equals 51.23 DegC.  t_fine carries fine temperature as global
+ * value.
+ *
+ * Taken from datasheet, Section 3.11.3, "Compensation formula".
+ */
+static s32 bmp280_compensate_temp(struct bmp280_data *data,
+				  s32 adc_temp)
+{
+	int ret;
+	s32 var1, var2;
+	__le16 buf[BMP280_COMP_TEMP_REG_COUNT / 2];
+
+	ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
+			       buf, BMP280_COMP_TEMP_REG_COUNT);
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to read temperature calibration parameters\n");
+		return ret;
+	}
+
+	/*
+	 * The double casts are necessary because le16_to_cpu returns an
+	 * unsigned 16-bit value.  Casting that value directly to a
+	 * signed 32-bit will not do proper sign extension.
+	 *
+	 * Conversely, T1 and P1 are unsigned values, so they can be
+	 * cast straight to the larger type.
+	 */
+	var1 = (((adc_temp >> 3) - ((s32)le16_to_cpu(buf[T1]) << 1)) *
+		((s32)(s16)le16_to_cpu(buf[T2]))) >> 11;
+	var2 = (((((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1]))) *
+		  ((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1])))) >> 12) *
+		((s32)(s16)le16_to_cpu(buf[T3]))) >> 14;
+	data->t_fine = var1 + var2;
+
+	return (data->t_fine * 5 + 128) >> 8;
+}
+
+/*
+ * Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24
+ * integer bits and 8 fractional bits).  Output value of "24674867"
+ * represents 24674867/256 = 96386.2 Pa = 963.862 hPa
+ *
+ * Taken from datasheet, Section 3.11.3, "Compensation formula".
+ */
+static u32 bmp280_compensate_press(struct bmp280_data *data,
+				   s32 adc_press)
+{
+	int ret;
+	s64 var1, var2, p;
+	__le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2];
+
+	ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
+			       buf, BMP280_COMP_PRESS_REG_COUNT);
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to read pressure calibration parameters\n");
+		return ret;
+	}
+
+	var1 = ((s64)data->t_fine) - 128000;
+	var2 = var1 * var1 * (s64)(s16)le16_to_cpu(buf[P6]);
+	var2 += (var1 * (s64)(s16)le16_to_cpu(buf[P5])) << 17;
+	var2 += ((s64)(s16)le16_to_cpu(buf[P4])) << 35;
+	var1 = ((var1 * var1 * (s64)(s16)le16_to_cpu(buf[P3])) >> 8) +
+		((var1 * (s64)(s16)le16_to_cpu(buf[P2])) << 12);
+	var1 = ((((s64)1) << 47) + var1) * ((s64)le16_to_cpu(buf[P1])) >> 33;
+
+	if (var1 == 0)
+		return 0;
+
+	p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125;
+	p = div64_s64(p, var1);
+	var1 = (((s64)(s16)le16_to_cpu(buf[P9])) * (p >> 13) * (p >> 13)) >> 25;
+	var2 = (((s64)(s16)le16_to_cpu(buf[P8])) * p) >> 19;
+	p = ((p + var1 + var2) >> 8) + (((s64)(s16)le16_to_cpu(buf[P7])) << 4);
+
+	return (u32)p;
+}
+
+static int bmp280_read_temp(struct bmp280_data *data,
+			    int *val)
+{
+	int ret;
+	__be32 tmp = 0;
+	s32 adc_temp, comp_temp;
+
+	ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
+			       (u8 *) &tmp, 3);
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read temperature\n");
+		return ret;
+	}
+
+	adc_temp = be32_to_cpu(tmp) >> 12;
+	comp_temp = bmp280_compensate_temp(data, adc_temp);
+
+	/*
+	 * val might be NULL if we're called by the read_press routine,
+	 * who only cares about the carry over t_fine value.
+	 */
+	if (val) {
+		*val = comp_temp * 10;
+		return IIO_VAL_INT;
+	}
+
+	return 0;
+}
+
+static int bmp280_read_press(struct bmp280_data *data,
+			     int *val, int *val2)
+{
+	int ret;
+	__be32 tmp = 0;
+	s32 adc_press;
+	u32 comp_press;
+
+	/* Read and compensate temperature so we get a reading of t_fine. */
+	ret = bmp280_read_temp(data, NULL);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
+			       (u8 *) &tmp, 3);
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read pressure\n");
+		return ret;
+	}
+
+	adc_press = be32_to_cpu(tmp) >> 12;
+	comp_press = bmp280_compensate_press(data, adc_press);
+
+	*val = comp_press;
+	*val2 = 256000;
+
+	return IIO_VAL_FRACTIONAL;
+}
+
+static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2)
+{
+	int ret;
+	__be16 tmp = 0;
+	s32 adc_humidity;
+	u32 comp_humidity;
+
+	/* Read and compensate temperature so we get a reading of t_fine. */
+	ret = bmp280_read_temp(data, NULL);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB,
+			       (u8 *) &tmp, 2);
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read humidity\n");
+		return ret;
+	}
+
+	adc_humidity = be16_to_cpu(tmp);
+	comp_humidity = bmp280_compensate_humidity(data, adc_humidity);
+
+	*val = comp_humidity;
+	*val2 = 1024;
+
+	return IIO_VAL_FRACTIONAL;
+}
+
+static int bmp280_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	int ret;
+	struct bmp280_data *data = iio_priv(indio_dev);
+
+	pm_runtime_get_sync(data->dev);
+	mutex_lock(&data->lock);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (chan->type) {
+		case IIO_HUMIDITYRELATIVE:
+			ret = data->chip_info->read_humid(data, val, val2);
+			break;
+		case IIO_PRESSURE:
+			ret = data->chip_info->read_press(data, val, val2);
+			break;
+		case IIO_TEMP:
+			ret = data->chip_info->read_temp(data, val);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		switch (chan->type) {
+		case IIO_HUMIDITYRELATIVE:
+			*val = 1 << data->oversampling_humid;
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_PRESSURE:
+			*val = 1 << data->oversampling_press;
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_TEMP:
+			*val = 1 << data->oversampling_temp;
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&data->lock);
+	pm_runtime_mark_last_busy(data->dev);
+	pm_runtime_put_autosuspend(data->dev);
+
+	return ret;
+}
+
+static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data,
+					       int val)
+{
+	int i;
+	const int *avail = data->chip_info->oversampling_humid_avail;
+	const int n = data->chip_info->num_oversampling_humid_avail;
+
+	for (i = 0; i < n; i++) {
+		if (avail[i] == val) {
+			data->oversampling_humid = ilog2(val);
+
+			return data->chip_info->chip_config(data);
+		}
+	}
+	return -EINVAL;
+}
+
+static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data,
+					       int val)
+{
+	int i;
+	const int *avail = data->chip_info->oversampling_temp_avail;
+	const int n = data->chip_info->num_oversampling_temp_avail;
+
+	for (i = 0; i < n; i++) {
+		if (avail[i] == val) {
+			data->oversampling_temp = ilog2(val);
+
+			return data->chip_info->chip_config(data);
+		}
+	}
+	return -EINVAL;
+}
+
+static int bmp280_write_oversampling_ratio_press(struct bmp280_data *data,
+					       int val)
+{
+	int i;
+	const int *avail = data->chip_info->oversampling_press_avail;
+	const int n = data->chip_info->num_oversampling_press_avail;
+
+	for (i = 0; i < n; i++) {
+		if (avail[i] == val) {
+			data->oversampling_press = ilog2(val);
+
+			return data->chip_info->chip_config(data);
+		}
+	}
+	return -EINVAL;
+}
+
+static int bmp280_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	int ret = 0;
+	struct bmp280_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		pm_runtime_get_sync(data->dev);
+		mutex_lock(&data->lock);
+		switch (chan->type) {
+		case IIO_HUMIDITYRELATIVE:
+			ret = bmp280_write_oversampling_ratio_humid(data, val);
+			break;
+		case IIO_PRESSURE:
+			ret = bmp280_write_oversampling_ratio_press(data, val);
+			break;
+		case IIO_TEMP:
+			ret = bmp280_write_oversampling_ratio_temp(data, val);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
+		mutex_unlock(&data->lock);
+		pm_runtime_mark_last_busy(data->dev);
+		pm_runtime_put_autosuspend(data->dev);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static ssize_t bmp280_show_avail(char *buf, const int *vals, const int n)
+{
+	size_t len = 0;
+	int i;
+
+	for (i = 0; i < n; i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", vals[i]);
+
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static ssize_t bmp280_show_temp_oversampling_avail(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev));
+
+	return bmp280_show_avail(buf, data->chip_info->oversampling_temp_avail,
+				 data->chip_info->num_oversampling_temp_avail);
+}
+
+static ssize_t bmp280_show_press_oversampling_avail(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev));
+
+	return bmp280_show_avail(buf, data->chip_info->oversampling_press_avail,
+				 data->chip_info->num_oversampling_press_avail);
+}
+
+static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available,
+	S_IRUGO, bmp280_show_temp_oversampling_avail, NULL, 0);
+
+static IIO_DEVICE_ATTR(in_pressure_oversampling_ratio_available,
+	S_IRUGO, bmp280_show_press_oversampling_avail, NULL, 0);
+
+static struct attribute *bmp280_attributes[] = {
+	&iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr,
+	&iio_dev_attr_in_pressure_oversampling_ratio_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group bmp280_attrs_group = {
+	.attrs = bmp280_attributes,
+};
+
+static const struct iio_info bmp280_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &bmp280_read_raw,
+	.write_raw = &bmp280_write_raw,
+	.attrs = &bmp280_attrs_group,
+};
+
+static int bmp280_chip_config(struct bmp280_data *data)
+{
+	int ret;
+	u8 osrs = BMP280_OSRS_TEMP_X(data->oversampling_temp + 1) |
+		  BMP280_OSRS_PRESS_X(data->oversampling_press + 1);
+
+	ret = regmap_update_bits(data->regmap, BMP280_REG_CTRL_MEAS,
+				 BMP280_OSRS_TEMP_MASK |
+				 BMP280_OSRS_PRESS_MASK |
+				 BMP280_MODE_MASK,
+				 osrs | BMP280_MODE_NORMAL);
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to write ctrl_meas register\n");
+		return ret;
+	}
+
+	ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
+				 BMP280_FILTER_MASK,
+				 BMP280_FILTER_4X);
+	if (ret < 0) {
+		dev_err(data->dev,
+			"failed to write config register\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
+
+static const struct bmp280_chip_info bmp280_chip_info = {
+	.oversampling_temp_avail = bmp280_oversampling_avail,
+	.num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail),
+
+	.oversampling_press_avail = bmp280_oversampling_avail,
+	.num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
+
+	.chip_config = bmp280_chip_config,
+	.read_temp = bmp280_read_temp,
+	.read_press = bmp280_read_press,
+};
+
+static int bme280_chip_config(struct bmp280_data *data)
+{
+	int ret = bmp280_chip_config(data);
+	u8 osrs = BMP280_OSRS_HUMIDITIY_X(data->oversampling_humid + 1);
+
+	if (ret < 0)
+		return ret;
+
+	return regmap_update_bits(data->regmap, BMP280_REG_CTRL_HUMIDITY,
+				  BMP280_OSRS_HUMIDITY_MASK, osrs);
+}
+
+static const struct bmp280_chip_info bme280_chip_info = {
+	.oversampling_temp_avail = bmp280_oversampling_avail,
+	.num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail),
+
+	.oversampling_press_avail = bmp280_oversampling_avail,
+	.num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
+
+	.oversampling_humid_avail = bmp280_oversampling_avail,
+	.num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail),
+
+	.chip_config = bme280_chip_config,
+	.read_temp = bmp280_read_temp,
+	.read_press = bmp280_read_press,
+	.read_humid = bmp280_read_humid,
+};
+
+static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas)
+{
+	int ret;
+	const int conversion_time_max[] = { 4500, 7500, 13500, 25500 };
+	unsigned int delay_us;
+	unsigned int ctrl;
+
+	if (data->use_eoc)
+		init_completion(&data->done);
+
+	ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas);
+	if (ret)
+		return ret;
+
+	if (data->use_eoc) {
+		/*
+		 * If we have a completion interrupt, use it, wait up to
+		 * 100ms. The longest conversion time listed is 76.5 ms for
+		 * advanced resolution mode.
+		 */
+		ret = wait_for_completion_timeout(&data->done,
+						  1 + msecs_to_jiffies(100));
+		if (!ret)
+			dev_err(data->dev, "timeout waiting for completion\n");
+	} else {
+		if (ctrl_meas == BMP180_MEAS_TEMP)
+			delay_us = 4500;
+		else
+			delay_us =
+				conversion_time_max[data->oversampling_press];
+
+		usleep_range(delay_us, delay_us + 1000);
+	}
+
+	ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl);
+	if (ret)
+		return ret;
+
+	/* The value of this bit reset to "0" after conversion is complete */
+	if (ctrl & BMP180_MEAS_SCO)
+		return -EIO;
+
+	return 0;
+}
+
+static int bmp180_read_adc_temp(struct bmp280_data *data, int *val)
+{
+	int ret;
+	__be16 tmp = 0;
+
+	ret = bmp180_measure(data, BMP180_MEAS_TEMP);
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, (u8 *)&tmp, 2);
+	if (ret)
+		return ret;
+
+	*val = be16_to_cpu(tmp);
+
+	return 0;
+}
+
+static int bmp180_read_calib(struct bmp280_data *data,
+			     struct bmp180_calib *calib)
+{
+	int ret;
+	int i;
+	__be16 buf[BMP180_REG_CALIB_COUNT / 2];
+
+	ret = regmap_bulk_read(data->regmap, BMP180_REG_CALIB_START, buf,
+			       sizeof(buf));
+
+	if (ret < 0)
+		return ret;
+
+	/* None of the words has the value 0 or 0xFFFF */
+	for (i = 0; i < ARRAY_SIZE(buf); i++) {
+		if (buf[i] == cpu_to_be16(0) || buf[i] == cpu_to_be16(0xffff))
+			return -EIO;
+	}
+
+	/* Toss the calibration data into the entropy pool */
+	add_device_randomness(buf, sizeof(buf));
+
+	calib->AC1 = be16_to_cpu(buf[AC1]);
+	calib->AC2 = be16_to_cpu(buf[AC2]);
+	calib->AC3 = be16_to_cpu(buf[AC3]);
+	calib->AC4 = be16_to_cpu(buf[AC4]);
+	calib->AC5 = be16_to_cpu(buf[AC5]);
+	calib->AC6 = be16_to_cpu(buf[AC6]);
+	calib->B1 = be16_to_cpu(buf[B1]);
+	calib->B2 = be16_to_cpu(buf[B2]);
+	calib->MB = be16_to_cpu(buf[MB]);
+	calib->MC = be16_to_cpu(buf[MC]);
+	calib->MD = be16_to_cpu(buf[MD]);
+
+	return 0;
+}
+
+/*
+ * Returns temperature in DegC, resolution is 0.1 DegC.
+ * t_fine carries fine temperature as global value.
+ *
+ * Taken from datasheet, Section 3.5, "Calculating pressure and temperature".
+ */
+static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp)
+{
+	s32 x1, x2;
+	struct bmp180_calib *calib = &data->calib;
+
+	x1 = ((adc_temp - calib->AC6) * calib->AC5) >> 15;
+	x2 = (calib->MC << 11) / (x1 + calib->MD);
+	data->t_fine = x1 + x2;
+
+	return (data->t_fine + 8) >> 4;
+}
+
+static int bmp180_read_temp(struct bmp280_data *data, int *val)
+{
+	int ret;
+	s32 adc_temp, comp_temp;
+
+	ret = bmp180_read_adc_temp(data, &adc_temp);
+	if (ret)
+		return ret;
+
+	comp_temp = bmp180_compensate_temp(data, adc_temp);
+
+	/*
+	 * val might be NULL if we're called by the read_press routine,
+	 * who only cares about the carry over t_fine value.
+	 */
+	if (val) {
+		*val = comp_temp * 100;
+		return IIO_VAL_INT;
+	}
+
+	return 0;
+}
+
+static int bmp180_read_adc_press(struct bmp280_data *data, int *val)
+{
+	int ret;
+	__be32 tmp = 0;
+	u8 oss = data->oversampling_press;
+
+	ret = bmp180_measure(data, BMP180_MEAS_PRESS_X(oss));
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, (u8 *)&tmp, 3);
+	if (ret)
+		return ret;
+
+	*val = (be32_to_cpu(tmp) >> 8) >> (8 - oss);
+
+	return 0;
+}
+
+/*
+ * Returns pressure in Pa, resolution is 1 Pa.
+ *
+ * Taken from datasheet, Section 3.5, "Calculating pressure and temperature".
+ */
+static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press)
+{
+	s32 x1, x2, x3, p;
+	s32 b3, b6;
+	u32 b4, b7;
+	s32 oss = data->oversampling_press;
+	struct bmp180_calib *calib = &data->calib;
+
+	b6 = data->t_fine - 4000;
+	x1 = (calib->B2 * (b6 * b6 >> 12)) >> 11;
+	x2 = calib->AC2 * b6 >> 11;
+	x3 = x1 + x2;
+	b3 = ((((s32)calib->AC1 * 4 + x3) << oss) + 2) / 4;
+	x1 = calib->AC3 * b6 >> 13;
+	x2 = (calib->B1 * ((b6 * b6) >> 12)) >> 16;
+	x3 = (x1 + x2 + 2) >> 2;
+	b4 = calib->AC4 * (u32)(x3 + 32768) >> 15;
+	b7 = ((u32)adc_press - b3) * (50000 >> oss);
+	if (b7 < 0x80000000)
+		p = (b7 * 2) / b4;
+	else
+		p = (b7 / b4) * 2;
+
+	x1 = (p >> 8) * (p >> 8);
+	x1 = (x1 * 3038) >> 16;
+	x2 = (-7357 * p) >> 16;
+
+	return p + ((x1 + x2 + 3791) >> 4);
+}
+
+static int bmp180_read_press(struct bmp280_data *data,
+			     int *val, int *val2)
+{
+	int ret;
+	s32 adc_press;
+	u32 comp_press;
+
+	/* Read and compensate temperature so we get a reading of t_fine. */
+	ret = bmp180_read_temp(data, NULL);
+	if (ret)
+		return ret;
+
+	ret = bmp180_read_adc_press(data, &adc_press);
+	if (ret)
+		return ret;
+
+	comp_press = bmp180_compensate_press(data, adc_press);
+
+	*val = comp_press;
+	*val2 = 1000;
+
+	return IIO_VAL_FRACTIONAL;
+}
+
+static int bmp180_chip_config(struct bmp280_data *data)
+{
+	return 0;
+}
+
+static const int bmp180_oversampling_temp_avail[] = { 1 };
+static const int bmp180_oversampling_press_avail[] = { 1, 2, 4, 8 };
+
+static const struct bmp280_chip_info bmp180_chip_info = {
+	.oversampling_temp_avail = bmp180_oversampling_temp_avail,
+	.num_oversampling_temp_avail =
+		ARRAY_SIZE(bmp180_oversampling_temp_avail),
+
+	.oversampling_press_avail = bmp180_oversampling_press_avail,
+	.num_oversampling_press_avail =
+		ARRAY_SIZE(bmp180_oversampling_press_avail),
+
+	.chip_config = bmp180_chip_config,
+	.read_temp = bmp180_read_temp,
+	.read_press = bmp180_read_press,
+};
+
+static irqreturn_t bmp085_eoc_irq(int irq, void *d)
+{
+	struct bmp280_data *data = d;
+
+	complete(&data->done);
+
+	return IRQ_HANDLED;
+}
+
+static int bmp085_fetch_eoc_irq(struct device *dev,
+				const char *name,
+				int irq,
+				struct bmp280_data *data)
+{
+	unsigned long irq_trig;
+	int ret;
+
+	irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
+	if (irq_trig != IRQF_TRIGGER_RISING) {
+		dev_err(dev, "non-rising trigger given for EOC interrupt, "
+			"trying to enforce it\n");
+		irq_trig = IRQF_TRIGGER_RISING;
+	}
+	ret = devm_request_threaded_irq(dev,
+			irq,
+			bmp085_eoc_irq,
+			NULL,
+			irq_trig,
+			name,
+			data);
+	if (ret) {
+		/* Bail out without IRQ but keep the driver in place */
+		dev_err(dev, "unable to request DRDY IRQ\n");
+		return 0;
+	}
+
+	data->use_eoc = true;
+	return 0;
+}
+
+int bmp280_common_probe(struct device *dev,
+			struct regmap *regmap,
+			unsigned int chip,
+			const char *name,
+			int irq)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct bmp280_data *data;
+	unsigned int chip_id;
+	struct gpio_desc *gpiod;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	mutex_init(&data->lock);
+	data->dev = dev;
+
+	indio_dev->dev.parent = dev;
+	indio_dev->name = name;
+	indio_dev->channels = bmp280_channels;
+	indio_dev->info = &bmp280_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	switch (chip) {
+	case BMP180_CHIP_ID:
+		indio_dev->num_channels = 2;
+		data->chip_info = &bmp180_chip_info;
+		data->oversampling_press = ilog2(8);
+		data->oversampling_temp = ilog2(1);
+		data->start_up_time = 10;
+		break;
+	case BMP280_CHIP_ID:
+		indio_dev->num_channels = 2;
+		data->chip_info = &bmp280_chip_info;
+		data->oversampling_press = ilog2(16);
+		data->oversampling_temp = ilog2(2);
+		data->start_up_time = 2;
+		break;
+	case BME280_CHIP_ID:
+		indio_dev->num_channels = 3;
+		data->chip_info = &bme280_chip_info;
+		data->oversampling_press = ilog2(16);
+		data->oversampling_humid = ilog2(16);
+		data->oversampling_temp = ilog2(2);
+		data->start_up_time = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Bring up regulators */
+	data->vddd = devm_regulator_get(dev, "vddd");
+	if (IS_ERR(data->vddd)) {
+		dev_err(dev, "failed to get VDDD regulator\n");
+		return PTR_ERR(data->vddd);
+	}
+	ret = regulator_enable(data->vddd);
+	if (ret) {
+		dev_err(dev, "failed to enable VDDD regulator\n");
+		return ret;
+	}
+	data->vdda = devm_regulator_get(dev, "vdda");
+	if (IS_ERR(data->vdda)) {
+		dev_err(dev, "failed to get VDDA regulator\n");
+		ret = PTR_ERR(data->vddd);
+		goto out_disable_vddd;
+	}
+	ret = regulator_enable(data->vdda);
+	if (ret) {
+		dev_err(dev, "failed to enable VDDA regulator\n");
+		goto out_disable_vddd;
+	}
+	/* Wait to make sure we started up properly */
+	mdelay(data->start_up_time);
+
+	/* Bring chip out of reset if there is an assigned GPIO line */
+	gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+	/* Deassert the signal */
+	if (!IS_ERR(gpiod)) {
+		dev_info(dev, "release reset\n");
+		gpiod_set_value(gpiod, 0);
+	}
+
+	data->regmap = regmap;
+	ret = regmap_read(regmap, BMP280_REG_ID, &chip_id);
+	if (ret < 0)
+		goto out_disable_vdda;
+	if (chip_id != chip) {
+		dev_err(dev, "bad chip id: expected %x got %x\n",
+			chip, chip_id);
+		ret = -EINVAL;
+		goto out_disable_vdda;
+	}
+
+	ret = data->chip_info->chip_config(data);
+	if (ret < 0)
+		goto out_disable_vdda;
+
+	dev_set_drvdata(dev, indio_dev);
+
+	/*
+	 * The BMP085 and BMP180 has calibration in an E2PROM, read it out
+	 * at probe time. It will not change.
+	 */
+	if (chip_id  == BMP180_CHIP_ID) {
+		ret = bmp180_read_calib(data, &data->calib);
+		if (ret < 0) {
+			dev_err(data->dev,
+				"failed to read calibration coefficients\n");
+			goto out_disable_vdda;
+		}
+	}
+
+	/*
+	 * Attempt to grab an optional EOC IRQ - only the BMP085 has this
+	 * however as it happens, the BMP085 shares the chip ID of BMP180
+	 * so we look for an IRQ if we have that.
+	 */
+	if (irq > 0 || (chip_id  == BMP180_CHIP_ID)) {
+		ret = bmp085_fetch_eoc_irq(dev, name, irq, data);
+		if (ret)
+			goto out_disable_vdda;
+	}
+
+	/* Enable runtime PM */
+	pm_runtime_get_noresume(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	/*
+	 * Set autosuspend to two orders of magnitude larger than the
+	 * start-up time.
+	 */
+	pm_runtime_set_autosuspend_delay(dev, data->start_up_time *100);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_put(dev);
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto out_runtime_pm_disable;
+
+
+	return 0;
+
+out_runtime_pm_disable:
+	pm_runtime_get_sync(data->dev);
+	pm_runtime_put_noidle(data->dev);
+	pm_runtime_disable(data->dev);
+out_disable_vdda:
+	regulator_disable(data->vdda);
+out_disable_vddd:
+	regulator_disable(data->vddd);
+	return ret;
+}
+EXPORT_SYMBOL(bmp280_common_probe);
+
+int bmp280_common_remove(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct bmp280_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	pm_runtime_get_sync(data->dev);
+	pm_runtime_put_noidle(data->dev);
+	pm_runtime_disable(data->dev);
+	regulator_disable(data->vdda);
+	regulator_disable(data->vddd);
+	return 0;
+}
+EXPORT_SYMBOL(bmp280_common_remove);
+
+#ifdef CONFIG_PM
+static int bmp280_runtime_suspend(struct device *dev)
+{
+	struct bmp280_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_disable(data->vdda);
+	if (ret)
+		return ret;
+	return regulator_disable(data->vddd);
+}
+
+static int bmp280_runtime_resume(struct device *dev)
+{
+	struct bmp280_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = regulator_enable(data->vddd);
+	if (ret)
+		return ret;
+	ret = regulator_enable(data->vdda);
+	if (ret)
+		return ret;
+	msleep(data->start_up_time);
+	return data->chip_info->chip_config(data);
+}
+#endif /* CONFIG_PM */
+
+const struct dev_pm_ops bmp280_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+	SET_RUNTIME_PM_OPS(bmp280_runtime_suspend,
+			   bmp280_runtime_resume, NULL)
+};
+EXPORT_SYMBOL(bmp280_dev_pm_ops);
+
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c
new file mode 100644
index 0000000..03742b1
--- /dev/null
+++ b/drivers/iio/pressure/bmp280-i2c.c
@@ -0,0 +1,91 @@
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include "bmp280.h"
+
+static int bmp280_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	const struct regmap_config *regmap_config;
+
+	switch (id->driver_data) {
+	case BMP180_CHIP_ID:
+		regmap_config = &bmp180_regmap_config;
+		break;
+	case BMP280_CHIP_ID:
+	case BME280_CHIP_ID:
+		regmap_config = &bmp280_regmap_config;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap = devm_regmap_init_i2c(client, regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&client->dev, "failed to allocate register map\n");
+		return PTR_ERR(regmap);
+	}
+
+	return bmp280_common_probe(&client->dev,
+				   regmap,
+				   id->driver_data,
+				   id->name,
+				   client->irq);
+}
+
+static int bmp280_i2c_remove(struct i2c_client *client)
+{
+	return bmp280_common_remove(&client->dev);
+}
+
+static const struct acpi_device_id bmp280_acpi_i2c_match[] = {
+	{"BMP0280", BMP280_CHIP_ID },
+	{"BMP0180", BMP180_CHIP_ID },
+	{"BMP0085", BMP180_CHIP_ID },
+	{"BME0280", BME280_CHIP_ID },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, bmp280_acpi_i2c_match);
+
+#ifdef CONFIG_OF
+static const struct of_device_id bmp280_of_i2c_match[] = {
+	{ .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID },
+	{ .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID },
+	{ .compatible = "bosch,bmp180", .data = (void *)BMP180_CHIP_ID },
+	{ .compatible = "bosch,bmp085", .data = (void *)BMP180_CHIP_ID },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match);
+#else
+#define bmp280_of_i2c_match NULL
+#endif
+
+static const struct i2c_device_id bmp280_i2c_id[] = {
+	{"bmp280", BMP280_CHIP_ID },
+	{"bmp180", BMP180_CHIP_ID },
+	{"bmp085", BMP180_CHIP_ID },
+	{"bme280", BME280_CHIP_ID },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id);
+
+static struct i2c_driver bmp280_i2c_driver = {
+	.driver = {
+		.name	= "bmp280",
+		.acpi_match_table = ACPI_PTR(bmp280_acpi_i2c_match),
+		.of_match_table = of_match_ptr(bmp280_of_i2c_match),
+		.pm = &bmp280_dev_pm_ops,
+	},
+	.probe		= bmp280_i2c_probe,
+	.remove		= bmp280_i2c_remove,
+	.id_table	= bmp280_i2c_id,
+};
+module_i2c_driver(bmp280_i2c_driver);
+
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c
new file mode 100644
index 0000000..6807113
--- /dev/null
+++ b/drivers/iio/pressure/bmp280-regmap.c
@@ -0,0 +1,84 @@
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "bmp280.h"
+
+static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case BMP280_REG_CTRL_MEAS:
+	case BMP280_REG_RESET:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool bmp180_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case BMP180_REG_OUT_XLSB:
+	case BMP180_REG_OUT_LSB:
+	case BMP180_REG_OUT_MSB:
+	case BMP280_REG_CTRL_MEAS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+const struct regmap_config bmp180_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = BMP180_REG_OUT_XLSB,
+	.cache_type = REGCACHE_RBTREE,
+
+	.writeable_reg = bmp180_is_writeable_reg,
+	.volatile_reg = bmp180_is_volatile_reg,
+};
+EXPORT_SYMBOL(bmp180_regmap_config);
+
+static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case BMP280_REG_CONFIG:
+	case BMP280_REG_CTRL_HUMIDITY:
+	case BMP280_REG_CTRL_MEAS:
+	case BMP280_REG_RESET:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case BMP280_REG_HUMIDITY_LSB:
+	case BMP280_REG_HUMIDITY_MSB:
+	case BMP280_REG_TEMP_XLSB:
+	case BMP280_REG_TEMP_LSB:
+	case BMP280_REG_TEMP_MSB:
+	case BMP280_REG_PRESS_XLSB:
+	case BMP280_REG_PRESS_LSB:
+	case BMP280_REG_PRESS_MSB:
+	case BMP280_REG_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+const struct regmap_config bmp280_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = BMP280_REG_HUMIDITY_LSB,
+	.cache_type = REGCACHE_RBTREE,
+
+	.writeable_reg = bmp280_is_writeable_reg,
+	.volatile_reg = bmp280_is_volatile_reg,
+};
+EXPORT_SYMBOL(bmp280_regmap_config);
diff --git b/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c
new file mode 100644
index 0000000..17bc955
--- /dev/null
+++ b/drivers/iio/pressure/bmp280-spi.c
@@ -0,0 +1,125 @@
+/*
+ * SPI interface for the BMP280 driver
+ *
+ * Inspired by the older BMP085 driver drivers/misc/bmp085-spi.c
+ */
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+
+#include "bmp280.h"
+
+static int bmp280_regmap_spi_write(void *context, const void *data,
+                                   size_t count)
+{
+	struct device *dev = context;
+	struct spi_device *spi = to_spi_device(dev);
+	u8 buf[2];
+
+	memcpy(buf, data, 2);
+	/*
+	 * The SPI register address (= full register address without bit 7) and
+	 * the write command (bit7 = RW = '0')
+	 */
+	buf[0] &= ~0x80;
+
+	return spi_write_then_read(spi, buf, 2, NULL, 0);
+}
+
+static int bmp280_regmap_spi_read(void *context, const void *reg,
+                                  size_t reg_size, void *val, size_t val_size)
+{
+	struct device *dev = context;
+	struct spi_device *spi = to_spi_device(dev);
+
+	return spi_write_then_read(spi, reg, reg_size, val, val_size);
+}
+
+static struct regmap_bus bmp280_regmap_bus = {
+	.write = bmp280_regmap_spi_write,
+	.read = bmp280_regmap_spi_read,
+	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
+	.val_format_endian_default = REGMAP_ENDIAN_BIG,
+};
+
+static int bmp280_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	struct regmap *regmap;
+	const struct regmap_config *regmap_config;
+	int ret;
+
+	spi->bits_per_word = 8;
+	ret = spi_setup(spi);
+	if (ret < 0) {
+		dev_err(&spi->dev, "spi_setup failed!\n");
+		return ret;
+	}
+
+	switch (id->driver_data) {
+	case BMP180_CHIP_ID:
+		regmap_config = &bmp180_regmap_config;
+		break;
+	case BMP280_CHIP_ID:
+	case BME280_CHIP_ID:
+		regmap_config = &bmp280_regmap_config;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	regmap = devm_regmap_init(&spi->dev,
+				  &bmp280_regmap_bus,
+				  &spi->dev,
+				  regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&spi->dev, "failed to allocate register map\n");
+		return PTR_ERR(regmap);
+	}
+
+	return bmp280_common_probe(&spi->dev,
+				   regmap,
+				   id->driver_data,
+				   id->name,
+				   spi->irq);
+}
+
+static int bmp280_spi_remove(struct spi_device *spi)
+{
+	return bmp280_common_remove(&spi->dev);
+}
+
+static const struct of_device_id bmp280_of_spi_match[] = {
+	{ .compatible = "bosch,bmp085", },
+	{ .compatible = "bosch,bmp180", },
+	{ .compatible = "bosch,bmp181", },
+	{ .compatible = "bosch,bmp280", },
+	{ .compatible = "bosch,bme280", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bmp280_of_spi_match);
+
+static const struct spi_device_id bmp280_spi_id[] = {
+	{ "bmp180", BMP180_CHIP_ID },
+	{ "bmp181", BMP180_CHIP_ID },
+	{ "bmp280", BMP280_CHIP_ID },
+	{ "bme280", BME280_CHIP_ID },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, bmp280_spi_id);
+
+static struct spi_driver bmp280_spi_driver = {
+	.driver = {
+		.name = "bmp280",
+		.of_match_table = bmp280_of_spi_match,
+		.pm = &bmp280_dev_pm_ops,
+	},
+	.id_table = bmp280_spi_id,
+	.probe = bmp280_spi_probe,
+	.remove = bmp280_spi_remove,
+};
+module_spi_driver(bmp280_spi_driver);
+
+MODULE_DESCRIPTION("BMP280 SPI bus driver");
+MODULE_LICENSE("GPL");
diff --git b/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
new file mode 100644
index 0000000..2c770e1
--- /dev/null
+++ b/drivers/iio/pressure/bmp280.h
@@ -0,0 +1,112 @@
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+
+/* BMP280 specific registers */
+#define BMP280_REG_HUMIDITY_LSB		0xFE
+#define BMP280_REG_HUMIDITY_MSB		0xFD
+#define BMP280_REG_TEMP_XLSB		0xFC
+#define BMP280_REG_TEMP_LSB		0xFB
+#define BMP280_REG_TEMP_MSB		0xFA
+#define BMP280_REG_PRESS_XLSB		0xF9
+#define BMP280_REG_PRESS_LSB		0xF8
+#define BMP280_REG_PRESS_MSB		0xF7
+
+#define BMP280_REG_CONFIG		0xF5
+#define BMP280_REG_CTRL_MEAS		0xF4
+#define BMP280_REG_STATUS		0xF3
+#define BMP280_REG_CTRL_HUMIDITY	0xF2
+
+/* Due to non linear mapping, and data sizes we can't do a bulk read */
+#define BMP280_REG_COMP_H1		0xA1
+#define BMP280_REG_COMP_H2		0xE1
+#define BMP280_REG_COMP_H3		0xE3
+#define BMP280_REG_COMP_H4		0xE4
+#define BMP280_REG_COMP_H5		0xE5
+#define BMP280_REG_COMP_H6		0xE7
+
+#define BMP280_REG_COMP_TEMP_START	0x88
+#define BMP280_COMP_TEMP_REG_COUNT	6
+
+#define BMP280_REG_COMP_PRESS_START	0x8E
+#define BMP280_COMP_PRESS_REG_COUNT	18
+
+#define BMP280_FILTER_MASK		(BIT(4) | BIT(3) | BIT(2))
+#define BMP280_FILTER_OFF		0
+#define BMP280_FILTER_2X		BIT(2)
+#define BMP280_FILTER_4X		BIT(3)
+#define BMP280_FILTER_8X		(BIT(3) | BIT(2))
+#define BMP280_FILTER_16X		BIT(4)
+
+#define BMP280_OSRS_HUMIDITY_MASK	(BIT(2) | BIT(1) | BIT(0))
+#define BMP280_OSRS_HUMIDITIY_X(osrs_h)	((osrs_h) << 0)
+#define BMP280_OSRS_HUMIDITY_SKIP	0
+#define BMP280_OSRS_HUMIDITY_1X		BMP280_OSRS_HUMIDITIY_X(1)
+#define BMP280_OSRS_HUMIDITY_2X		BMP280_OSRS_HUMIDITIY_X(2)
+#define BMP280_OSRS_HUMIDITY_4X		BMP280_OSRS_HUMIDITIY_X(3)
+#define BMP280_OSRS_HUMIDITY_8X		BMP280_OSRS_HUMIDITIY_X(4)
+#define BMP280_OSRS_HUMIDITY_16X	BMP280_OSRS_HUMIDITIY_X(5)
+
+#define BMP280_OSRS_TEMP_MASK		(BIT(7) | BIT(6) | BIT(5))
+#define BMP280_OSRS_TEMP_SKIP		0
+#define BMP280_OSRS_TEMP_X(osrs_t)	((osrs_t) << 5)
+#define BMP280_OSRS_TEMP_1X		BMP280_OSRS_TEMP_X(1)
+#define BMP280_OSRS_TEMP_2X		BMP280_OSRS_TEMP_X(2)
+#define BMP280_OSRS_TEMP_4X		BMP280_OSRS_TEMP_X(3)
+#define BMP280_OSRS_TEMP_8X		BMP280_OSRS_TEMP_X(4)
+#define BMP280_OSRS_TEMP_16X		BMP280_OSRS_TEMP_X(5)
+
+#define BMP280_OSRS_PRESS_MASK		(BIT(4) | BIT(3) | BIT(2))
+#define BMP280_OSRS_PRESS_SKIP		0
+#define BMP280_OSRS_PRESS_X(osrs_p)	((osrs_p) << 2)
+#define BMP280_OSRS_PRESS_1X		BMP280_OSRS_PRESS_X(1)
+#define BMP280_OSRS_PRESS_2X		BMP280_OSRS_PRESS_X(2)
+#define BMP280_OSRS_PRESS_4X		BMP280_OSRS_PRESS_X(3)
+#define BMP280_OSRS_PRESS_8X		BMP280_OSRS_PRESS_X(4)
+#define BMP280_OSRS_PRESS_16X		BMP280_OSRS_PRESS_X(5)
+
+#define BMP280_MODE_MASK		(BIT(1) | BIT(0))
+#define BMP280_MODE_SLEEP		0
+#define BMP280_MODE_FORCED		BIT(0)
+#define BMP280_MODE_NORMAL		(BIT(1) | BIT(0))
+
+/* BMP180 specific registers */
+#define BMP180_REG_OUT_XLSB		0xF8
+#define BMP180_REG_OUT_LSB		0xF7
+#define BMP180_REG_OUT_MSB		0xF6
+
+#define BMP180_REG_CALIB_START		0xAA
+#define BMP180_REG_CALIB_COUNT		22
+
+#define BMP180_MEAS_SCO			BIT(5)
+#define BMP180_MEAS_TEMP		(0x0E | BMP180_MEAS_SCO)
+#define BMP180_MEAS_PRESS_X(oss)	((oss) << 6 | 0x14 | BMP180_MEAS_SCO)
+#define BMP180_MEAS_PRESS_1X		BMP180_MEAS_PRESS_X(0)
+#define BMP180_MEAS_PRESS_2X		BMP180_MEAS_PRESS_X(1)
+#define BMP180_MEAS_PRESS_4X		BMP180_MEAS_PRESS_X(2)
+#define BMP180_MEAS_PRESS_8X		BMP180_MEAS_PRESS_X(3)
+
+/* BMP180 and BMP280 common registers */
+#define BMP280_REG_CTRL_MEAS		0xF4
+#define BMP280_REG_RESET		0xE0
+#define BMP280_REG_ID			0xD0
+
+#define BMP180_CHIP_ID			0x55
+#define BMP280_CHIP_ID			0x58
+#define BME280_CHIP_ID			0x60
+#define BMP280_SOFT_RESET_VAL		0xB6
+
+/* Regmap configurations */
+extern const struct regmap_config bmp180_regmap_config;
+extern const struct regmap_config bmp280_regmap_config;
+
+/* Probe called from different transports */
+int bmp280_common_probe(struct device *dev,
+			struct regmap *regmap,
+			unsigned int chip,
+			const char *name,
+			int irq);
+int bmp280_common_remove(struct device *dev);
+
+/* PM ops */
+extern const struct dev_pm_ops bmp280_dev_pm_ops;
diff --git b/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c
new file mode 100644
index 0000000..ac76515
--- /dev/null
+++ b/drivers/iio/pressure/hp03.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2016 Marek Vasut <marex@denx.de>
+ *
+ * Driver for Hope RF HP03 digital temperature and pressure sensor.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) "hp03: " fmt
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/*
+ * The HP03 sensor occupies two fixed I2C addresses:
+ *  0x50 ... read-only EEPROM with calibration data
+ *  0x77 ... read-write ADC for pressure and temperature
+ */
+#define HP03_EEPROM_ADDR		0x50
+#define HP03_ADC_ADDR			0x77
+
+#define HP03_EEPROM_CX_OFFSET		0x10
+#define HP03_EEPROM_AB_OFFSET		0x1e
+#define HP03_EEPROM_CD_OFFSET		0x20
+
+#define HP03_ADC_WRITE_REG		0xff
+#define HP03_ADC_READ_REG		0xfd
+#define HP03_ADC_READ_PRESSURE		0xf0	/* D1 in datasheet */
+#define HP03_ADC_READ_TEMP		0xe8	/* D2 in datasheet */
+
+struct hp03_priv {
+	struct i2c_client	*client;
+	struct mutex		lock;
+	struct gpio_desc	*xclr_gpio;
+
+	struct i2c_client	*eeprom_client;
+	struct regmap		*eeprom_regmap;
+
+	s32			pressure;	/* kPa */
+	s32			temp;		/* Deg. C */
+};
+
+static const struct iio_chan_spec hp03_channels[] = {
+	{
+		.type = IIO_PRESSURE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+	},
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+	},
+};
+
+static bool hp03_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static bool hp03_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static const struct regmap_config hp03_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+
+	.max_register	= HP03_EEPROM_CD_OFFSET + 1,
+	.cache_type	= REGCACHE_RBTREE,
+
+	.writeable_reg	= hp03_is_writeable_reg,
+	.volatile_reg	= hp03_is_volatile_reg,
+};
+
+static int hp03_get_temp_pressure(struct hp03_priv *priv, const u8 reg)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(priv->client, HP03_ADC_WRITE_REG, reg);
+	if (ret < 0)
+		return ret;
+
+	msleep(50);	/* Wait for conversion to finish */
+
+	return i2c_smbus_read_word_data(priv->client, HP03_ADC_READ_REG);
+}
+
+static int hp03_update_temp_pressure(struct hp03_priv *priv)
+{
+	struct device *dev = &priv->client->dev;
+	u8 coefs[18];
+	u16 cx_val[7];
+	int ab_val, d1_val, d2_val, diff_val, dut, off, sens, x;
+	int i, ret;
+
+	/* Sample coefficients from EEPROM */
+	ret = regmap_bulk_read(priv->eeprom_regmap, HP03_EEPROM_CX_OFFSET,
+			       coefs, sizeof(coefs));
+	if (ret < 0) {
+		dev_err(dev, "Failed to read EEPROM (reg=%02x)\n",
+			HP03_EEPROM_CX_OFFSET);
+		return ret;
+	}
+
+	/* Sample Temperature and Pressure */
+	gpiod_set_value_cansleep(priv->xclr_gpio, 1);
+
+	ret = hp03_get_temp_pressure(priv, HP03_ADC_READ_PRESSURE);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read pressure\n");
+		goto err_adc;
+	}
+	d1_val = ret;
+
+	ret = hp03_get_temp_pressure(priv, HP03_ADC_READ_TEMP);
+	if (ret < 0) {
+		dev_err(dev, "Failed to read temperature\n");
+		goto err_adc;
+	}
+	d2_val = ret;
+
+	gpiod_set_value_cansleep(priv->xclr_gpio, 0);
+
+	/* The Cx coefficients and Temp/Pressure values are MSB first. */
+	for (i = 0; i < 7; i++)
+		cx_val[i] = (coefs[2 * i] << 8) | (coefs[(2 * i) + 1] << 0);
+	d1_val = ((d1_val >> 8) & 0xff) | ((d1_val & 0xff) << 8);
+	d2_val = ((d2_val >> 8) & 0xff) | ((d2_val & 0xff) << 8);
+
+	/* Coefficient voodoo from the HP03 datasheet. */
+	if (d2_val >= cx_val[4])
+		ab_val = coefs[14];	/* A-value */
+	else
+		ab_val = coefs[15];	/* B-value */
+
+	diff_val = d2_val - cx_val[4];
+	dut = (ab_val * (diff_val >> 7) * (diff_val >> 7)) >> coefs[16];
+	dut = diff_val - dut;
+
+	off = (cx_val[1] + (((cx_val[3] - 1024) * dut) >> 14)) * 4;
+	sens = cx_val[0] + ((cx_val[2] * dut) >> 10);
+	x = ((sens * (d1_val - 7168)) >> 14) - off;
+
+	priv->pressure = ((x * 100) >> 5) + (cx_val[6] * 10);
+	priv->temp = 250 + ((dut * cx_val[5]) >> 16) - (dut >> coefs[17]);
+
+	return 0;
+
+err_adc:
+	gpiod_set_value_cansleep(priv->xclr_gpio, 0);
+	return ret;
+}
+
+static int hp03_read_raw(struct iio_dev *indio_dev,
+			 struct iio_chan_spec const *chan,
+			 int *val, int *val2, long mask)
+{
+	struct hp03_priv *priv = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = hp03_update_temp_pressure(priv);
+	mutex_unlock(&priv->lock);
+
+	if (ret)
+		return ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_PRESSURE:
+			*val = priv->pressure;
+			return IIO_VAL_INT;
+		case IIO_TEMP:
+			*val = priv->temp;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_PRESSURE:
+			*val = 0;
+			*val2 = 1000;
+			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_TEMP:
+			*val = 10;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info hp03_info = {
+	.driver_module	= THIS_MODULE,
+	.read_raw	= &hp03_read_raw,
+};
+
+static int hp03_probe(struct i2c_client *client,
+		      const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct iio_dev *indio_dev;
+	struct hp03_priv *priv;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	priv = iio_priv(indio_dev);
+	priv->client = client;
+	mutex_init(&priv->lock);
+
+	indio_dev->dev.parent = dev;
+	indio_dev->name = id->name;
+	indio_dev->channels = hp03_channels;
+	indio_dev->num_channels = ARRAY_SIZE(hp03_channels);
+	indio_dev->info = &hp03_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	priv->xclr_gpio = devm_gpiod_get_index(dev, "xclr", 0, GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->xclr_gpio)) {
+		dev_err(dev, "Failed to claim XCLR GPIO\n");
+		ret = PTR_ERR(priv->xclr_gpio);
+		return ret;
+	}
+
+	/*
+	 * Allocate another device for the on-sensor EEPROM,
+	 * which has it's dedicated I2C address and contains
+	 * the calibration constants for the sensor.
+	 */
+	priv->eeprom_client = i2c_new_dummy(client->adapter, HP03_EEPROM_ADDR);
+	if (!priv->eeprom_client) {
+		dev_err(dev, "New EEPROM I2C device failed\n");
+		return -ENODEV;
+	}
+
+	priv->eeprom_regmap = regmap_init_i2c(priv->eeprom_client,
+					      &hp03_regmap_config);
+	if (IS_ERR(priv->eeprom_regmap)) {
+		dev_err(dev, "Failed to allocate EEPROM regmap\n");
+		ret = PTR_ERR(priv->eeprom_regmap);
+		goto err_cleanup_eeprom_client;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(dev, "Failed to register IIO device\n");
+		goto err_cleanup_eeprom_regmap;
+	}
+
+	i2c_set_clientdata(client, indio_dev);
+
+	return 0;
+
+err_cleanup_eeprom_regmap:
+	regmap_exit(priv->eeprom_regmap);
+
+err_cleanup_eeprom_client:
+	i2c_unregister_device(priv->eeprom_client);
+	return ret;
+}
+
+static int hp03_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct hp03_priv *priv = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	regmap_exit(priv->eeprom_regmap);
+	i2c_unregister_device(priv->eeprom_client);
+
+	return 0;
+}
+
+static const struct i2c_device_id hp03_id[] = {
+	{ "hp03", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, hp03_id);
+
+static struct i2c_driver hp03_driver = {
+	.driver = {
+		.name	= "hp03",
+	},
+	.probe		= hp03_probe,
+	.remove		= hp03_remove,
+	.id_table	= hp03_id,
+};
+module_i2c_driver(hp03_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Driver for Hope RF HP03 pressure and temperature sensor");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c
new file mode 100644
index 0000000..12f769e
--- /dev/null
+++ b/drivers/iio/pressure/hp206c.c
@@ -0,0 +1,427 @@
+/*
+ * hp206c.c - HOPERF HP206C precision barometer and altimeter sensor
+ *
+ * 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 slave address 0x76)
+ *
+ * Datasheet:
+ *  http://www.hoperf.com/upload/sensor/HP206C_DataSheet_EN_V2.0.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/delay.h>
+#include <linux/util_macros.h>
+#include <linux/acpi.h>
+
+/* I2C commands: */
+#define HP206C_CMD_SOFT_RST	0x06
+
+#define HP206C_CMD_ADC_CVT	0x40
+
+#define HP206C_CMD_ADC_CVT_OSR_4096	0x00
+#define HP206C_CMD_ADC_CVT_OSR_2048	0x04
+#define HP206C_CMD_ADC_CVT_OSR_1024	0x08
+#define HP206C_CMD_ADC_CVT_OSR_512	0x0c
+#define HP206C_CMD_ADC_CVT_OSR_256	0x10
+#define HP206C_CMD_ADC_CVT_OSR_128	0x14
+
+#define HP206C_CMD_ADC_CVT_CHNL_PT	0x00
+#define HP206C_CMD_ADC_CVT_CHNL_T	0x02
+
+#define HP206C_CMD_READ_P	0x30
+#define HP206C_CMD_READ_T	0x32
+
+#define HP206C_CMD_READ_REG	0x80
+#define HP206C_CMD_WRITE_REG	0xc0
+
+#define HP206C_REG_INT_EN	0x0b
+#define HP206C_REG_INT_CFG	0x0c
+
+#define HP206C_REG_INT_SRC	0x0d
+#define HP206C_FLAG_DEV_RDY	0x40
+
+#define HP206C_REG_PARA		0x0f
+#define HP206C_FLAG_CMPS_EN	0x80
+
+/* Maximum spin for DEV_RDY */
+#define HP206C_MAX_DEV_RDY_WAIT_COUNT 20
+#define HP206C_DEV_RDY_WAIT_US    20000
+
+struct hp206c_data {
+	struct mutex mutex;
+	struct i2c_client *client;
+	int temp_osr_index;
+	int pres_osr_index;
+};
+
+struct hp206c_osr_setting {
+	u8 osr_mask;
+	unsigned int temp_conv_time_us;
+	unsigned int pres_conv_time_us;
+};
+
+/* Data from Table 5 in datasheet. */
+static const struct hp206c_osr_setting hp206c_osr_settings[] = {
+	{ HP206C_CMD_ADC_CVT_OSR_4096,	65600,	131100	},
+	{ HP206C_CMD_ADC_CVT_OSR_2048,	32800,	65600	},
+	{ HP206C_CMD_ADC_CVT_OSR_1024,	16400,	32800	},
+	{ HP206C_CMD_ADC_CVT_OSR_512,	8200,	16400	},
+	{ HP206C_CMD_ADC_CVT_OSR_256,	4100,	8200	},
+	{ HP206C_CMD_ADC_CVT_OSR_128,	2100,	4100	},
+};
+static const int hp206c_osr_rates[] = { 4096, 2048, 1024, 512, 256, 128 };
+static const char hp206c_osr_rates_str[] = "4096 2048 1024 512 256 128";
+
+static inline int hp206c_read_reg(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, HP206C_CMD_READ_REG | reg);
+}
+
+static inline int hp206c_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+	return i2c_smbus_write_byte_data(client,
+			HP206C_CMD_WRITE_REG | reg, val);
+}
+
+static int hp206c_read_20bit(struct i2c_client *client, u8 cmd)
+{
+	int ret;
+	u8 values[3];
+
+	ret = i2c_smbus_read_i2c_block_data(client, cmd, 3, values);
+	if (ret < 0)
+		return ret;
+	if (ret != 3)
+		return -EIO;
+	return ((values[0] & 0xF) << 16) | (values[1] << 8) | (values[2]);
+}
+
+/* Spin for max 160ms until DEV_RDY is 1, or return error. */
+static int hp206c_wait_dev_rdy(struct iio_dev *indio_dev)
+{
+	int ret;
+	int count = 0;
+	struct hp206c_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+
+	while (++count <= HP206C_MAX_DEV_RDY_WAIT_COUNT) {
+		ret = hp206c_read_reg(client, HP206C_REG_INT_SRC);
+		if (ret < 0) {
+			dev_err(&indio_dev->dev, "Failed READ_REG INT_SRC: %d\n", ret);
+			return ret;
+		}
+		if (ret & HP206C_FLAG_DEV_RDY)
+			return 0;
+		usleep_range(HP206C_DEV_RDY_WAIT_US, HP206C_DEV_RDY_WAIT_US * 3 / 2);
+	}
+	return -ETIMEDOUT;
+}
+
+static int hp206c_set_compensation(struct i2c_client *client, bool enabled)
+{
+	int val;
+
+	val = hp206c_read_reg(client, HP206C_REG_PARA);
+	if (val < 0)
+		return val;
+	if (enabled)
+		val |= HP206C_FLAG_CMPS_EN;
+	else
+		val &= ~HP206C_FLAG_CMPS_EN;
+
+	return hp206c_write_reg(client, HP206C_REG_PARA, val);
+}
+
+/* Do a soft reset */
+static int hp206c_soft_reset(struct iio_dev *indio_dev)
+{
+	int ret;
+	struct hp206c_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+
+	ret = i2c_smbus_write_byte(client, HP206C_CMD_SOFT_RST);
+	if (ret) {
+		dev_err(&client->dev, "Failed to reset device: %d\n", ret);
+		return ret;
+	}
+
+	usleep_range(400, 600);
+
+	ret = hp206c_wait_dev_rdy(indio_dev);
+	if (ret) {
+		dev_err(&client->dev, "Device not ready after soft reset: %d\n", ret);
+		return ret;
+	}
+
+	ret = hp206c_set_compensation(client, true);
+	if (ret)
+		dev_err(&client->dev, "Failed to enable compensation: %d\n", ret);
+	return ret;
+}
+
+static int hp206c_conv_and_read(struct iio_dev *indio_dev,
+				u8 conv_cmd, u8 read_cmd,
+				unsigned int sleep_us)
+{
+	int ret;
+	struct hp206c_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+
+	ret = hp206c_wait_dev_rdy(indio_dev);
+	if (ret < 0) {
+		dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);
+		return ret;
+	}
+
+	ret = i2c_smbus_write_byte(client, conv_cmd);
+	if (ret < 0) {
+		dev_err(&indio_dev->dev, "Failed convert: %d\n", ret);
+		return ret;
+	}
+
+	usleep_range(sleep_us, sleep_us * 3 / 2);
+
+	ret = hp206c_wait_dev_rdy(indio_dev);
+	if (ret < 0) {
+		dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);
+		return ret;
+	}
+
+	ret = hp206c_read_20bit(client, read_cmd);
+	if (ret < 0)
+		dev_err(&indio_dev->dev, "Failed read: %d\n", ret);
+
+	return ret;
+}
+
+static int hp206c_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan, int *val,
+			   int *val2, long mask)
+{
+	int ret;
+	struct hp206c_data *data = iio_priv(indio_dev);
+	const struct hp206c_osr_setting *osr_setting;
+	u8 conv_cmd;
+
+	mutex_lock(&data->mutex);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		switch (chan->type) {
+		case IIO_TEMP:
+			*val = hp206c_osr_rates[data->temp_osr_index];
+			ret = IIO_VAL_INT;
+			break;
+
+		case IIO_PRESSURE:
+			*val = hp206c_osr_rates[data->pres_osr_index];
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_TEMP:
+			osr_setting = &hp206c_osr_settings[data->temp_osr_index];
+			conv_cmd = HP206C_CMD_ADC_CVT |
+					osr_setting->osr_mask |
+					HP206C_CMD_ADC_CVT_CHNL_T;
+			ret = hp206c_conv_and_read(indio_dev,
+					conv_cmd,
+					HP206C_CMD_READ_T,
+					osr_setting->temp_conv_time_us);
+			if (ret >= 0) {
+				/* 20 significant bits are provided.
+				 * Extend sign over the rest.
+				 */
+				*val = sign_extend32(ret, 19);
+				ret = IIO_VAL_INT;
+			}
+			break;
+
+		case IIO_PRESSURE:
+			osr_setting = &hp206c_osr_settings[data->pres_osr_index];
+			conv_cmd = HP206C_CMD_ADC_CVT |
+					osr_setting->osr_mask |
+					HP206C_CMD_ADC_CVT_CHNL_PT;
+			ret = hp206c_conv_and_read(indio_dev,
+					conv_cmd,
+					HP206C_CMD_READ_P,
+					osr_setting->pres_conv_time_us);
+			if (ret >= 0) {
+				*val = ret;
+				ret = IIO_VAL_INT;
+			}
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_TEMP:
+			*val = 0;
+			*val2 = 10000;
+			ret = IIO_VAL_INT_PLUS_MICRO;
+			break;
+
+		case IIO_PRESSURE:
+			*val = 0;
+			*val2 = 1000;
+			ret = IIO_VAL_INT_PLUS_MICRO;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+
+static int hp206c_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	int ret = 0;
+	struct hp206c_data *data = iio_priv(indio_dev);
+
+	if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
+		return -EINVAL;
+	mutex_lock(&data->mutex);
+	switch (chan->type) {
+	case IIO_TEMP:
+		data->temp_osr_index = find_closest_descending(val,
+			hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));
+		break;
+	case IIO_PRESSURE:
+		data->pres_osr_index = find_closest_descending(val,
+			hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+
+static const struct iio_chan_spec hp206c_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+	},
+	{
+		.type = IIO_PRESSURE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+	}
+};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(hp206c_osr_rates_str);
+
+static struct attribute *hp206c_attributes[] = {
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group hp206c_attribute_group = {
+	.attrs = hp206c_attributes,
+};
+
+static const struct iio_info hp206c_info = {
+	.attrs = &hp206c_attribute_group,
+	.read_raw = hp206c_read_raw,
+	.write_raw = hp206c_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int hp206c_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct iio_dev *indio_dev;
+	struct hp206c_data *data;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE |
+				     I2C_FUNC_SMBUS_BYTE_DATA |
+				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+		dev_err(&client->dev, "Adapter does not support "
+				"all required i2c functionality\n");
+		return -ENODEV;
+	}
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	mutex_init(&data->mutex);
+
+	indio_dev->info = &hp206c_info;
+	indio_dev->name = id->name;
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = hp206c_channels;
+	indio_dev->num_channels = ARRAY_SIZE(hp206c_channels);
+
+	i2c_set_clientdata(client, indio_dev);
+
+	/* Do a soft reset on probe */
+	ret = hp206c_soft_reset(indio_dev);
+	if (ret) {
+		dev_err(&client->dev, "Failed to reset on startup: %d\n", ret);
+		return -ENODEV;
+	}
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id hp206c_id[] = {
+	{"hp206c"},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, hp206c_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id hp206c_acpi_match[] = {
+	{"HOP206C", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
+#endif
+
+static struct i2c_driver hp206c_driver = {
+	.probe = hp206c_probe,
+	.id_table = hp206c_id,
+	.driver = {
+		.name = "hp206c",
+		.acpi_match_table = ACPI_PTR(hp206c_acpi_match),
+	},
+};
+
+module_i2c_driver(hp206c_driver);
+
+MODULE_DESCRIPTION("HOPERF HP206C precision barometer and altimeter sensor");
+MODULE_AUTHOR("Leonard Crestez <leonard.crestez@intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
index 01b2e0b..6392d7b 100644
--- a/drivers/iio/pressure/mpl3115.c
+++ b/drivers/iio/pressure/mpl3115.c
@@ -171,7 +171,7 @@ static irqreturn_t mpl3115_trigger_handler(int irq, void *p)
 	mutex_unlock(&data->lock);
 
 	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
-		iio_get_time_ns());
+		iio_get_time_ns(indio_dev));
 
 done:
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h
index 8b08e4b..ccda63c 100644
--- a/drivers/iio/pressure/ms5611.h
+++ b/drivers/iio/pressure/ms5611.h
@@ -16,15 +16,11 @@
 #include <linux/iio/iio.h>
 #include <linux/mutex.h>
 
+struct regulator;
+
 #define MS5611_RESET			0x1e
 #define MS5611_READ_ADC			0x00
 #define MS5611_READ_PROM_WORD		0xA0
-#define MS5611_START_TEMP_CONV		0x58
-#define MS5611_START_PRESSURE_CONV	0x48
-
-#define MS5611_CONV_TIME_MIN		9040
-#define MS5611_CONV_TIME_MAX		10000
-
 #define MS5611_PROM_WORDS_NB		8
 
 enum {
@@ -39,16 +35,31 @@ struct ms5611_chip_info {
 					    s32 *temp, s32 *pressure);
 };
 
+/*
+ * OverSampling Rate descriptor.
+ * Warning: cmd MUST be kept aligned on a word boundary (see
+ * m5611_spi_read_adc_temp_and_pressure in ms5611_spi.c).
+ */
+struct ms5611_osr {
+	unsigned long conv_usec;
+	u8 cmd;
+	unsigned short rate;
+};
+
 struct ms5611_state {
 	void *client;
 	struct mutex lock;
 
+	const struct ms5611_osr *pressure_osr;
+	const struct ms5611_osr *temp_osr;
+
 	int (*reset)(struct device *dev);
 	int (*read_prom_word)(struct device *dev, int index, u16 *word);
 	int (*read_adc_temp_and_pressure)(struct device *dev,
 					  s32 *temp, s32 *pressure);
 
 	struct ms5611_chip_info *chip_info;
+	struct regulator *vdd;
 };
 
 int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c
index 992ad8d..feb41f8 100644
--- a/drivers/iio/pressure/ms5611_core.c
+++ b/drivers/iio/pressure/ms5611_core.c
@@ -18,11 +18,44 @@
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 
+#include <linux/iio/sysfs.h>
 #include <linux/iio/buffer.h>
 #include <linux/iio/triggered_buffer.h>
 #include <linux/iio/trigger_consumer.h>
 #include "ms5611.h"
 
+#define MS5611_INIT_OSR(_cmd, _conv_usec, _rate) \
+	{ .cmd = _cmd, .conv_usec = _conv_usec, .rate = _rate }
+
+static const struct ms5611_osr ms5611_avail_pressure_osr[] = {
+	MS5611_INIT_OSR(0x40, 600,  256),
+	MS5611_INIT_OSR(0x42, 1170, 512),
+	MS5611_INIT_OSR(0x44, 2280, 1024),
+	MS5611_INIT_OSR(0x46, 4540, 2048),
+	MS5611_INIT_OSR(0x48, 9040, 4096)
+};
+
+static const struct ms5611_osr ms5611_avail_temp_osr[] = {
+	MS5611_INIT_OSR(0x50, 600,  256),
+	MS5611_INIT_OSR(0x52, 1170, 512),
+	MS5611_INIT_OSR(0x54, 2280, 1024),
+	MS5611_INIT_OSR(0x56, 4540, 2048),
+	MS5611_INIT_OSR(0x58, 9040, 4096)
+};
+
+static const char ms5611_show_osr[] = "256 512 1024 2048 4096";
+
+static IIO_CONST_ATTR(oversampling_ratio_available, ms5611_show_osr);
+
+static struct attribute *ms5611_attributes[] = {
+	&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ms5611_attribute_group = {
+	.attrs = ms5611_attributes,
+};
+
 static bool ms5611_prom_is_valid(u16 *prom, size_t len)
 {
 	int i, j;
@@ -191,7 +224,8 @@ static irqreturn_t ms5611_trigger_handler(int irq, void *p)
 	if (ret < 0)
 		goto err;
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
+	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+					   iio_get_time_ns(indio_dev));
 
 err:
 	iio_trigger_notify_done(indio_dev->trig);
@@ -239,11 +273,70 @@ static int ms5611_read_raw(struct iio_dev *indio_dev,
 		default:
 			return -EINVAL;
 		}
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		if (chan->type != IIO_TEMP && chan->type != IIO_PRESSURE)
+			break;
+		mutex_lock(&st->lock);
+		if (chan->type == IIO_TEMP)
+			*val = (int)st->temp_osr->rate;
+		else
+			*val = (int)st->pressure_osr->rate;
+		mutex_unlock(&st->lock);
+		return IIO_VAL_INT;
 	}
 
 	return -EINVAL;
 }
 
+static const struct ms5611_osr *ms5611_find_osr(int rate,
+						const struct ms5611_osr *osr,
+						size_t count)
+{
+	unsigned int r;
+
+	for (r = 0; r < count; r++)
+		if ((unsigned short)rate == osr[r].rate)
+			break;
+	if (r >= count)
+		return NULL;
+	return &osr[r];
+}
+
+static int ms5611_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	struct ms5611_state *st = iio_priv(indio_dev);
+	const struct ms5611_osr *osr = NULL;
+
+	if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
+		return -EINVAL;
+
+	if (chan->type == IIO_TEMP)
+		osr = ms5611_find_osr(val, ms5611_avail_temp_osr,
+				      ARRAY_SIZE(ms5611_avail_temp_osr));
+	else if (chan->type == IIO_PRESSURE)
+		osr = ms5611_find_osr(val, ms5611_avail_pressure_osr,
+				      ARRAY_SIZE(ms5611_avail_pressure_osr));
+	if (!osr)
+		return -EINVAL;
+
+	mutex_lock(&st->lock);
+
+	if (iio_buffer_enabled(indio_dev)) {
+		mutex_unlock(&st->lock);
+		return -EBUSY;
+	}
+
+	if (chan->type == IIO_TEMP)
+		st->temp_osr = osr;
+	else
+		st->pressure_osr = osr;
+
+	mutex_unlock(&st->lock);
+	return 0;
+}
+
 static const unsigned long ms5611_scan_masks[] = {0x3, 0};
 
 static struct ms5611_chip_info chip_info_tbl[] = {
@@ -259,7 +352,8 @@ static const struct iio_chan_spec ms5611_channels[] = {
 	{
 		.type = IIO_PRESSURE,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
-			BIT(IIO_CHAN_INFO_SCALE),
+			BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
 		.scan_index = 0,
 		.scan_type = {
 			.sign = 's',
@@ -271,7 +365,8 @@ static const struct iio_chan_spec ms5611_channels[] = {
 	{
 		.type = IIO_TEMP,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
-			BIT(IIO_CHAN_INFO_SCALE),
+			BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
 		.scan_index = 1,
 		.scan_type = {
 			.sign = 's',
@@ -285,40 +380,68 @@ static const struct iio_chan_spec ms5611_channels[] = {
 
 static const struct iio_info ms5611_info = {
 	.read_raw = &ms5611_read_raw,
+	.write_raw = &ms5611_write_raw,
+	.attrs = &ms5611_attribute_group,
 	.driver_module = THIS_MODULE,
 };
 
 static int ms5611_init(struct iio_dev *indio_dev)
 {
 	int ret;
-	struct regulator *vdd = devm_regulator_get(indio_dev->dev.parent,
-	                                           "vdd");
+	struct ms5611_state *st = iio_priv(indio_dev);
 
 	/* Enable attached regulator if any. */
-	if (!IS_ERR(vdd)) {
-		ret = regulator_enable(vdd);
+	st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
+	if (!IS_ERR(st->vdd)) {
+		ret = regulator_enable(st->vdd);
 		if (ret) {
 			dev_err(indio_dev->dev.parent,
-			        "failed to enable Vdd supply: %d\n", ret);
+				"failed to enable Vdd supply: %d\n", ret);
 			return ret;
 		}
+	} else {
+		ret = PTR_ERR(st->vdd);
+		if (ret != -ENODEV)
+			return ret;
 	}
 
 	ret = ms5611_reset(indio_dev);
 	if (ret < 0)
-		return ret;
+		goto err_regulator_disable;
 
-	return ms5611_read_prom(indio_dev);
+	ret = ms5611_read_prom(indio_dev);
+	if (ret < 0)
+		goto err_regulator_disable;
+
+	return 0;
+
+err_regulator_disable:
+	if (!IS_ERR_OR_NULL(st->vdd))
+		regulator_disable(st->vdd);
+	return ret;
+}
+
+static void ms5611_fini(const struct iio_dev *indio_dev)
+{
+	const struct ms5611_state *st = iio_priv(indio_dev);
+
+	if (!IS_ERR_OR_NULL(st->vdd))
+		regulator_disable(st->vdd);
 }
 
 int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
-                 const char *name, int type)
+		 const char *name, int type)
 {
 	int ret;
 	struct ms5611_state *st = iio_priv(indio_dev);
 
 	mutex_init(&st->lock);
 	st->chip_info = &chip_info_tbl[type];
+	st->temp_osr =
+		&ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1];
+	st->pressure_osr =
+		&ms5611_avail_pressure_osr[ARRAY_SIZE(ms5611_avail_pressure_osr)
+					   - 1];
 	indio_dev->dev.parent = dev;
 	indio_dev->name = name;
 	indio_dev->info = &ms5611_info;
@@ -335,7 +458,7 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
 					 ms5611_trigger_handler, NULL);
 	if (ret < 0) {
 		dev_err(dev, "iio triggered buffer setup failed\n");
-		return ret;
+		goto err_fini;
 	}
 
 	ret = iio_device_register(indio_dev);
@@ -348,7 +471,8 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
 
 err_buffer_cleanup:
 	iio_triggered_buffer_cleanup(indio_dev);
-
+err_fini:
+	ms5611_fini(indio_dev);
 	return ret;
 }
 EXPORT_SYMBOL(ms5611_probe);
@@ -357,6 +481,7 @@ int ms5611_remove(struct iio_dev *indio_dev)
 {
 	iio_device_unregister(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
+	ms5611_fini(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c
index 7f6fc8e..55fb5fc 100644
--- a/drivers/iio/pressure/ms5611_i2c.c
+++ b/drivers/iio/pressure/ms5611_i2c.c
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 
 #include "ms5611.h"
 
@@ -62,23 +63,23 @@ static int ms5611_i2c_read_adc_temp_and_pressure(struct device *dev,
 {
 	int ret;
 	struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
+	const struct ms5611_osr *osr = st->temp_osr;
 
-	ret = i2c_smbus_write_byte(st->client, MS5611_START_TEMP_CONV);
+	ret = i2c_smbus_write_byte(st->client, osr->cmd);
 	if (ret < 0)
 		return ret;
 
-	usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
-
+	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
 	ret = ms5611_i2c_read_adc(st, temp);
 	if (ret < 0)
 		return ret;
 
-	ret = i2c_smbus_write_byte(st->client, MS5611_START_PRESSURE_CONV);
+	osr = st->pressure_osr;
+	ret = i2c_smbus_write_byte(st->client, osr->cmd);
 	if (ret < 0)
 		return ret;
 
-	usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
-
+	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
 	return ms5611_i2c_read_adc(st, pressure);
 }
 
@@ -113,6 +114,17 @@ static int ms5611_i2c_remove(struct i2c_client *client)
 	return ms5611_remove(i2c_get_clientdata(client));
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id ms5611_i2c_matches[] = {
+	{ .compatible = "meas,ms5611" },
+	{ .compatible = "ms5611" },
+	{ .compatible = "meas,ms5607" },
+	{ .compatible = "ms5607" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ms5611_i2c_matches);
+#endif
+
 static const struct i2c_device_id ms5611_id[] = {
 	{ "ms5611", MS5611 },
 	{ "ms5607", MS5607 },
@@ -123,6 +135,7 @@ MODULE_DEVICE_TABLE(i2c, ms5611_id);
 static struct i2c_driver ms5611_driver = {
 	.driver = {
 		.name = "ms5611",
+		.of_match_table = of_match_ptr(ms5611_i2c_matches)
 	},
 	.id_table = ms5611_id,
 	.probe = ms5611_i2c_probe,
diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c
index 5cc009e..932e050 100644
--- a/drivers/iio/pressure/ms5611_spi.c
+++ b/drivers/iio/pressure/ms5611_spi.c
@@ -12,6 +12,7 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/spi/spi.h>
+#include <linux/of_device.h>
 
 #include "ms5611.h"
 
@@ -55,28 +56,29 @@ static int ms5611_spi_read_adc(struct device *dev, s32 *val)
 static int ms5611_spi_read_adc_temp_and_pressure(struct device *dev,
 						 s32 *temp, s32 *pressure)
 {
-	u8 cmd;
 	int ret;
 	struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
+	const struct ms5611_osr *osr = st->temp_osr;
 
-	cmd = MS5611_START_TEMP_CONV;
-	ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0);
+	/*
+	 * Warning: &osr->cmd MUST be aligned on a word boundary since used as
+	 * 2nd argument (void*) of spi_write_then_read.
+	 */
+	ret = spi_write_then_read(st->client, &osr->cmd, 1, NULL, 0);
 	if (ret < 0)
 		return ret;
 
-	usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
-
+	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
 	ret = ms5611_spi_read_adc(dev, temp);
 	if (ret < 0)
 		return ret;
 
-	cmd = MS5611_START_PRESSURE_CONV;
-	ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0);
+	osr = st->pressure_osr;
+	ret = spi_write_then_read(st->client, &osr->cmd, 1, NULL, 0);
 	if (ret < 0)
 		return ret;
 
-	usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
-
+	usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
 	return ms5611_spi_read_adc(dev, pressure);
 }
 
@@ -106,7 +108,7 @@ static int ms5611_spi_probe(struct spi_device *spi)
 	st->client = spi;
 
 	return ms5611_probe(indio_dev, &spi->dev, spi_get_device_id(spi)->name,
-	                    spi_get_device_id(spi)->driver_data);
+			    spi_get_device_id(spi)->driver_data);
 }
 
 static int ms5611_spi_remove(struct spi_device *spi)
@@ -114,6 +116,17 @@ static int ms5611_spi_remove(struct spi_device *spi)
 	return ms5611_remove(spi_get_drvdata(spi));
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id ms5611_spi_matches[] = {
+	{ .compatible = "meas,ms5611" },
+	{ .compatible = "ms5611" },
+	{ .compatible = "meas,ms5607" },
+	{ .compatible = "ms5607" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ms5611_spi_matches);
+#endif
+
 static const struct spi_device_id ms5611_id[] = {
 	{ "ms5611", MS5611 },
 	{ "ms5607", MS5607 },
@@ -124,6 +137,7 @@ MODULE_DEVICE_TABLE(spi, ms5611_id);
 static struct spi_driver ms5611_driver = {
 	.driver = {
 		.name = "ms5611",
+		.of_match_table = of_match_ptr(ms5611_spi_matches)
 	},
 	.id_table = ms5611_id,
 	.probe = ms5611_spi_probe,
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
index e68052c..953ffbc 100644
--- a/drivers/iio/pressure/ms5637.c
+++ b/drivers/iio/pressure/ms5637.c
@@ -1,6 +1,6 @@
 /*
- * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607
- *            pressure & temperature sensor
+ * ms5637.c - Support for Measurement-Specialties MS5637, MS5805
+ *            MS5837 and MS8607 pressure & temperature sensor
  *
  * Copyright (c) 2015 Measurement-Specialties
  *
@@ -11,6 +11,10 @@
  * Datasheet:
  *  http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
  * Datasheet:
+ *  http://www.meas-spec.com/downloads/MS5805-02BA01.pdf
+ * Datasheet:
+ *  http://www.meas-spec.com/downloads/MS5837-30BA.pdf
+ * Datasheet:
  *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
  */
 
@@ -170,9 +174,12 @@ static int ms5637_probe(struct i2c_client *client,
 
 static const struct i2c_device_id ms5637_id[] = {
 	{"ms5637", 0},
-	{"ms8607-temppressure", 1},
+	{"ms5805", 0},
+	{"ms5837", 0},
+	{"ms8607-temppressure", 0},
 	{}
 };
+MODULE_DEVICE_TABLE(i2c, ms5637_id);
 
 static struct i2c_driver ms5637_driver = {
 	.probe = ms5637_probe,
diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h
index f5f4149..903a21e 100644
--- a/drivers/iio/pressure/st_pressure.h
+++ b/drivers/iio/pressure/st_pressure.h
@@ -17,6 +17,7 @@
 #define LPS001WP_PRESS_DEV_NAME		"lps001wp"
 #define LPS25H_PRESS_DEV_NAME		"lps25h"
 #define LPS331AP_PRESS_DEV_NAME		"lps331ap"
+#define LPS22HB_PRESS_DEV_NAME		"lps22hb"
 
 /**
  * struct st_sensors_platform_data - default press platform data
diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c
index 2ff53f2..99468d0 100644
--- a/drivers/iio/pressure/st_pressure_buffer.c
+++ b/drivers/iio/pressure/st_pressure_buffer.c
@@ -82,7 +82,7 @@ static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = {
 
 int st_press_allocate_ring(struct iio_dev *indio_dev)
 {
-	return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+	return iio_triggered_buffer_setup(indio_dev, NULL,
 		&st_sensors_trigger_handler, &st_press_buffer_setup_ops);
 }
 
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index d3ca320..55df9a7 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -28,6 +28,72 @@
 #include <linux/iio/common/st_sensors.h>
 #include "st_pressure.h"
 
+/*
+ * About determining pressure scaling factors
+ * ------------------------------------------
+ *
+ * Datasheets specify typical pressure sensitivity so that pressure is computed
+ * according to the following equation :
+ *     pressure[mBar] = raw / sensitivity
+ * where :
+ *     raw          the 24 bits long raw sampled pressure
+ *     sensitivity  a scaling factor specified by the datasheet in LSB/mBar
+ *
+ * IIO ABI expects pressure to be expressed as kPascal, hence pressure should be
+ * computed according to :
+ *     pressure[kPascal] = pressure[mBar] / 10
+ *                       = raw / (sensitivity * 10)                          (1)
+ *
+ * Finally, st_press_read_raw() returns pressure scaling factor as an
+ * IIO_VAL_INT_PLUS_NANO with a zero integral part and "gain" as decimal part.
+ * Therefore, from (1), "gain" becomes :
+ *     gain = 10^9 / (sensitivity * 10)
+ *          = 10^8 / sensitivity
+ *
+ * About determining temperature scaling factors and offsets
+ * ---------------------------------------------------------
+ *
+ * Datasheets specify typical temperature sensitivity and offset so that
+ * temperature is computed according to the following equation :
+ *     temp[Celsius] = offset[Celsius] + (raw / sensitivity)
+ * where :
+ *     raw          the 16 bits long raw sampled temperature
+ *     offset       a constant specified by the datasheet in degree Celsius
+ *                  (sometimes zero)
+ *     sensitivity  a scaling factor specified by the datasheet in LSB/Celsius
+ *
+ * IIO ABI expects temperature to be expressed as milli degree Celsius such as
+ * user space should compute temperature according to :
+ *     temp[mCelsius] = temp[Celsius] * 10^3
+ *                    = (offset[Celsius] + (raw / sensitivity)) * 10^3
+ *                    = ((offset[Celsius] * sensitivity) + raw) *
+ *                      (10^3 / sensitivity)                                 (2)
+ *
+ * IIO ABI expects user space to apply offset and scaling factors to raw samples
+ * according to :
+ *     temp[mCelsius] = (OFFSET + raw) * SCALE
+ * where :
+ *     OFFSET an arbitrary constant exposed by device
+ *     SCALE  an arbitrary scaling factor exposed by device
+ *
+ * Matching OFFSET and SCALE with members of (2) gives :
+ *     OFFSET = offset[Celsius] * sensitivity                                (3)
+ *     SCALE  = 10^3 / sensitivity                                           (4)
+ *
+ * st_press_read_raw() returns temperature scaling factor as an
+ * IIO_VAL_FRACTIONAL with a 10^3 numerator and "gain2" as denominator.
+ * Therefore, from (3), "gain2" becomes :
+ *     gain2 = sensitivity
+ *
+ * When declared within channel, i.e. for a non zero specified offset,
+ * st_press_read_raw() will return the latter as an IIO_VAL_FRACTIONAL such as :
+ *     numerator = OFFSET * 10^3
+ *     denominator = 10^3
+ * giving from (4):
+ *     numerator = offset[Celsius] * 10^3 * sensitivity
+ *               = offset[mCelsius] * gain2
+ */
+
 #define MCELSIUS_PER_CELSIUS			1000
 
 /* Default pressure sensitivity */
@@ -39,8 +105,6 @@
 #define ST_PRESS_LSB_PER_CELSIUS		480UL
 #define ST_PRESS_MILLI_CELSIUS_OFFSET		42500UL
 
-#define ST_PRESS_NUMBER_DATA_CHANNELS		1
-
 /* FULLSCALE */
 #define ST_PRESS_FS_AVL_1100MB			1100
 #define ST_PRESS_FS_AVL_1260MB			1260
@@ -48,7 +112,11 @@
 #define ST_PRESS_1_OUT_XL_ADDR			0x28
 #define ST_TEMP_1_OUT_L_ADDR			0x2b
 
-/* CUSTOM VALUES FOR LPS331AP SENSOR */
+/*
+ * CUSTOM VALUES FOR LPS331AP SENSOR
+ * See LPS331AP datasheet:
+ * http://www2.st.com/resource/en/datasheet/lps331ap.pdf
+ */
 #define ST_PRESS_LPS331AP_WAI_EXP		0xbb
 #define ST_PRESS_LPS331AP_ODR_ADDR		0x20
 #define ST_PRESS_LPS331AP_ODR_MASK		0x70
@@ -67,9 +135,13 @@
 #define ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK	0x20
 #define ST_PRESS_LPS331AP_IHL_IRQ_ADDR		0x22
 #define ST_PRESS_LPS331AP_IHL_IRQ_MASK		0x80
+#define ST_PRESS_LPS331AP_OD_IRQ_ADDR		0x22
+#define ST_PRESS_LPS331AP_OD_IRQ_MASK		0x40
 #define ST_PRESS_LPS331AP_MULTIREAD_BIT		true
 
-/* CUSTOM VALUES FOR LPS001WP SENSOR */
+/*
+ * CUSTOM VALUES FOR THE OBSOLETE LPS001WP SENSOR
+ */
 
 /* LPS001WP pressure resolution */
 #define ST_PRESS_LPS001WP_LSB_PER_MBAR		16UL
@@ -92,7 +164,11 @@
 #define ST_PRESS_LPS001WP_OUT_L_ADDR		0x28
 #define ST_TEMP_LPS001WP_OUT_L_ADDR		0x2a
 
-/* CUSTOM VALUES FOR LPS25H SENSOR */
+/*
+ * CUSTOM VALUES FOR LPS25H SENSOR
+ * See LPS25H datasheet:
+ * http://www2.st.com/resource/en/datasheet/lps25h.pdf
+ */
 #define ST_PRESS_LPS25H_WAI_EXP			0xbd
 #define ST_PRESS_LPS25H_ODR_ADDR		0x20
 #define ST_PRESS_LPS25H_ODR_MASK		0x70
@@ -109,31 +185,60 @@
 #define ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK	0x10
 #define ST_PRESS_LPS25H_IHL_IRQ_ADDR		0x22
 #define ST_PRESS_LPS25H_IHL_IRQ_MASK		0x80
+#define ST_PRESS_LPS25H_OD_IRQ_ADDR		0x22
+#define ST_PRESS_LPS25H_OD_IRQ_MASK		0x40
 #define ST_PRESS_LPS25H_MULTIREAD_BIT		true
 #define ST_PRESS_LPS25H_OUT_XL_ADDR		0x28
 #define ST_TEMP_LPS25H_OUT_L_ADDR		0x2b
 
+/*
+ * CUSTOM VALUES FOR LPS22HB SENSOR
+ * See LPS22HB datasheet:
+ * http://www2.st.com/resource/en/datasheet/lps22hb.pdf
+ */
+
+/* LPS22HB temperature sensitivity */
+#define ST_PRESS_LPS22HB_LSB_PER_CELSIUS	100UL
+
+#define ST_PRESS_LPS22HB_WAI_EXP		0xb1
+#define ST_PRESS_LPS22HB_ODR_ADDR		0x10
+#define ST_PRESS_LPS22HB_ODR_MASK		0x70
+#define ST_PRESS_LPS22HB_ODR_AVL_1HZ_VAL	0x01
+#define ST_PRESS_LPS22HB_ODR_AVL_10HZ_VAL	0x02
+#define ST_PRESS_LPS22HB_ODR_AVL_25HZ_VAL	0x03
+#define ST_PRESS_LPS22HB_ODR_AVL_50HZ_VAL	0x04
+#define ST_PRESS_LPS22HB_ODR_AVL_75HZ_VAL	0x05
+#define ST_PRESS_LPS22HB_PW_ADDR		0x10
+#define ST_PRESS_LPS22HB_PW_MASK		0x70
+#define ST_PRESS_LPS22HB_BDU_ADDR		0x10
+#define ST_PRESS_LPS22HB_BDU_MASK		0x02
+#define ST_PRESS_LPS22HB_DRDY_IRQ_ADDR		0x12
+#define ST_PRESS_LPS22HB_DRDY_IRQ_INT1_MASK	0x04
+#define ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK	0x08
+#define ST_PRESS_LPS22HB_IHL_IRQ_ADDR		0x12
+#define ST_PRESS_LPS22HB_IHL_IRQ_MASK		0x80
+#define ST_PRESS_LPS22HB_OD_IRQ_ADDR		0x12
+#define ST_PRESS_LPS22HB_OD_IRQ_MASK		0x40
+#define ST_PRESS_LPS22HB_MULTIREAD_BIT		true
+
 static const struct iio_chan_spec st_press_1_channels[] = {
 	{
 		.type = IIO_PRESSURE,
-		.channel2 = IIO_NO_MOD,
 		.address = ST_PRESS_1_OUT_XL_ADDR,
-		.scan_index = ST_SENSORS_SCAN_X,
+		.scan_index = 0,
 		.scan_type = {
 			.sign = 'u',
 			.realbits = 24,
-			.storagebits = 24,
+			.storagebits = 32,
 			.endianness = IIO_LE,
 		},
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
-		.modified = 0,
 	},
 	{
 		.type = IIO_TEMP,
-		.channel2 = IIO_NO_MOD,
 		.address = ST_TEMP_1_OUT_L_ADDR,
-		.scan_index = -1,
+		.scan_index = 1,
 		.scan_type = {
 			.sign = 'u',
 			.realbits = 16,
@@ -144,17 +249,15 @@ static const struct iio_chan_spec st_press_1_channels[] = {
 			BIT(IIO_CHAN_INFO_RAW) |
 			BIT(IIO_CHAN_INFO_SCALE) |
 			BIT(IIO_CHAN_INFO_OFFSET),
-		.modified = 0,
 	},
-	IIO_CHAN_SOFT_TIMESTAMP(1)
+	IIO_CHAN_SOFT_TIMESTAMP(2)
 };
 
 static const struct iio_chan_spec st_press_lps001wp_channels[] = {
 	{
 		.type = IIO_PRESSURE,
-		.channel2 = IIO_NO_MOD,
 		.address = ST_PRESS_LPS001WP_OUT_L_ADDR,
-		.scan_index = ST_SENSORS_SCAN_X,
+		.scan_index = 0,
 		.scan_type = {
 			.sign = 'u',
 			.realbits = 16,
@@ -164,13 +267,11 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) |
 			BIT(IIO_CHAN_INFO_SCALE),
-		.modified = 0,
 	},
 	{
 		.type = IIO_TEMP,
-		.channel2 = IIO_NO_MOD,
 		.address = ST_TEMP_LPS001WP_OUT_L_ADDR,
-		.scan_index = -1,
+		.scan_index = 1,
 		.scan_type = {
 			.sign = 'u',
 			.realbits = 16,
@@ -180,9 +281,42 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
 		.info_mask_separate =
 			BIT(IIO_CHAN_INFO_RAW) |
 			BIT(IIO_CHAN_INFO_SCALE),
-		.modified = 0,
 	},
-	IIO_CHAN_SOFT_TIMESTAMP(1)
+	IIO_CHAN_SOFT_TIMESTAMP(2)
+};
+
+static const struct iio_chan_spec st_press_lps22hb_channels[] = {
+	{
+		.type = IIO_PRESSURE,
+		.address = ST_PRESS_1_OUT_XL_ADDR,
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 24,
+			.storagebits = 32,
+			.endianness = IIO_LE,
+		},
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	},
+	{
+		.type = IIO_TEMP,
+		.address = ST_TEMP_1_OUT_L_ADDR,
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 16,
+			.storagebits = 16,
+			.endianness = IIO_LE,
+		},
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(2)
 };
 
 static const struct st_sensor_settings st_press_sensors_settings[] = {
@@ -235,6 +369,9 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
 			.mask_int2 = ST_PRESS_LPS331AP_DRDY_IRQ_INT2_MASK,
 			.addr_ihl = ST_PRESS_LPS331AP_IHL_IRQ_ADDR,
 			.mask_ihl = ST_PRESS_LPS331AP_IHL_IRQ_MASK,
+			.addr_od = ST_PRESS_LPS331AP_OD_IRQ_ADDR,
+			.mask_od = ST_PRESS_LPS331AP_OD_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_PRESS_LPS331AP_MULTIREAD_BIT,
 		.bootime = 2,
@@ -332,10 +469,66 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
 			.mask_int2 = ST_PRESS_LPS25H_DRDY_IRQ_INT2_MASK,
 			.addr_ihl = ST_PRESS_LPS25H_IHL_IRQ_ADDR,
 			.mask_ihl = ST_PRESS_LPS25H_IHL_IRQ_MASK,
+			.addr_od = ST_PRESS_LPS25H_OD_IRQ_ADDR,
+			.mask_od = ST_PRESS_LPS25H_OD_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
 		},
 		.multi_read_bit = ST_PRESS_LPS25H_MULTIREAD_BIT,
 		.bootime = 2,
 	},
+	{
+		.wai = ST_PRESS_LPS22HB_WAI_EXP,
+		.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+		.sensors_supported = {
+			[0] = LPS22HB_PRESS_DEV_NAME,
+		},
+		.ch = (struct iio_chan_spec *)st_press_lps22hb_channels,
+		.num_ch = ARRAY_SIZE(st_press_lps22hb_channels),
+		.odr = {
+			.addr = ST_PRESS_LPS22HB_ODR_ADDR,
+			.mask = ST_PRESS_LPS22HB_ODR_MASK,
+			.odr_avl = {
+				{ 1, ST_PRESS_LPS22HB_ODR_AVL_1HZ_VAL, },
+				{ 10, ST_PRESS_LPS22HB_ODR_AVL_10HZ_VAL, },
+				{ 25, ST_PRESS_LPS22HB_ODR_AVL_25HZ_VAL, },
+				{ 50, ST_PRESS_LPS22HB_ODR_AVL_50HZ_VAL, },
+				{ 75, ST_PRESS_LPS22HB_ODR_AVL_75HZ_VAL, },
+			},
+		},
+		.pw = {
+			.addr = ST_PRESS_LPS22HB_PW_ADDR,
+			.mask = ST_PRESS_LPS22HB_PW_MASK,
+			.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+		},
+		.fs = {
+			.fs_avl = {
+				/*
+				 * Pressure and temperature sensitivity values
+				 * as defined in table 3 of LPS22HB datasheet.
+				 */
+				[0] = {
+					.num = ST_PRESS_FS_AVL_1260MB,
+					.gain = ST_PRESS_KPASCAL_NANO_SCALE,
+					.gain2 = ST_PRESS_LPS22HB_LSB_PER_CELSIUS,
+				},
+			},
+		},
+		.bdu = {
+			.addr = ST_PRESS_LPS22HB_BDU_ADDR,
+			.mask = ST_PRESS_LPS22HB_BDU_MASK,
+		},
+		.drdy_irq = {
+			.addr = ST_PRESS_LPS22HB_DRDY_IRQ_ADDR,
+			.mask_int1 = ST_PRESS_LPS22HB_DRDY_IRQ_INT1_MASK,
+			.mask_int2 = ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK,
+			.addr_ihl = ST_PRESS_LPS22HB_IHL_IRQ_ADDR,
+			.mask_ihl = ST_PRESS_LPS22HB_IHL_IRQ_MASK,
+			.addr_od = ST_PRESS_LPS22HB_OD_IRQ_ADDR,
+			.mask_od = ST_PRESS_LPS22HB_OD_IRQ_MASK,
+			.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
+		},
+		.multi_read_bit = ST_PRESS_LPS22HB_MULTIREAD_BIT,
+	},
 };
 
 static int st_press_write_raw(struct iio_dev *indio_dev,
@@ -435,6 +628,7 @@ static const struct iio_info press_info = {
 static const struct iio_trigger_ops st_press_trigger_ops = {
 	.owner = THIS_MODULE,
 	.set_trigger_state = ST_PRESS_TRIGGER_SET_STATE,
+	.validate_device = st_sensors_validate_device,
 };
 #define ST_PRESS_TRIGGER_OPS (&st_press_trigger_ops)
 #else
@@ -451,23 +645,30 @@ int st_press_common_probe(struct iio_dev *indio_dev)
 	indio_dev->info = &press_info;
 	mutex_init(&press_data->tb.buf_lock);
 
-	st_sensors_power_enable(indio_dev);
+	err = st_sensors_power_enable(indio_dev);
+	if (err)
+		return err;
 
 	err = st_sensors_check_device_support(indio_dev,
 					ARRAY_SIZE(st_press_sensors_settings),
 					st_press_sensors_settings);
 	if (err < 0)
-		return err;
-
-	press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS;
+		goto st_press_power_off;
+
+	/*
+	 * Skip timestamping channel while declaring available channels to
+	 * common st_sensor layer. Look at st_sensors_get_buffer_element() to
+	 * see how timestamps are explicitly pushed as last samples block
+	 * element.
+	 */
+	press_data->num_data_channels = press_data->sensor_settings->num_ch - 1;
 	press_data->multiread_bit = press_data->sensor_settings->multi_read_bit;
 	indio_dev->channels = press_data->sensor_settings->ch;
 	indio_dev->num_channels = press_data->sensor_settings->num_ch;
 
-	if (press_data->sensor_settings->fs.addr != 0)
-		press_data->current_fullscale =
-			(struct st_sensor_fullscale_avl *)
-				&press_data->sensor_settings->fs.fs_avl[0];
+	press_data->current_fullscale =
+		(struct st_sensor_fullscale_avl *)
+			&press_data->sensor_settings->fs.fs_avl[0];
 
 	press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz;
 
@@ -479,11 +680,11 @@ int st_press_common_probe(struct iio_dev *indio_dev)
 
 	err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
 	if (err < 0)
-		return err;
+		goto st_press_power_off;
 
 	err = st_press_allocate_ring(indio_dev);
 	if (err < 0)
-		return err;
+		goto st_press_power_off;
 
 	if (irq > 0) {
 		err = st_sensors_allocate_trigger(indio_dev,
@@ -506,6 +707,8 @@ st_press_device_register_error:
 		st_sensors_deallocate_trigger(indio_dev);
 st_press_probe_trigger_error:
 	st_press_deallocate_ring(indio_dev);
+st_press_power_off:
+	st_sensors_power_disable(indio_dev);
 
 	return err;
 }
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 8fcf976..ed18701 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -32,6 +32,10 @@ static const struct of_device_id st_press_of_match[] = {
 		.compatible = "st,lps331ap-press",
 		.data = LPS331AP_PRESS_DEV_NAME,
 	},
+	{
+		.compatible = "st,lps22hb-press",
+		.data = LPS22HB_PRESS_DEV_NAME,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, st_press_of_match);
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index 40c0692..5505080 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -50,6 +50,7 @@ static const struct spi_device_id st_press_id_table[] = {
 	{ LPS001WP_PRESS_DEV_NAME },
 	{ LPS25H_PRESS_DEV_NAME },
 	{ LPS331AP_PRESS_DEV_NAME },
+	{ LPS22HB_PRESS_DEV_NAME },
 	{},
 };
 MODULE_DEVICE_TABLE(spi, st_press_id_table);
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index e2f926c..2e3a70e 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -231,10 +231,16 @@ static void as3935_event_work(struct work_struct *work)
 {
 	struct as3935_state *st;
 	int val;
+	int ret;
 
 	st = container_of(work, struct as3935_state, work.work);
 
-	as3935_read(st, AS3935_INT, &val);
+	ret = as3935_read(st, AS3935_INT, &val);
+	if (ret) {
+		dev_warn(&st->spi->dev, "read error\n");
+		return;
+	}
+
 	val &= AS3935_INT_MASK;
 
 	switch (val) {
@@ -242,7 +248,7 @@ static void as3935_event_work(struct work_struct *work)
 		iio_trigger_poll(st->trig);
 		break;
 	case AS3935_NOISE_INT:
-		dev_warn(&st->spi->dev, "noise level is too high");
+		dev_warn(&st->spi->dev, "noise level is too high\n");
 		break;
 	}
 }
@@ -346,7 +352,6 @@ static int as3935_probe(struct spi_device *spi)
 
 	st = iio_priv(indio_dev);
 	st->spi = spi;
-	st->tune_cap = 0;
 
 	spi_set_drvdata(spi, indio_dev);
 	mutex_init(&st->lock);
@@ -468,4 +473,3 @@ module_spi_driver(as3935_driver);
 MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
 MODULE_DESCRIPTION("AS3935 lightning sensor");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:as3935");
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index 4f50238..3141c3c 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -203,22 +203,19 @@ static int lidar_read_raw(struct iio_dev *indio_dev,
 	struct lidar_data *data = iio_priv(indio_dev);
 	int ret = -EINVAL;
 
-	mutex_lock(&indio_dev->mlock);
-
-	if (iio_buffer_enabled(indio_dev) && mask == IIO_CHAN_INFO_RAW) {
-		ret = -EBUSY;
-		goto error_busy;
-	}
-
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW: {
 		u16 reg;
 
+		if (iio_device_claim_direct_mode(indio_dev))
+			return -EBUSY;
+
 		ret = lidar_get_measurement(data, &reg);
 		if (!ret) {
 			*val = reg;
 			ret = IIO_VAL_INT;
 		}
+		iio_device_release_direct_mode(indio_dev);
 		break;
 	}
 	case IIO_CHAN_INFO_SCALE:
@@ -228,9 +225,6 @@ static int lidar_read_raw(struct iio_dev *indio_dev,
 		break;
 	}
 
-error_busy:
-	mutex_unlock(&indio_dev->mlock);
-
 	return ret;
 }
 
@@ -244,7 +238,7 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private)
 	ret = lidar_get_measurement(data, data->buffer);
 	if (!ret) {
 		iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
-						   iio_get_time_ns());
+						   iio_get_time_ns(indio_dev));
 	} else if (ret != -EINVAL) {
 		dev_err(&data->client->dev, "cannot read LIDAR measurement");
 	}
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index 66cd09a..1d74b3a 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -492,7 +492,7 @@ static void sx9500_push_events(struct iio_dev *indio_dev)
 		dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
 		ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
 					  IIO_EV_TYPE_THRESH, dir);
-		iio_push_event(indio_dev, ev, iio_get_time_ns());
+		iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));
 		data->prox_stat[chan] = new_prox;
 	}
 }
@@ -669,7 +669,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private)
 	}
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
-					   iio_get_time_ns());
+					   iio_get_time_ns(indio_dev));
 
 out:
 	mutex_unlock(&data->mutex);
diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
index ab6fe8f..c0a19a0 100644
--- a/drivers/iio/temperature/tsys02d.c
+++ b/drivers/iio/temperature/tsys02d.c
@@ -174,6 +174,7 @@ static const struct i2c_device_id tsys02d_id[] = {
 	{"tsys02d", 0},
 	{}
 };
+MODULE_DEVICE_TABLE(i2c, tsys02d_id);
 
 static struct i2c_driver tsys02d_driver = {
 	.probe = tsys02d_probe,
diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 519e677..809b2e7 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -24,6 +24,18 @@ config IIO_INTERRUPT_TRIGGER
 	  To compile this driver as a module, choose M here: the
 	  module will be called iio-trig-interrupt.
 
+config IIO_TIGHTLOOP_TRIGGER
+	tristate "A kthread based hammering loop trigger"
+	depends on IIO_SW_TRIGGER
+	help
+	  An experimental trigger, used to allow sensors to be sampled as fast
+	  as possible under the limitations of whatever else is going on.
+	  Uses a tight loop in a kthread.  Will only work with lower half only
+	  trigger consumers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iio-trig-loop.
+
 config IIO_SYSFS_TRIGGER
 	tristate "SYSFS trigger"
 	depends on SYSFS
diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
index fe06eb5..aab4dc2 100644
--- a/drivers/iio/trigger/Makefile
+++ b/drivers/iio/trigger/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
 obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
 obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
+obj-$(CONFIG_IIO_TIGHTLOOP_TRIGGER) += iio-trig-loop.o
diff --git b/drivers/iio/trigger/iio-trig-loop.c b/drivers/iio/trigger/iio-trig-loop.c
new file mode 100644
index 0000000..dc6be28
--- /dev/null
+++ b/drivers/iio/trigger/iio-trig-loop.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2016 Jonathan Cameron <jic23@kernel.org>
+ *
+ * Licensed under the GPL-2.
+ *
+ * Based on a mashup of the hrtimer trigger and continuous sampling proposal of
+ * Gregor Boirie <gregor.boirie@parrot.com>
+ *
+ * Note this is still rather experimental and may eat babies.
+ *
+ * Todo
+ * * Protect against connection of devices that 'need' the top half
+ *   handler.
+ * * Work out how to run top half handlers in this context if it is
+ *   safe to do so (timestamp grabbing for example)
+ *
+ * Tested against a max1363. Used about 33% cpu for the thread and 20%
+ * for generic_buffer piping to /dev/null. Watermark set at 64 on a 128
+ * element kfifo buffer.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irq_work.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/sw_trigger.h>
+
+struct iio_loop_info {
+	struct iio_sw_trigger swt;
+	struct task_struct *task;
+};
+
+static struct config_item_type iio_loop_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+static int iio_loop_thread(void *data)
+{
+	struct iio_trigger *trig = data;
+
+	set_freezable();
+
+	do {
+		iio_trigger_poll_chained(trig);
+	} while (likely(!kthread_freezable_should_stop(NULL)));
+
+	return 0;
+}
+
+static int iio_loop_trigger_set_state(struct iio_trigger *trig, bool state)
+{
+	struct iio_loop_info *loop_trig = iio_trigger_get_drvdata(trig);
+
+	if (state) {
+		loop_trig->task = kthread_run(iio_loop_thread,
+					      trig, trig->name);
+		if (unlikely(IS_ERR(loop_trig->task))) {
+			dev_err(&trig->dev,
+				"failed to create trigger loop thread\n");
+			return PTR_ERR(loop_trig->task);
+		}
+	} else {
+		kthread_stop(loop_trig->task);
+	}
+
+	return 0;
+}
+
+static const struct iio_trigger_ops iio_loop_trigger_ops = {
+	.set_trigger_state = iio_loop_trigger_set_state,
+	.owner = THIS_MODULE,
+};
+
+static struct iio_sw_trigger *iio_trig_loop_probe(const char *name)
+{
+	struct iio_loop_info *trig_info;
+	int ret;
+
+	trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
+	if (!trig_info)
+		return ERR_PTR(-ENOMEM);
+
+	trig_info->swt.trigger = iio_trigger_alloc("%s", name);
+	if (!trig_info->swt.trigger) {
+		ret = -ENOMEM;
+		goto err_free_trig_info;
+	}
+
+	iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info);
+	trig_info->swt.trigger->ops = &iio_loop_trigger_ops;
+
+	ret = iio_trigger_register(trig_info->swt.trigger);
+	if (ret)
+		goto err_free_trigger;
+
+	iio_swt_group_init_type_name(&trig_info->swt, name, &iio_loop_type);
+
+	return &trig_info->swt;
+
+err_free_trigger:
+	iio_trigger_free(trig_info->swt.trigger);
+err_free_trig_info:
+	kfree(trig_info);
+
+	return ERR_PTR(ret);
+}
+
+static int iio_trig_loop_remove(struct iio_sw_trigger *swt)
+{
+	struct iio_loop_info *trig_info;
+
+	trig_info = iio_trigger_get_drvdata(swt->trigger);
+
+	iio_trigger_unregister(swt->trigger);
+	iio_trigger_free(swt->trigger);
+	kfree(trig_info);
+
+	return 0;
+}
+
+static const struct iio_sw_trigger_ops iio_trig_loop_ops = {
+	.probe = iio_trig_loop_probe,
+	.remove = iio_trig_loop_remove,
+};
+
+static struct iio_sw_trigger_type iio_trig_loop = {
+	.name = "loop",
+	.owner = THIS_MODULE,
+	.ops = &iio_trig_loop_ops,
+};
+
+module_iio_sw_trigger_driver(iio_trig_loop);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
+MODULE_DESCRIPTION("Loop based trigger for the iio subsystem");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:iio-trig-loop");
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 8ecdc38..2fb1f43 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -632,7 +632,7 @@ config TOUCHSCREEN_EDT_FT5X06
 
 config TOUCHSCREEN_MIGOR
 	tristate "Renesas MIGO-R touchscreen"
-	depends on SH_MIGOR && I2C
+	depends on (SH_MIGOR || COMPILE_TEST) && I2C
 	help
 	  Say Y here to enable MIGO-R touchscreen support.
 
@@ -1046,6 +1046,44 @@ config TOUCHSCREEN_PCAP
 	  To compile this driver as a module, choose M here: the
 	  module will be called pcap_ts.
 
+config TOUCHSCREEN_RM_TS
+	tristate "Raydium I2C Touchscreen"
+	depends on I2C
+	depends on GPIOLIB || COMPILE_TEST
+	help
+	  Say Y here if you have Raydium series I2C touchscreen,
+	  such as RM32380, connected to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called raydium_i2c_ts.
+
+config TOUCHSCREEN_SILEAD
+	tristate "Silead I2C touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have the Silead touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called silead.
+
+config TOUCHSCREEN_SIS_I2C
+	tristate "SiS 9200 family I2C touchscreen"
+	depends on I2C
+	select CRC_ITU_T
+	depends on GPIOLIB || COMPILE_TEST
+	help
+	  This enables support for SiS 9200 family over I2C based touchscreens.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sis_i2c.
+
 config TOUCHSCREEN_ST1232
 	tristate "Sitronix ST1232 touchscreen controllers"
 	depends on I2C
@@ -1094,6 +1132,19 @@ config TOUCHSCREEN_SUR40
 	  To compile this driver as a module, choose M here: the
 	  module will be called sur40.
 
+config TOUCHSCREEN_SURFACE3_SPI
+	tristate "Ntrig/Microsoft Surface 3 SPI touchscreen"
+	depends on SPI
+	depends on GPIOLIB || COMPILE_TEST
+	help
+	  Say Y here if you have the Ntrig/Microsoft SPI touchscreen
+	  controller chip as found on the Surface 3 in your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called surface3_spi.
+
 config TOUCHSCREEN_SX8654
 	tristate "Semtech SX8654 touchscreen"
 	depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index f42975e..b4373d6 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -62,11 +62,15 @@ obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE)	+= usbtouchscreen.o
 obj-$(CONFIG_TOUCHSCREEN_PCAP)		+= pcap_ts.o
 obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)	+= penmount.o
 obj-$(CONFIG_TOUCHSCREEN_PIXCIR)	+= pixcir_i2c_ts.o
+obj-$(CONFIG_TOUCHSCREEN_RM_TS)		+= raydium_i2c_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
+obj-$(CONFIG_TOUCHSCREEN_SILEAD)	+= silead.o
+obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)	+= sis_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_ST1232)	+= st1232.o
 obj-$(CONFIG_TOUCHSCREEN_STMPE)		+= stmpe-ts.o
 obj-$(CONFIG_TOUCHSCREEN_SUN4I)		+= sun4i-ts.o
 obj-$(CONFIG_TOUCHSCREEN_SUR40)		+= sur40.o
+obj-$(CONFIG_TOUCHSCREEN_SURFACE3_SPI)	+= surface3_spi.o
 obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC)	+= ti_am335x_tsc.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 69d299d..e16a446 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -379,7 +379,7 @@ static const struct attribute_group ad7879_attr_group = {
 static int ad7879_gpio_direction_input(struct gpio_chip *chip,
 					unsigned gpio)
 {
-	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	struct ad7879 *ts = gpiochip_get_data(chip);
 	int err;
 
 	mutex_lock(&ts->mutex);
@@ -393,7 +393,7 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip,
 static int ad7879_gpio_direction_output(struct gpio_chip *chip,
 					unsigned gpio, int level)
 {
-	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	struct ad7879 *ts = gpiochip_get_data(chip);
 	int err;
 
 	mutex_lock(&ts->mutex);
@@ -412,7 +412,7 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip,
 
 static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
 {
-	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	struct ad7879 *ts = gpiochip_get_data(chip);
 	u16 val;
 
 	mutex_lock(&ts->mutex);
@@ -425,7 +425,7 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
 static void ad7879_gpio_set_value(struct gpio_chip *chip,
 				  unsigned gpio, int value)
 {
-	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	struct ad7879 *ts = gpiochip_get_data(chip);
 
 	mutex_lock(&ts->mutex);
 	if (value)
@@ -456,7 +456,7 @@ static int ad7879_gpio_add(struct ad7879 *ts,
 		ts->gc.owner = THIS_MODULE;
 		ts->gc.parent = ts->dev;
 
-		ret = gpiochip_add(&ts->gc);
+		ret = gpiochip_add_data(&ts->gc, ts);
 		if (ret)
 			dev_err(ts->dev, "failed to register gpio %d\n",
 				ts->gc.base);
@@ -595,7 +595,7 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
 	} else {
 		input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
 		input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
-		touchscreen_parse_properties(input_dev, false);
+		touchscreen_parse_properties(input_dev, false, NULL);
 		if (!input_abs_get_max(input_dev, ABS_PRESSURE)) {
 			dev_err(dev, "Touchscreen pressure is not specified\n");
 			return ERR_PTR(-EINVAL);
diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
index ae460a5..4d11b27 100644
--- a/drivers/input/touchscreen/bcm_iproc_tsc.c
+++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
@@ -23,6 +23,8 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/serio.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #define IPROC_TS_NAME "iproc-ts"
 
@@ -88,7 +90,11 @@
 #define TS_WIRE_MODE_BIT        BIT(1)
 
 #define dbg_reg(dev, priv, reg) \
-	dev_dbg(dev, "%20s= 0x%08x\n", #reg, readl((priv)->regs + reg))
+do { \
+	u32 val; \
+	regmap_read(priv->regmap, reg, &val); \
+	dev_dbg(dev, "%20s= 0x%08x\n", #reg, val); \
+} while (0)
 
 struct tsc_param {
 	/* Each step is 1024 us.  Valid 1-256 */
@@ -141,7 +147,7 @@ struct iproc_ts_priv {
 	struct platform_device *pdev;
 	struct input_dev *idev;
 
-	void __iomem *regs;
+	struct regmap *regmap;
 	struct clk *tsc_clk;
 
 	int  pen_status;
@@ -196,22 +202,22 @@ static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
 	int i;
 	bool needs_sync = false;
 
-	intr_status = readl(priv->regs + INTERRUPT_STATUS);
+	regmap_read(priv->regmap, INTERRUPT_STATUS, &intr_status);
 	intr_status &= TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK;
 	if (intr_status == 0)
 		return IRQ_NONE;
 
 	/* Clear all interrupt status bits, write-1-clear */
-	writel(intr_status, priv->regs + INTERRUPT_STATUS);
-
+	regmap_write(priv->regmap, INTERRUPT_STATUS, intr_status);
 	/* Pen up/down */
 	if (intr_status & TS_PEN_INTR_MASK) {
-		if (readl(priv->regs + CONTROLLER_STATUS) & TS_PEN_DOWN)
+		regmap_read(priv->regmap, CONTROLLER_STATUS, &priv->pen_status);
+		if (priv->pen_status & TS_PEN_DOWN)
 			priv->pen_status = PEN_DOWN_STATUS;
 		else
 			priv->pen_status = PEN_UP_STATUS;
 
-		input_report_key(priv->idev, BTN_TOUCH, priv->pen_status);
+		input_report_key(priv->idev, BTN_TOUCH,	priv->pen_status);
 		needs_sync = true;
 
 		dev_dbg(&priv->pdev->dev,
@@ -221,7 +227,7 @@ static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
 	/* coordinates in FIFO exceed the theshold */
 	if (intr_status & TS_FIFO_INTR_MASK) {
 		for (i = 0; i < priv->cfg_params.fifo_threshold; i++) {
-			raw_coordinate = readl(priv->regs + FIFO_DATA);
+			regmap_read(priv->regmap, FIFO_DATA, &raw_coordinate);
 			if (raw_coordinate == INVALID_COORD)
 				continue;
 
@@ -239,7 +245,7 @@ static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
 			x = (x >> 4) & 0x0FFF;
 			y = (y >> 4) & 0x0FFF;
 
-			/* adjust x y according to lcd tsc mount angle */
+			/* Adjust x y according to LCD tsc mount angle. */
 			if (priv->cfg_params.invert_x)
 				x = priv->cfg_params.max_x - x;
 
@@ -262,9 +268,10 @@ static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
 
 static int iproc_ts_start(struct input_dev *idev)
 {
-	struct iproc_ts_priv *priv = input_get_drvdata(idev);
 	u32 val;
+	u32 mask;
 	int error;
+	struct iproc_ts_priv *priv = input_get_drvdata(idev);
 
 	/* Enable clock */
 	error = clk_prepare_enable(priv->tsc_clk);
@@ -279,9 +286,10 @@ static int iproc_ts_start(struct input_dev *idev)
 	 *  FIFO reaches the int_th value, and pen event(up/down)
 	 */
 	val = TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK;
-	writel(val, priv->regs + INTERRUPT_MASK);
+	regmap_update_bits(priv->regmap, INTERRUPT_MASK, val, val);
 
-	writel(priv->cfg_params.fifo_threshold, priv->regs + INTERRUPT_THRES);
+	val = priv->cfg_params.fifo_threshold;
+	regmap_write(priv->regmap, INTERRUPT_THRES, val);
 
 	/* Initialize control reg1 */
 	val = 0;
@@ -289,26 +297,23 @@ static int iproc_ts_start(struct input_dev *idev)
 	val |= priv->cfg_params.debounce_timeout << DEBOUNCE_TIMEOUT_SHIFT;
 	val |= priv->cfg_params.settling_timeout << SETTLING_TIMEOUT_SHIFT;
 	val |= priv->cfg_params.touch_timeout << TOUCH_TIMEOUT_SHIFT;
-	writel(val, priv->regs + REGCTL1);
+	regmap_write(priv->regmap, REGCTL1, val);
 
 	/* Try to clear all interrupt status */
-	val = readl(priv->regs + INTERRUPT_STATUS);
-	val |= TS_FIFO_INTR_MASK | TS_PEN_INTR_MASK;
-	writel(val, priv->regs + INTERRUPT_STATUS);
+	val = TS_FIFO_INTR_MASK | TS_PEN_INTR_MASK;
+	regmap_update_bits(priv->regmap, INTERRUPT_STATUS, val, val);
 
 	/* Initialize control reg2 */
-	val = readl(priv->regs + REGCTL2);
-	val |= TS_CONTROLLER_EN_BIT | TS_WIRE_MODE_BIT;
-
-	val &= ~TS_CONTROLLER_AVGDATA_MASK;
+	val = TS_CONTROLLER_EN_BIT | TS_WIRE_MODE_BIT;
 	val |= priv->cfg_params.average_data << TS_CONTROLLER_AVGDATA_SHIFT;
 
-	val &= ~(TS_CONTROLLER_PWR_LDO |	/* PWR up LDO */
+	mask = (TS_CONTROLLER_AVGDATA_MASK);
+	mask |= (TS_CONTROLLER_PWR_LDO |	/* PWR up LDO */
 		   TS_CONTROLLER_PWR_ADC |	/* PWR up ADC */
 		   TS_CONTROLLER_PWR_BGP |	/* PWR up BGP */
 		   TS_CONTROLLER_PWR_TS);	/* PWR up TS */
-
-	writel(val, priv->regs + REGCTL2);
+	mask |= val;
+	regmap_update_bits(priv->regmap, REGCTL2, mask, val);
 
 	ts_reg_dump(priv);
 
@@ -320,12 +325,17 @@ static void iproc_ts_stop(struct input_dev *dev)
 	u32 val;
 	struct iproc_ts_priv *priv = input_get_drvdata(dev);
 
-	writel(0, priv->regs + INTERRUPT_MASK); /* Disable all interrupts */
+	/*
+	 * Disable FIFO int_th and pen event(up/down)Interrupts only
+	 * as the interrupt mask register is shared between ADC, TS and
+	 * flextimer.
+	 */
+	val = TS_PEN_INTR_MASK | TS_FIFO_INTR_MASK;
+	regmap_update_bits(priv->regmap, INTERRUPT_MASK, val, 0);
 
 	/* Only power down touch screen controller */
-	val = readl(priv->regs + REGCTL2);
-	val |= TS_CONTROLLER_PWR_TS;
-	writel(val, priv->regs + REGCTL2);
+	val = TS_CONTROLLER_PWR_TS;
+	regmap_update_bits(priv->regmap, REGCTL2, val, val);
 
 	clk_disable(priv->tsc_clk);
 }
@@ -414,7 +424,6 @@ static int iproc_ts_probe(struct platform_device *pdev)
 {
 	struct iproc_ts_priv *priv;
 	struct input_dev *idev;
-	struct resource *res;
 	int irq;
 	int error;
 
@@ -422,12 +431,12 @@ static int iproc_ts_probe(struct platform_device *pdev)
 	if (!priv)
 		return -ENOMEM;
 
-	/* touchscreen controller memory mapped regs */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	priv->regs = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(priv->regs)) {
-		error = PTR_ERR(priv->regs);
-		dev_err(&pdev->dev, "unable to map I/O memory: %d\n", error);
+	/* touchscreen controller memory mapped regs via syscon*/
+	priv->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+							"ts_syscon");
+	if (IS_ERR(priv->regmap)) {
+		error = PTR_ERR(priv->regmap);
+		dev_err(&pdev->dev, "unable to map I/O memory:%d\n", error);
 		return error;
 	}
 
diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c
index 22a6fea..0bf1406 100644
--- a/drivers/input/touchscreen/chipone_icn8318.c
+++ b/drivers/input/touchscreen/chipone_icn8318.c
@@ -17,6 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
 #include <linux/module.h>
 #include <linux/of.h>
 
@@ -52,11 +53,7 @@ struct icn8318_data {
 	struct i2c_client *client;
 	struct input_dev *input;
 	struct gpio_desc *wake_gpio;
-	u32 max_x;
-	u32 max_y;
-	bool invert_x;
-	bool invert_y;
-	bool swap_x_y;
+	struct touchscreen_properties prop;
 };
 
 static int icn8318_read_touch_data(struct i2c_client *client,
@@ -91,7 +88,7 @@ static irqreturn_t icn8318_irq(int irq, void *dev_id)
 	struct icn8318_data *data = dev_id;
 	struct device *dev = &data->client->dev;
 	struct icn8318_touch_data touch_data;
-	int i, ret, x, y;
+	int i, ret;
 
 	ret = icn8318_read_touch_data(data->client, &touch_data);
 	if (ret < 0) {
@@ -124,22 +121,9 @@ static irqreturn_t icn8318_irq(int irq, void *dev_id)
 		if (!act)
 			continue;
 
-		x = be16_to_cpu(touch->x);
-		y = be16_to_cpu(touch->y);
-
-		if (data->invert_x)
-			x = data->max_x - x;
-
-		if (data->invert_y)
-			y = data->max_y - y;
-
-		if (!data->swap_x_y) {
-			input_event(data->input, EV_ABS, ABS_MT_POSITION_X, x);
-			input_event(data->input, EV_ABS, ABS_MT_POSITION_Y, y);
-		} else {
-			input_event(data->input, EV_ABS, ABS_MT_POSITION_X, y);
-			input_event(data->input, EV_ABS, ABS_MT_POSITION_Y, x);
-		}
+		touchscreen_report_pos(data->input, &data->prop,
+				       be16_to_cpu(touch->x),
+				       be16_to_cpu(touch->y), true);
 	}
 
 	input_mt_sync_frame(data->input);
@@ -200,10 +184,8 @@ static int icn8318_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
 	struct device *dev = &client->dev;
-	struct device_node *np = dev->of_node;
 	struct icn8318_data *data;
 	struct input_dev *input;
-	u32 fuzz_x = 0, fuzz_y = 0;
 	int error;
 
 	if (!client->irq) {
@@ -223,19 +205,6 @@ static int icn8318_probe(struct i2c_client *client,
 		return error;
 	}
 
-	if (of_property_read_u32(np, "touchscreen-size-x", &data->max_x) ||
-	    of_property_read_u32(np, "touchscreen-size-y", &data->max_y)) {
-		dev_err(dev, "Error touchscreen-size-x and/or -y missing\n");
-		return -EINVAL;
-	}
-
-	/* Optional */
-	of_property_read_u32(np, "touchscreen-fuzz-x", &fuzz_x);
-	of_property_read_u32(np, "touchscreen-fuzz-y", &fuzz_y);
-	data->invert_x = of_property_read_bool(np, "touchscreen-inverted-x");
-	data->invert_y = of_property_read_bool(np, "touchscreen-inverted-y");
-	data->swap_x_y = of_property_read_bool(np, "touchscreen-swapped-x-y");
-
 	input = devm_input_allocate_device(dev);
 	if (!input)
 		return -ENOMEM;
@@ -246,16 +215,14 @@ static int icn8318_probe(struct i2c_client *client,
 	input->close = icn8318_stop;
 	input->dev.parent = dev;
 
-	if (!data->swap_x_y) {
-		input_set_abs_params(input, ABS_MT_POSITION_X, 0,
-				     data->max_x, fuzz_x, 0);
-		input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
-				     data->max_y, fuzz_y, 0);
-	} else {
-		input_set_abs_params(input, ABS_MT_POSITION_X, 0,
-				     data->max_y, fuzz_y, 0);
-		input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
-				     data->max_x, fuzz_x, 0);
+	input_set_capability(input, EV_ABS, ABS_MT_POSITION_X);
+	input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y);
+
+	touchscreen_parse_properties(input, true, &data->prop);
+	if (!input_abs_get_max(input, ABS_MT_POSITION_X) ||
+	    !input_abs_get_max(input, ABS_MT_POSITION_Y)) {
+		dev_err(dev, "Error touchscreen-size-x and/or -y missing\n");
+		return -EINVAL;
 	}
 
 	error = input_mt_init_slots(input, ICN8318_MAX_TOUCHES,
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
index 5ed3105..44deca8 100644
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ b/drivers/input/touchscreen/cyttsp4_core.c
@@ -1499,7 +1499,7 @@ static int cyttsp4_core_sleep_(struct cyttsp4 *cd)
 
 	if (IS_BOOTLOADER(mode[0], mode[1])) {
 		mutex_unlock(&cd->system_lock);
-		dev_err(cd->dev, "%s: Device in BOOTLADER mode.\n", __func__);
+		dev_err(cd->dev, "%s: Device in BOOTLOADER mode.\n", __func__);
 		rc = -EINVAL;
 		goto error;
 	}
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index 91cda8f..79381cc 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -657,7 +657,7 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
 
 	input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
 	input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
-	touchscreen_parse_properties(input_dev, true);
+	touchscreen_parse_properties(input_dev, true, NULL);
 
 	error = input_mt_init_slots(input_dev, CY_MAX_ID, 0);
 	if (error) {
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 23fbe38..703e295 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -86,6 +86,7 @@ struct edt_reg_addr {
 struct edt_ft5x06_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
+	struct touchscreen_properties prop;
 	u16 num_x;
 	u16 num_y;
 
@@ -246,8 +247,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
 		if (!down)
 			continue;
 
-		input_report_abs(tsdata->input, ABS_MT_POSITION_X, x);
-		input_report_abs(tsdata->input, ABS_MT_POSITION_Y, y);
+		touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y,
+				       true);
 	}
 
 	input_mt_report_pointer_emulation(tsdata->input, true);
@@ -972,7 +973,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 	input_set_abs_params(input, ABS_MT_POSITION_Y,
 			     0, tsdata->num_y * 64 - 1, 0, 0);
 
-	touchscreen_parse_properties(input, true);
+	touchscreen_parse_properties(input, true, &tsdata->prop);
 
 	error = input_mt_init_slots(input, tsdata->max_support_points,
 				INPUT_MT_DIRECT);
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
index ddf694b..fe4848b 100644
--- a/drivers/input/touchscreen/ili210x.c
+++ b/drivers/input/touchscreen/ili210x.c
@@ -169,7 +169,7 @@ static ssize_t ili210x_calibrate(struct device *dev,
 
 	return count;
 }
-static DEVICE_ATTR(calibrate, 0644, NULL, ili210x_calibrate);
+static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
 
 static struct attribute *ili210x_attributes[] = {
 	&dev_attr_calibrate.attr,
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c
index c038db9..02fb119 100644
--- a/drivers/input/touchscreen/migor_ts.c
+++ b/drivers/input/touchscreen/migor_ts.c
@@ -202,7 +202,7 @@ static int migor_ts_remove(struct i2c_client *client)
 	return 0;
 }
 
-static int migor_ts_suspend(struct device *dev)
+static int __maybe_unused migor_ts_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct migor_ts_priv *priv = i2c_get_clientdata(client);
@@ -213,7 +213,7 @@ static int migor_ts_suspend(struct device *dev)
 	return 0;
 }
 
-static int migor_ts_resume(struct device *dev)
+static int __maybe_unused migor_ts_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct migor_ts_priv *priv = i2c_get_clientdata(client);
@@ -230,7 +230,7 @@ static const struct i2c_device_id migor_ts_id[] = {
 	{ "migor_ts", 0 },
 	{ }
 };
-MODULE_DEVICE_TABLE(i2c, migor_ts);
+MODULE_DEVICE_TABLE(i2c, migor_ts_id);
 
 static struct i2c_driver migor_ts_driver = {
 	.driver = {
diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c
index bb6f2fe..8d7f9c8 100644
--- a/drivers/input/touchscreen/of_touchscreen.c
+++ b/drivers/input/touchscreen/of_touchscreen.c
@@ -55,12 +55,16 @@ static void touchscreen_set_params(struct input_dev *dev,
  * @input: input device that should be parsed
  * @multitouch: specifies whether parsed properties should be applied to
  *	single-touch or multi-touch axes
+ * @prop: pointer to a struct touchscreen_properties into which to store
+ *	axis swap and invert info for use with touchscreen_report_x_y();
+ *	or %NULL
  *
  * This function parses common DT properties for touchscreens and setups the
  * input device accordingly. The function keeps previously set up default
  * values if no value is specified via DT.
  */
-void touchscreen_parse_properties(struct input_dev *input, bool multitouch)
+void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
+				  struct touchscreen_properties *prop)
 {
 	struct device *dev = input->dev.parent;
 	unsigned int axis;
@@ -104,5 +108,80 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch)
 						&fuzz);
 	if (data_present)
 		touchscreen_set_params(input, axis, maximum, fuzz);
+
+	if (!prop)
+		return;
+
+	axis = multitouch ? ABS_MT_POSITION_X : ABS_X;
+
+	prop->max_x = input_abs_get_max(input, axis);
+	prop->max_y = input_abs_get_max(input, axis + 1);
+	prop->invert_x =
+		device_property_read_bool(dev, "touchscreen-inverted-x");
+	prop->invert_y =
+		device_property_read_bool(dev, "touchscreen-inverted-y");
+	prop->swap_x_y =
+		device_property_read_bool(dev, "touchscreen-swapped-x-y");
+
+	if (prop->swap_x_y)
+		swap(input->absinfo[axis], input->absinfo[axis + 1]);
 }
 EXPORT_SYMBOL(touchscreen_parse_properties);
+
+static void
+touchscreen_apply_prop_to_x_y(const struct touchscreen_properties *prop,
+			      unsigned int *x, unsigned int *y)
+{
+	if (prop->invert_x)
+		*x = prop->max_x - *x;
+
+	if (prop->invert_y)
+		*y = prop->max_y - *y;
+
+	if (prop->swap_x_y)
+		swap(*x, *y);
+}
+
+/**
+ * touchscreen_set_mt_pos - Set input_mt_pos coordinates
+ * @pos: input_mt_pos to set coordinates of
+ * @prop: pointer to a struct touchscreen_properties
+ * @x: X coordinate to store in pos
+ * @y: Y coordinate to store in pos
+ *
+ * Adjust the passed in x and y values applying any axis inversion and
+ * swapping requested in the passed in touchscreen_properties and store
+ * the result in a struct input_mt_pos.
+ */
+void touchscreen_set_mt_pos(struct input_mt_pos *pos,
+			    const struct touchscreen_properties *prop,
+			    unsigned int x, unsigned int y)
+{
+	touchscreen_apply_prop_to_x_y(prop, &x, &y);
+	pos->x = x;
+	pos->y = y;
+}
+EXPORT_SYMBOL(touchscreen_set_mt_pos);
+
+/**
+ * touchscreen_report_pos - Report touchscreen coordinates
+ * @input: input_device to report coordinates for
+ * @prop: pointer to a struct touchscreen_properties
+ * @x: X coordinate to report
+ * @y: Y coordinate to report
+ * @multitouch: Report coordinates on single-touch or multi-touch axes
+ *
+ * Adjust the passed in x and y values applying any axis inversion and
+ * swapping requested in the passed in touchscreen_properties and then
+ * report the resulting coordinates on the input_dev's x and y axis.
+ */
+void touchscreen_report_pos(struct input_dev *input,
+			    const struct touchscreen_properties *prop,
+			    unsigned int x, unsigned int y,
+			    bool multitouch)
+{
+	touchscreen_apply_prop_to_x_y(prop, &x, &y);
+	input_report_abs(input, multitouch ? ABS_MT_POSITION_X : ABS_X, x);
+	input_report_abs(input, multitouch ? ABS_MT_POSITION_Y : ABS_Y, y);
+}
+EXPORT_SYMBOL(touchscreen_report_pos);
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 09523a3..d159e14 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -27,9 +27,9 @@
 #include <linux/input/touchscreen.h>
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
-/*#include <linux/of.h>*/
 #include <linux/of_device.h>
 #include <linux/platform_data/pixcir_i2c_ts.h>
+#include <asm/unaligned.h>
 
 #define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 
@@ -41,19 +41,15 @@ struct pixcir_i2c_ts_data {
 	struct gpio_desc *gpio_enable;
 	struct gpio_desc *gpio_wake;
 	const struct pixcir_i2c_chip_data *chip;
+	struct touchscreen_properties prop;
 	int max_fingers;	/* Max fingers supported in this instance */
 	bool running;
 };
 
-struct pixcir_touch {
-	int x;
-	int y;
-	int id;
-};
-
 struct pixcir_report_data {
 	int num_touches;
-	struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
+	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
+	int ids[PIXCIR_MAX_SLOTS];
 };
 
 static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
@@ -98,11 +94,11 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 	bufptr = &rdbuf[2];
 
 	for (i = 0; i < touch; i++) {
-		report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
-		report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
-
+		touchscreen_set_mt_pos(&report->pos[i], &tsdata->prop,
+				       get_unaligned_le16(bufptr),
+				       get_unaligned_le16(bufptr + 2));
 		if (chip->has_hw_ids) {
-			report->touches[i].id = bufptr[4];
+			report->ids[i] = bufptr[4];
 			bufptr = bufptr + 5;
 		} else {
 			bufptr = bufptr + 4;
@@ -113,9 +109,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 			     struct pixcir_report_data *report)
 {
-	struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
 	int slots[PIXCIR_MAX_SLOTS];
-	struct pixcir_touch *touch;
 	int n, i, slot;
 	struct device *dev = &ts->client->dev;
 	const struct pixcir_i2c_chip_data *chip = ts->chip;
@@ -124,24 +118,16 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 	if (n > PIXCIR_MAX_SLOTS)
 		n = PIXCIR_MAX_SLOTS;
 
-	if (!ts->chip->has_hw_ids) {
-		for (i = 0; i < n; i++) {
-			touch = &report->touches[i];
-			pos[i].x = touch->x;
-			pos[i].y = touch->y;
-		}
-
-		input_mt_assign_slots(ts->input, slots, pos, n, 0);
-	}
+	if (!ts->chip->has_hw_ids)
+		input_mt_assign_slots(ts->input, slots, report->pos, n, 0);
 
 	for (i = 0; i < n; i++) {
-		touch = &report->touches[i];
-
 		if (chip->has_hw_ids) {
-			slot = input_mt_get_slot_by_key(ts->input, touch->id);
+			slot = input_mt_get_slot_by_key(ts->input,
+							report->ids[i]);
 			if (slot < 0) {
 				dev_dbg(dev, "no free slot for id 0x%x\n",
-					touch->id);
+					report->ids[i]);
 				continue;
 			}
 		} else {
@@ -149,14 +135,15 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 		}
 
 		input_mt_slot(ts->input, slot);
-		input_mt_report_slot_state(ts->input,
-					   MT_TOOL_FINGER, true);
+		input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true);
 
-		input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
-		input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
+		input_report_abs(ts->input, ABS_MT_POSITION_X,
+				 report->pos[i].x);
+		input_report_abs(ts->input, ABS_MT_POSITION_Y,
+				 report->pos[i].y);
 
 		dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
-			i, slot, touch->x, touch->y);
+			i, slot, report->pos[i].x, report->pos[i].y);
 	}
 
 	input_mt_sync_frame(ts->input);
@@ -515,7 +502,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	} else {
 		input_set_capability(input, EV_ABS, ABS_MT_POSITION_X);
 		input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y);
-		touchscreen_parse_properties(input, true);
+		touchscreen_parse_properties(input, true, &tsdata->prop);
 		if (!input_abs_get_max(input, ABS_MT_POSITION_X) ||
 		    !input_abs_get_max(input, ABS_MT_POSITION_Y)) {
 			dev_err(dev, "Touchscreen size is not specified\n");
diff --git b/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c
new file mode 100644
index 0000000..a99fb5c
--- /dev/null
+++ b/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -0,0 +1,1238 @@
+/*
+ * Raydium touchscreen I2C driver.
+ *
+ * Copyright (C) 2012-2014, Raydium Semiconductor Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only 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.
+ *
+ * Raydium reserves the right to make changes without further notice
+ * to the materials described herein. Raydium does not assume any
+ * liability arising out of the application described herein.
+ *
+ * Contact Raydium Semiconductor Corporation at www.rad-ic.com
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+/* Slave I2C mode */
+#define RM_BOOT_BLDR		0x02
+#define RM_BOOT_MAIN		0x03
+
+/* I2C bootoloader commands */
+#define RM_CMD_BOOT_PAGE_WRT	0x0B		/* send bl page write */
+#define RM_CMD_BOOT_WRT		0x11		/* send bl write */
+#define RM_CMD_BOOT_ACK		0x22		/* send ack*/
+#define RM_CMD_BOOT_CHK		0x33		/* send data check */
+#define RM_CMD_BOOT_READ	0x44		/* send wait bl data ready*/
+
+#define RM_BOOT_RDY		0xFF		/* bl data ready */
+
+/* I2C main commands */
+#define RM_CMD_QUERY_BANK	0x2B
+#define RM_CMD_DATA_BANK	0x4D
+#define RM_CMD_ENTER_SLEEP	0x4E
+#define RM_CMD_BANK_SWITCH	0xAA
+
+#define RM_RESET_MSG_ADDR	0x40000004
+
+#define RM_MAX_READ_SIZE	56
+#define RM_PACKET_CRC_SIZE	2
+
+/* Touch relative info */
+#define RM_MAX_RETRIES		3
+#define RM_MAX_TOUCH_NUM	10
+#define RM_BOOT_DELAY_MS	100
+
+/* Offsets in contact data */
+#define RM_CONTACT_STATE_POS	0
+#define RM_CONTACT_X_POS	1
+#define RM_CONTACT_Y_POS	3
+#define RM_CONTACT_PRESSURE_POS	5
+#define RM_CONTACT_WIDTH_X_POS	6
+#define RM_CONTACT_WIDTH_Y_POS	7
+
+/* Bootloader relative info */
+#define RM_BL_WRT_CMD_SIZE	3	/* bl flash wrt cmd size */
+#define RM_BL_WRT_PKG_SIZE	32	/* bl wrt pkg size */
+#define RM_BL_WRT_LEN		(RM_BL_WRT_PKG_SIZE + RM_BL_WRT_CMD_SIZE)
+#define RM_FW_PAGE_SIZE		128
+#define RM_MAX_FW_RETRIES	30
+#define RM_MAX_FW_SIZE		0xD000
+
+#define RM_POWERON_DELAY_USEC	500
+#define RM_RESET_DELAY_MSEC	50
+
+enum raydium_bl_cmd {
+	BL_HEADER = 0,
+	BL_PAGE_STR,
+	BL_PKG_IDX,
+	BL_DATA_STR,
+};
+
+enum raydium_bl_ack {
+	RAYDIUM_ACK_NULL = 0,
+	RAYDIUM_WAIT_READY,
+	RAYDIUM_PATH_READY,
+};
+
+enum raydium_boot_mode {
+	RAYDIUM_TS_MAIN = 0,
+	RAYDIUM_TS_BLDR,
+};
+
+/* Response to RM_CMD_DATA_BANK request */
+struct raydium_data_info {
+	__le32 data_bank_addr;
+	u8 pkg_size;
+	u8 tp_info_size;
+};
+
+struct raydium_info {
+	__le32 hw_ver;		/*device version */
+	u8 main_ver;
+	u8 sub_ver;
+	__le16 ft_ver;		/* test version */
+	u8 x_num;
+	u8 y_num;
+	__le16 x_max;
+	__le16 y_max;
+	u8 x_res;		/* units/mm */
+	u8 y_res;		/* units/mm */
+};
+
+/* struct raydium_data - represents state of Raydium touchscreen device */
+struct raydium_data {
+	struct i2c_client *client;
+	struct input_dev *input;
+
+	struct regulator *avdd;
+	struct regulator *vccio;
+	struct gpio_desc *reset_gpio;
+
+	struct raydium_info info;
+
+	struct mutex sysfs_mutex;
+
+	u8 *report_data;
+
+	u32 data_bank_addr;
+	u8 report_size;
+	u8 contact_size;
+	u8 pkg_size;
+
+	enum raydium_boot_mode boot_mode;
+
+	bool wake_irq_enabled;
+};
+
+static int raydium_i2c_send(struct i2c_client *client,
+			    u8 addr, const void *data, size_t len)
+{
+	u8 *buf;
+	int tries = 0;
+	int ret;
+
+	buf = kmalloc(len + 1, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf[0] = addr;
+	memcpy(buf + 1, data, len);
+
+	do {
+		ret = i2c_master_send(client, buf, len + 1);
+		if (likely(ret == len + 1))
+			break;
+
+		msleep(20);
+	} while (++tries < RM_MAX_RETRIES);
+
+	kfree(buf);
+
+	if (unlikely(ret != len + 1)) {
+		if (ret >= 0)
+			ret = -EIO;
+		dev_err(&client->dev, "%s failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int raydium_i2c_read(struct i2c_client *client,
+			    u8 addr, void *data, size_t len)
+{
+	struct i2c_msg xfer[] = {
+		{
+			.addr = client->addr,
+			.len = 1,
+			.buf = &addr,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = data,
+		}
+	};
+	int ret;
+
+	ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer));
+	if (unlikely(ret != ARRAY_SIZE(xfer)))
+		return ret < 0 ? ret : -EIO;
+
+	return 0;
+}
+
+static int raydium_i2c_read_message(struct i2c_client *client,
+				    u32 addr, void *data, size_t len)
+{
+	__be32 be_addr;
+	size_t xfer_len;
+	int error;
+
+	while (len) {
+		xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE);
+
+		be_addr = cpu_to_be32(addr);
+
+		error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
+					 &be_addr, sizeof(be_addr));
+		if (!error)
+			error = raydium_i2c_read(client, addr & 0xff,
+						 data, xfer_len);
+		if (error)
+			return error;
+
+		len -= xfer_len;
+		data += xfer_len;
+		addr += xfer_len;
+	}
+
+	return 0;
+}
+
+static int raydium_i2c_send_message(struct i2c_client *client,
+				    u32 addr, const void *data, size_t len)
+{
+	__be32 be_addr = cpu_to_be32(addr);
+	int error;
+
+	error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
+				 &be_addr, sizeof(be_addr));
+	if (!error)
+		error = raydium_i2c_send(client, addr & 0xff, data, len);
+
+	return error;
+}
+
+static int raydium_i2c_sw_reset(struct i2c_client *client)
+{
+	const u8 soft_rst_cmd = 0x01;
+	int error;
+
+	error = raydium_i2c_send_message(client, RM_RESET_MSG_ADDR,
+					 &soft_rst_cmd, sizeof(soft_rst_cmd));
+	if (error) {
+		dev_err(&client->dev, "software reset failed: %d\n", error);
+		return error;
+	}
+
+	msleep(RM_RESET_DELAY_MSEC);
+
+	return 0;
+}
+
+static int raydium_i2c_query_ts_info(struct raydium_data *ts)
+{
+	struct i2c_client *client = ts->client;
+	struct raydium_data_info data_info;
+	__le32 query_bank_addr;
+
+	int error, retry_cnt;
+
+	for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) {
+		error = raydium_i2c_read(client, RM_CMD_DATA_BANK,
+					 &data_info, sizeof(data_info));
+		if (error)
+			continue;
+
+		/*
+		 * Warn user if we already allocated memory for reports and
+		 * then the size changed (due to firmware update?) and keep
+		 * old size instead.
+		 */
+		if (ts->report_data && ts->pkg_size != data_info.pkg_size) {
+			dev_warn(&client->dev,
+				 "report size changes, was: %d, new: %d\n",
+				 ts->pkg_size, data_info.pkg_size);
+		} else {
+			ts->pkg_size = data_info.pkg_size;
+			ts->report_size = ts->pkg_size - RM_PACKET_CRC_SIZE;
+		}
+
+		ts->contact_size = data_info.tp_info_size;
+		ts->data_bank_addr = le32_to_cpu(data_info.data_bank_addr);
+
+		dev_dbg(&client->dev,
+			"data_bank_addr: %#08x, report_size: %d, contact_size: %d\n",
+			ts->data_bank_addr, ts->report_size, ts->contact_size);
+
+		error = raydium_i2c_read(client, RM_CMD_QUERY_BANK,
+					 &query_bank_addr,
+					 sizeof(query_bank_addr));
+		if (error)
+			continue;
+
+		error = raydium_i2c_read_message(client,
+						 le32_to_cpu(query_bank_addr),
+						 &ts->info, sizeof(ts->info));
+		if (error)
+			continue;
+
+		return 0;
+	}
+
+	dev_err(&client->dev, "failed to query device parameters: %d\n", error);
+	return error;
+}
+
+static int raydium_i2c_check_fw_status(struct raydium_data *ts)
+{
+	struct i2c_client *client = ts->client;
+	static const u8 bl_ack = 0x62;
+	static const u8 main_ack = 0x66;
+	u8 buf[4];
+	int error;
+
+	error = raydium_i2c_read(client, RM_CMD_BOOT_READ, buf, sizeof(buf));
+	if (!error) {
+		if (buf[0] == bl_ack)
+			ts->boot_mode = RAYDIUM_TS_BLDR;
+		else if (buf[0] == main_ack)
+			ts->boot_mode = RAYDIUM_TS_MAIN;
+		return 0;
+	}
+
+	return error;
+}
+
+static int raydium_i2c_initialize(struct raydium_data *ts)
+{
+	struct i2c_client *client = ts->client;
+	int error, retry_cnt;
+
+	for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) {
+		/* Wait for Hello packet */
+		msleep(RM_BOOT_DELAY_MS);
+
+		error = raydium_i2c_check_fw_status(ts);
+		if (error) {
+			dev_err(&client->dev,
+				"failed to read 'hello' packet: %d\n", error);
+			continue;
+		}
+
+		if (ts->boot_mode == RAYDIUM_TS_BLDR ||
+		    ts->boot_mode == RAYDIUM_TS_MAIN) {
+			break;
+		}
+	}
+
+	if (error)
+		ts->boot_mode = RAYDIUM_TS_BLDR;
+
+	if (ts->boot_mode == RAYDIUM_TS_BLDR) {
+		ts->info.hw_ver = cpu_to_le32(0xffffffffUL);
+		ts->info.main_ver = 0xff;
+		ts->info.sub_ver = 0xff;
+	} else {
+		raydium_i2c_query_ts_info(ts);
+	}
+
+	return error;
+}
+
+static int raydium_i2c_bl_chk_state(struct i2c_client *client,
+				    enum raydium_bl_ack state)
+{
+	static const u8 ack_ok[] = { 0xFF, 0x39, 0x30, 0x30, 0x54 };
+	u8 rbuf[sizeof(ack_ok)];
+	u8 retry;
+	int error;
+
+	for (retry = 0; retry < RM_MAX_FW_RETRIES; retry++) {
+		switch (state) {
+		case RAYDIUM_ACK_NULL:
+			return 0;
+
+		case RAYDIUM_WAIT_READY:
+			error = raydium_i2c_read(client, RM_CMD_BOOT_CHK,
+						 &rbuf[0], 1);
+			if (!error && rbuf[0] == RM_BOOT_RDY)
+				return 0;
+
+			break;
+
+		case RAYDIUM_PATH_READY:
+			error = raydium_i2c_read(client, RM_CMD_BOOT_CHK,
+						 rbuf, sizeof(rbuf));
+			if (!error && !memcmp(rbuf, ack_ok, sizeof(ack_ok)))
+				return 0;
+
+			break;
+
+		default:
+			dev_err(&client->dev, "%s: invalid target state %d\n",
+				__func__, state);
+			return -EINVAL;
+		}
+
+		msleep(20);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int raydium_i2c_write_object(struct i2c_client *client,
+				    const void *data, size_t len,
+				    enum raydium_bl_ack state)
+{
+	int error;
+
+	error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len);
+	if (error) {
+		dev_err(&client->dev, "WRT obj command failed: %d\n",
+			error);
+		return error;
+	}
+
+	error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, NULL, 0);
+	if (error) {
+		dev_err(&client->dev, "Ack obj command failed: %d\n", error);
+		return error;
+	}
+
+	error = raydium_i2c_bl_chk_state(client, state);
+	if (error) {
+		dev_err(&client->dev, "BL check state failed: %d\n", error);
+		return error;
+	}
+	return 0;
+}
+
+static bool raydium_i2c_boot_trigger(struct i2c_client *client)
+{
+	static const u8 cmd[7][6] = {
+		{ 0x08, 0x0C, 0x09, 0x00, 0x50, 0xD7 },
+		{ 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 },
+		{ 0x08, 0x04, 0x09, 0x00, 0x50, 0x00 },
+		{ 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 },
+		{ 0x08, 0x0C, 0x09, 0x00, 0x50, 0x00 },
+		{ 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 },
+		{ 0x02, 0xA2, 0x00, 0x00, 0x00, 0x00 },
+	};
+	int i;
+	int error;
+
+	for (i = 0; i < 7; i++) {
+		error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]),
+						 RAYDIUM_WAIT_READY);
+		if (error) {
+			dev_err(&client->dev,
+				"boot trigger failed at step %d: %d\n",
+				i, error);
+			return error;
+		}
+	}
+
+	return 0;
+}
+
+static bool raydium_i2c_fw_trigger(struct i2c_client *client)
+{
+	static const u8 cmd[5][11] = {
+		{ 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0xD7, 0, 0, 0 },
+		{ 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 },
+		{ 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 },
+		{ 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 },
+		{ 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 },
+	};
+	int i;
+	int error;
+
+	for (i = 0; i < 5; i++) {
+		error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]),
+						 RAYDIUM_ACK_NULL);
+		if (error) {
+			dev_err(&client->dev,
+				"fw trigger failed at step %d: %d\n",
+				i, error);
+			return error;
+		}
+	}
+
+	return 0;
+}
+
+static int raydium_i2c_check_path(struct i2c_client *client)
+{
+	static const u8 cmd[] = { 0x09, 0x00, 0x09, 0x00, 0x50, 0x10, 0x00 };
+	int error;
+
+	error = raydium_i2c_write_object(client, cmd, sizeof(cmd),
+					 RAYDIUM_PATH_READY);
+	if (error) {
+		dev_err(&client->dev, "check path command failed: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int raydium_i2c_enter_bl(struct i2c_client *client)
+{
+	static const u8 cal_cmd[] = { 0x00, 0x01, 0x52 };
+	int error;
+
+	error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd),
+					 RAYDIUM_ACK_NULL);
+	if (error) {
+		dev_err(&client->dev, "enter bl command failed: %d\n", error);
+		return error;
+	}
+
+	msleep(RM_BOOT_DELAY_MS);
+	return 0;
+}
+
+static int raydium_i2c_leave_bl(struct i2c_client *client)
+{
+	static const u8 leave_cmd[] = { 0x05, 0x00 };
+	int error;
+
+	error = raydium_i2c_write_object(client, leave_cmd, sizeof(leave_cmd),
+					 RAYDIUM_ACK_NULL);
+	if (error) {
+		dev_err(&client->dev, "leave bl command failed: %d\n", error);
+		return error;
+	}
+
+	msleep(RM_BOOT_DELAY_MS);
+	return 0;
+}
+
+static int raydium_i2c_write_checksum(struct i2c_client *client,
+				      size_t length, u16 checksum)
+{
+	u8 checksum_cmd[] = { 0x00, 0x05, 0x6D, 0x00, 0x00, 0x00, 0x00 };
+	int error;
+
+	put_unaligned_le16(length, &checksum_cmd[3]);
+	put_unaligned_le16(checksum, &checksum_cmd[5]);
+
+	error = raydium_i2c_write_object(client,
+					 checksum_cmd, sizeof(checksum_cmd),
+					 RAYDIUM_ACK_NULL);
+	if (error) {
+		dev_err(&client->dev, "failed to write checksum: %d\n",
+			error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int raydium_i2c_disable_watch_dog(struct i2c_client *client)
+{
+	static const u8 cmd[] = { 0x0A, 0xAA };
+	int error;
+
+	error = raydium_i2c_write_object(client, cmd, sizeof(cmd),
+					 RAYDIUM_WAIT_READY);
+	if (error) {
+		dev_err(&client->dev, "disable watchdog command failed: %d\n",
+			error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int raydium_i2c_fw_write_page(struct i2c_client *client,
+				     u16 page_idx, const void *data, size_t len)
+{
+	u8 buf[RM_BL_WRT_LEN];
+	size_t xfer_len;
+	int error;
+	int i;
+
+	BUILD_BUG_ON((RM_FW_PAGE_SIZE % RM_BL_WRT_PKG_SIZE) != 0);
+
+	for (i = 0; i < RM_FW_PAGE_SIZE / RM_BL_WRT_PKG_SIZE; i++) {
+		buf[BL_HEADER] = RM_CMD_BOOT_PAGE_WRT;
+		buf[BL_PAGE_STR] = page_idx ? 0xff : 0;
+		buf[BL_PKG_IDX] = i + 1;
+
+		xfer_len = min_t(size_t, len, RM_BL_WRT_PKG_SIZE);
+		memcpy(&buf[BL_DATA_STR], data, xfer_len);
+		if (len < RM_BL_WRT_PKG_SIZE)
+			memset(&buf[BL_DATA_STR + xfer_len], 0xff,
+				RM_BL_WRT_PKG_SIZE - xfer_len);
+
+		error = raydium_i2c_write_object(client, buf, RM_BL_WRT_LEN,
+						 RAYDIUM_WAIT_READY);
+		if (error) {
+			dev_err(&client->dev,
+				"page write command failed for page %d, chunk %d: %d\n",
+				page_idx, i, error);
+			return error;
+		}
+
+		data += xfer_len;
+		len -= xfer_len;
+	}
+
+	return error;
+}
+
+static u16 raydium_calc_chksum(const u8 *buf, u16 len)
+{
+	u16 checksum = 0;
+	u16 i;
+
+	for (i = 0; i < len; i++)
+		checksum += buf[i];
+
+	return checksum;
+}
+
+static int raydium_i2c_do_update_firmware(struct raydium_data *ts,
+					 const struct firmware *fw)
+{
+	struct i2c_client *client = ts->client;
+	const void *data;
+	size_t data_len;
+	size_t len;
+	int page_nr;
+	int i;
+	int error;
+	u16 fw_checksum;
+
+	if (fw->size == 0 || fw->size > RM_MAX_FW_SIZE) {
+		dev_err(&client->dev, "Invalid firmware length\n");
+		return -EINVAL;
+	}
+
+	error = raydium_i2c_check_fw_status(ts);
+	if (error) {
+		dev_err(&client->dev, "Unable to access IC %d\n", error);
+		return error;
+	}
+
+	if (ts->boot_mode == RAYDIUM_TS_MAIN) {
+		for (i = 0; i < RM_MAX_RETRIES; i++) {
+			error = raydium_i2c_enter_bl(client);
+			if (!error) {
+				error = raydium_i2c_check_fw_status(ts);
+				if (error) {
+					dev_err(&client->dev,
+						"unable to access IC: %d\n",
+						error);
+					return error;
+				}
+
+				if (ts->boot_mode == RAYDIUM_TS_BLDR)
+					break;
+			}
+		}
+
+		if (ts->boot_mode == RAYDIUM_TS_MAIN) {
+			dev_err(&client->dev,
+				"failied to jump to boot loader: %d\n",
+				error);
+			return -EIO;
+		}
+	}
+
+	error = raydium_i2c_disable_watch_dog(client);
+	if (error)
+		return error;
+
+	error = raydium_i2c_check_path(client);
+	if (error)
+		return error;
+
+	error = raydium_i2c_boot_trigger(client);
+	if (error) {
+		dev_err(&client->dev, "send boot trigger fail: %d\n", error);
+		return error;
+	}
+
+	msleep(RM_BOOT_DELAY_MS);
+
+	data = fw->data;
+	data_len = fw->size;
+	page_nr = 0;
+
+	while (data_len) {
+		len = min_t(size_t, data_len, RM_FW_PAGE_SIZE);
+
+		error = raydium_i2c_fw_write_page(client, page_nr++, data, len);
+		if (error)
+			return error;
+
+		msleep(20);
+
+		data += len;
+		data_len -= len;
+	}
+
+	error = raydium_i2c_leave_bl(client);
+	if (error) {
+		dev_err(&client->dev,
+			"failed to leave boot loader: %d\n", error);
+		return error;
+	}
+
+	dev_dbg(&client->dev, "left boot loader mode\n");
+	msleep(RM_BOOT_DELAY_MS);
+
+	error = raydium_i2c_check_fw_status(ts);
+	if (error) {
+		dev_err(&client->dev,
+			"failed to check fw status after write: %d\n",
+			error);
+		return error;
+	}
+
+	if (ts->boot_mode != RAYDIUM_TS_MAIN) {
+		dev_err(&client->dev,
+			"failed to switch to main fw after writing firmware: %d\n",
+			error);
+		return -EINVAL;
+	}
+
+	error = raydium_i2c_fw_trigger(client);
+	if (error) {
+		dev_err(&client->dev, "failed to trigger fw: %d\n", error);
+		return error;
+	}
+
+	fw_checksum = raydium_calc_chksum(fw->data, fw->size);
+
+	error = raydium_i2c_write_checksum(client, fw->size, fw_checksum);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static int raydium_i2c_fw_update(struct raydium_data *ts)
+{
+	struct i2c_client *client = ts->client;
+	const struct firmware *fw = NULL;
+	const char *fw_file = "raydium.fw";
+	int error;
+
+	error = request_firmware(&fw, fw_file, &client->dev);
+	if (error) {
+		dev_err(&client->dev, "Unable to open firmware %s\n", fw_file);
+		return error;
+	}
+
+	disable_irq(client->irq);
+
+	error = raydium_i2c_do_update_firmware(ts, fw);
+	if (error) {
+		dev_err(&client->dev, "firmware update failed: %d\n", error);
+		ts->boot_mode = RAYDIUM_TS_BLDR;
+		goto out_enable_irq;
+	}
+
+	error = raydium_i2c_initialize(ts);
+	if (error) {
+		dev_err(&client->dev,
+			"failed to initialize device after firmware update: %d\n",
+			error);
+		ts->boot_mode = RAYDIUM_TS_BLDR;
+		goto out_enable_irq;
+	}
+
+	ts->boot_mode = RAYDIUM_TS_MAIN;
+
+out_enable_irq:
+	enable_irq(client->irq);
+	msleep(100);
+
+	release_firmware(fw);
+
+	return error;
+}
+
+static void raydium_mt_event(struct raydium_data *ts)
+{
+	int i;
+
+	for (i = 0; i < ts->report_size / ts->contact_size; i++) {
+		u8 *contact = &ts->report_data[ts->contact_size * i];
+		bool state = contact[RM_CONTACT_STATE_POS];
+		u8 wx, wy;
+
+		input_mt_slot(ts->input, i);
+		input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, state);
+
+		if (!state)
+			continue;
+
+		input_report_abs(ts->input, ABS_MT_POSITION_X,
+				get_unaligned_le16(&contact[RM_CONTACT_X_POS]));
+		input_report_abs(ts->input, ABS_MT_POSITION_Y,
+				get_unaligned_le16(&contact[RM_CONTACT_Y_POS]));
+		input_report_abs(ts->input, ABS_MT_PRESSURE,
+				contact[RM_CONTACT_PRESSURE_POS]);
+
+		wx = contact[RM_CONTACT_WIDTH_X_POS];
+		wy = contact[RM_CONTACT_WIDTH_Y_POS];
+
+		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, max(wx, wy));
+		input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, min(wx, wy));
+	}
+
+	input_mt_sync_frame(ts->input);
+	input_sync(ts->input);
+}
+
+static irqreturn_t raydium_i2c_irq(int irq, void *_dev)
+{
+	struct raydium_data *ts = _dev;
+	int error;
+	u16 fw_crc;
+	u16 calc_crc;
+
+	if (ts->boot_mode != RAYDIUM_TS_MAIN)
+		goto out;
+
+	error = raydium_i2c_read_message(ts->client, ts->data_bank_addr,
+					 ts->report_data, ts->pkg_size);
+	if (error)
+		goto out;
+
+	fw_crc = get_unaligned_le16(&ts->report_data[ts->report_size]);
+	calc_crc = raydium_calc_chksum(ts->report_data, ts->report_size);
+	if (unlikely(fw_crc != calc_crc)) {
+		dev_warn(&ts->client->dev,
+			 "%s: invalid packet crc %#04x vs %#04x\n",
+			 __func__, calc_crc, fw_crc);
+		goto out;
+	}
+
+	raydium_mt_event(ts);
+
+out:
+	return IRQ_HANDLED;
+}
+
+static ssize_t raydium_i2c_fw_ver_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct raydium_data *ts = i2c_get_clientdata(client);
+
+	return sprintf(buf, "%d.%d\n", ts->info.main_ver, ts->info.sub_ver);
+}
+
+static ssize_t raydium_i2c_hw_ver_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct raydium_data *ts = i2c_get_clientdata(client);
+
+	return sprintf(buf, "%#04x\n", le32_to_cpu(ts->info.hw_ver));
+}
+
+static ssize_t raydium_i2c_boot_mode_show(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct raydium_data *ts = i2c_get_clientdata(client);
+
+	return sprintf(buf, "%s\n",
+		       ts->boot_mode == RAYDIUM_TS_MAIN ?
+				"Normal" : "Recovery");
+}
+
+static ssize_t raydium_i2c_update_fw_store(struct device *dev,
+					   struct device_attribute *attr,
+					   const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct raydium_data *ts = i2c_get_clientdata(client);
+	int error;
+
+	error = mutex_lock_interruptible(&ts->sysfs_mutex);
+	if (error)
+		return error;
+
+	error = raydium_i2c_fw_update(ts);
+
+	mutex_unlock(&ts->sysfs_mutex);
+
+	return error ?: count;
+}
+
+static ssize_t raydium_i2c_calibrate_store(struct device *dev,
+					   struct device_attribute *attr,
+					   const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct raydium_data *ts = i2c_get_clientdata(client);
+	static const u8 cal_cmd[] = { 0x00, 0x01, 0x9E };
+	int error;
+
+	error = mutex_lock_interruptible(&ts->sysfs_mutex);
+	if (error)
+		return error;
+
+	error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd),
+					 RAYDIUM_WAIT_READY);
+	if (error)
+		dev_err(&client->dev, "calibrate command failed: %d\n", error);
+
+	mutex_unlock(&ts->sysfs_mutex);
+	return error ?: count;
+}
+
+static DEVICE_ATTR(fw_version, S_IRUGO, raydium_i2c_fw_ver_show, NULL);
+static DEVICE_ATTR(hw_version, S_IRUGO, raydium_i2c_hw_ver_show, NULL);
+static DEVICE_ATTR(boot_mode, S_IRUGO, raydium_i2c_boot_mode_show, NULL);
+static DEVICE_ATTR(update_fw, S_IWUSR, NULL, raydium_i2c_update_fw_store);
+static DEVICE_ATTR(calibrate, S_IWUSR, NULL, raydium_i2c_calibrate_store);
+
+static struct attribute *raydium_i2c_attributes[] = {
+	&dev_attr_update_fw.attr,
+	&dev_attr_boot_mode.attr,
+	&dev_attr_fw_version.attr,
+	&dev_attr_hw_version.attr,
+	&dev_attr_calibrate.attr,
+	NULL
+};
+
+static struct attribute_group raydium_i2c_attribute_group = {
+	.attrs = raydium_i2c_attributes,
+};
+
+static void raydium_i2c_remove_sysfs_group(void *_data)
+{
+	struct raydium_data *ts = _data;
+
+	sysfs_remove_group(&ts->client->dev.kobj, &raydium_i2c_attribute_group);
+}
+
+static int raydium_i2c_power_on(struct raydium_data *ts)
+{
+	int error;
+
+	if (!ts->reset_gpio)
+		return 0;
+
+	gpiod_set_value_cansleep(ts->reset_gpio, 1);
+
+	error = regulator_enable(ts->avdd);
+	if (error) {
+		dev_err(&ts->client->dev,
+			"failed to enable avdd regulator: %d\n", error);
+		goto release_reset_gpio;
+	}
+
+	error = regulator_enable(ts->vccio);
+	if (error) {
+		regulator_disable(ts->avdd);
+		dev_err(&ts->client->dev,
+			"failed to enable vccio regulator: %d\n", error);
+		goto release_reset_gpio;
+	}
+
+	udelay(RM_POWERON_DELAY_USEC);
+
+release_reset_gpio:
+	gpiod_set_value_cansleep(ts->reset_gpio, 0);
+
+	if (error)
+		return error;
+
+	msleep(RM_RESET_DELAY_MSEC);
+
+	return 0;
+}
+
+static void raydium_i2c_power_off(void *_data)
+{
+	struct raydium_data *ts = _data;
+
+	if (ts->reset_gpio) {
+		gpiod_set_value_cansleep(ts->reset_gpio, 1);
+		regulator_disable(ts->vccio);
+		regulator_disable(ts->avdd);
+	}
+}
+
+static int raydium_i2c_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	union i2c_smbus_data dummy;
+	struct raydium_data *ts;
+	int error;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev,
+			"i2c check functionality error (need I2C_FUNC_I2C)\n");
+		return -ENXIO;
+	}
+
+	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	mutex_init(&ts->sysfs_mutex);
+
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+
+	ts->avdd = devm_regulator_get(&client->dev, "avdd");
+	if (IS_ERR(ts->avdd)) {
+		error = PTR_ERR(ts->avdd);
+		if (error != -EPROBE_DEFER)
+			dev_err(&client->dev,
+				"Failed to get 'avdd' regulator: %d\n", error);
+		return error;
+	}
+
+	ts->vccio = devm_regulator_get(&client->dev, "vccio");
+	if (IS_ERR(ts->vccio)) {
+		error = PTR_ERR(ts->vccio);
+		if (error != -EPROBE_DEFER)
+			dev_err(&client->dev,
+				"Failed to get 'vccio' regulator: %d\n", error);
+		return error;
+	}
+
+	ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+						 GPIOD_OUT_LOW);
+	if (IS_ERR(ts->reset_gpio)) {
+		error = PTR_ERR(ts->reset_gpio);
+		if (error != -EPROBE_DEFER)
+			dev_err(&client->dev,
+				"failed to get reset gpio: %d\n", error);
+		return error;
+	}
+
+	error = raydium_i2c_power_on(ts);
+	if (error)
+		return error;
+
+	error = devm_add_action(&client->dev, raydium_i2c_power_off, ts);
+	if (error) {
+		dev_err(&client->dev,
+			"failed to install power off action: %d\n", error);
+		raydium_i2c_power_off(ts);
+		return error;
+	}
+
+	/* Make sure there is something at this address */
+	if (i2c_smbus_xfer(client->adapter, client->addr, 0,
+			   I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) {
+		dev_err(&client->dev, "nothing at this address\n");
+		return -ENXIO;
+	}
+
+	error = raydium_i2c_initialize(ts);
+	if (error) {
+		dev_err(&client->dev, "failed to initialize: %d\n", error);
+		return error;
+	}
+
+	ts->report_data = devm_kmalloc(&client->dev,
+				       ts->pkg_size, GFP_KERNEL);
+	if (!ts->report_data)
+		return -ENOMEM;
+
+	ts->input = devm_input_allocate_device(&client->dev);
+	if (!ts->input) {
+		dev_err(&client->dev, "Failed to allocate input device\n");
+		return -ENOMEM;
+	}
+
+	ts->input->name = "Raydium Touchscreen";
+	ts->input->id.bustype = BUS_I2C;
+
+	input_set_drvdata(ts->input, ts);
+
+	input_set_abs_params(ts->input, ABS_MT_POSITION_X,
+			     0, le16_to_cpu(ts->info.x_max), 0, 0);
+	input_set_abs_params(ts->input, ABS_MT_POSITION_Y,
+			     0, le16_to_cpu(ts->info.y_max), 0, 0);
+	input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->info.x_res);
+	input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->info.y_res);
+
+	input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+	input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
+
+	error = input_mt_init_slots(ts->input, RM_MAX_TOUCH_NUM,
+				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+	if (error) {
+		dev_err(&client->dev,
+			"failed to initialize MT slots: %d\n", error);
+		return error;
+	}
+
+	error = input_register_device(ts->input);
+	if (error) {
+		dev_err(&client->dev,
+			"unable to register input device: %d\n", error);
+		return error;
+	}
+
+	error = devm_request_threaded_irq(&client->dev, client->irq,
+					  NULL, raydium_i2c_irq,
+					  IRQF_ONESHOT, client->name, ts);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		return error;
+	}
+
+	error = sysfs_create_group(&client->dev.kobj,
+				   &raydium_i2c_attribute_group);
+	if (error) {
+		dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
+			error);
+		return error;
+	}
+
+	error = devm_add_action(&client->dev,
+				raydium_i2c_remove_sysfs_group, ts);
+	if (error) {
+		raydium_i2c_remove_sysfs_group(ts);
+		dev_err(&client->dev,
+			"Failed to add sysfs cleanup action: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static void __maybe_unused raydium_enter_sleep(struct i2c_client *client)
+{
+	static const u8 sleep_cmd[] = { 0x5A, 0xff, 0x00, 0x0f };
+	int error;
+
+	error = raydium_i2c_send(client, RM_CMD_ENTER_SLEEP,
+				 sleep_cmd, sizeof(sleep_cmd));
+	if (error)
+		dev_err(&client->dev,
+			"sleep command failed: %d\n", error);
+}
+
+static int __maybe_unused raydium_i2c_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct raydium_data *ts = i2c_get_clientdata(client);
+
+	/* Sleep is not available in BLDR recovery mode */
+	if (ts->boot_mode != RAYDIUM_TS_MAIN)
+		return -EBUSY;
+
+	disable_irq(client->irq);
+
+	if (device_may_wakeup(dev)) {
+		raydium_enter_sleep(client);
+
+		ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0);
+	} else {
+		raydium_i2c_power_off(ts);
+	}
+
+	return 0;
+}
+
+static int __maybe_unused raydium_i2c_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct raydium_data *ts = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(dev)) {
+		if (ts->wake_irq_enabled)
+			disable_irq_wake(client->irq);
+		raydium_i2c_sw_reset(client);
+	} else {
+		raydium_i2c_power_on(ts);
+		raydium_i2c_initialize(ts);
+	}
+
+	enable_irq(client->irq);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
+			 raydium_i2c_suspend, raydium_i2c_resume);
+
+static const struct i2c_device_id raydium_i2c_id[] = {
+	{ "raydium_i2c" , 0 },
+	{ "rm32380", 0 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, raydium_i2c_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id raydium_acpi_id[] = {
+	{ "RAYD0001", 0 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, raydium_acpi_id);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id raydium_of_match[] = {
+	{ .compatible = "raydium,rm32380", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, raydium_of_match);
+#endif
+
+static struct i2c_driver raydium_i2c_driver = {
+	.probe = raydium_i2c_probe,
+	.id_table = raydium_i2c_id,
+	.driver = {
+		.name = "raydium_ts",
+		.pm = &raydium_i2c_pm_ops,
+		.acpi_match_table = ACPI_PTR(raydium_acpi_id),
+		.of_match_table = of_match_ptr(raydium_of_match),
+	},
+};
+module_i2c_driver(raydium_i2c_driver);
+
+MODULE_AUTHOR("Raydium");
+MODULE_DESCRIPTION("Raydium I2c Touchscreen driver");
+MODULE_LICENSE("GPL v2");
diff --git b/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
new file mode 100644
index 0000000..7379fe1
--- /dev/null
+++ b/drivers/input/touchscreen/silead.c
@@ -0,0 +1,565 @@
+/* -------------------------------------------------------------------------
+ * Copyright (C) 2014-2015, Intel Corporation
+ *
+ * Derived from:
+ *  gslX68X.c
+ *  Copyright (C) 2010-2015, Shanghai Sileadinc Co.Ltd
+ *
+ *  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/i2c.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/interrupt.h>
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/pm.h>
+#include <linux/irq.h>
+
+#include <asm/unaligned.h>
+
+#define SILEAD_TS_NAME		"silead_ts"
+
+#define SILEAD_REG_RESET	0xE0
+#define SILEAD_REG_DATA		0x80
+#define SILEAD_REG_TOUCH_NR	0x80
+#define SILEAD_REG_POWER	0xBC
+#define SILEAD_REG_CLOCK	0xE4
+#define SILEAD_REG_STATUS	0xB0
+#define SILEAD_REG_ID		0xFC
+#define SILEAD_REG_MEM_CHECK	0xB0
+
+#define SILEAD_STATUS_OK	0x5A5A5A5A
+#define SILEAD_TS_DATA_LEN	44
+#define SILEAD_CLOCK		0x04
+
+#define SILEAD_CMD_RESET	0x88
+#define SILEAD_CMD_START	0x00
+
+#define SILEAD_POINT_DATA_LEN	0x04
+#define SILEAD_POINT_Y_OFF      0x00
+#define SILEAD_POINT_Y_MSB_OFF	0x01
+#define SILEAD_POINT_X_OFF	0x02
+#define SILEAD_POINT_X_MSB_OFF	0x03
+#define SILEAD_TOUCH_ID_MASK	0xF0
+
+#define SILEAD_CMD_SLEEP_MIN	10000
+#define SILEAD_CMD_SLEEP_MAX	20000
+#define SILEAD_POWER_SLEEP	20
+#define SILEAD_STARTUP_SLEEP	30
+
+#define SILEAD_MAX_FINGERS	10
+
+enum silead_ts_power {
+	SILEAD_POWER_ON  = 1,
+	SILEAD_POWER_OFF = 0
+};
+
+struct silead_ts_data {
+	struct i2c_client *client;
+	struct gpio_desc *gpio_power;
+	struct input_dev *input;
+	char fw_name[64];
+	struct touchscreen_properties prop;
+	u32 max_fingers;
+	u32 chip_id;
+	struct input_mt_pos pos[SILEAD_MAX_FINGERS];
+	int slots[SILEAD_MAX_FINGERS];
+	int id[SILEAD_MAX_FINGERS];
+};
+
+struct silead_fw_data {
+	u32 offset;
+	u32 val;
+};
+
+static int silead_ts_request_input_dev(struct silead_ts_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int error;
+
+	data->input = devm_input_allocate_device(dev);
+	if (!data->input) {
+		dev_err(dev,
+			"Failed to allocate input device\n");
+		return -ENOMEM;
+	}
+
+	input_set_abs_params(data->input, ABS_MT_POSITION_X, 0, 4095, 0, 0);
+	input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
+	touchscreen_parse_properties(data->input, true, &data->prop);
+
+	input_mt_init_slots(data->input, data->max_fingers,
+			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
+			    INPUT_MT_TRACK);
+
+	data->input->name = SILEAD_TS_NAME;
+	data->input->phys = "input/ts";
+	data->input->id.bustype = BUS_I2C;
+
+	error = input_register_device(data->input);
+	if (error) {
+		dev_err(dev, "Failed to register input device: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static void silead_ts_set_power(struct i2c_client *client,
+				enum silead_ts_power state)
+{
+	struct silead_ts_data *data = i2c_get_clientdata(client);
+
+	if (data->gpio_power) {
+		gpiod_set_value_cansleep(data->gpio_power, state);
+		msleep(SILEAD_POWER_SLEEP);
+	}
+}
+
+static void silead_ts_read_data(struct i2c_client *client)
+{
+	struct silead_ts_data *data = i2c_get_clientdata(client);
+	struct input_dev *input = data->input;
+	struct device *dev = &client->dev;
+	u8 *bufp, buf[SILEAD_TS_DATA_LEN];
+	int touch_nr, error, i;
+
+	error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_DATA,
+					      SILEAD_TS_DATA_LEN, buf);
+	if (error < 0) {
+		dev_err(dev, "Data read error %d\n", error);
+		return;
+	}
+
+	touch_nr = buf[0];
+	if (touch_nr > data->max_fingers) {
+		dev_warn(dev, "More touches reported then supported %d > %d\n",
+			 touch_nr, data->max_fingers);
+		touch_nr = data->max_fingers;
+	}
+
+	bufp = buf + SILEAD_POINT_DATA_LEN;
+	for (i = 0; i < touch_nr; i++, bufp += SILEAD_POINT_DATA_LEN) {
+		/* Bits 4-7 are the touch id */
+		data->id[i] = (bufp[SILEAD_POINT_X_MSB_OFF] &
+			       SILEAD_TOUCH_ID_MASK) >> 4;
+		touchscreen_set_mt_pos(&data->pos[i], &data->prop,
+			get_unaligned_le16(&bufp[SILEAD_POINT_X_OFF]) & 0xfff,
+			get_unaligned_le16(&bufp[SILEAD_POINT_Y_OFF]) & 0xfff);
+	}
+
+	input_mt_assign_slots(input, data->slots, data->pos, touch_nr, 0);
+
+	for (i = 0; i < touch_nr; i++) {
+		input_mt_slot(input, data->slots[i]);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+		input_report_abs(input, ABS_MT_POSITION_X, data->pos[i].x);
+		input_report_abs(input, ABS_MT_POSITION_Y, data->pos[i].y);
+
+		dev_dbg(dev, "x=%d y=%d hw_id=%d sw_id=%d\n", data->pos[i].x,
+			data->pos[i].y, data->id[i], data->slots[i]);
+	}
+
+	input_mt_sync_frame(input);
+	input_sync(input);
+}
+
+static int silead_ts_init(struct i2c_client *client)
+{
+	struct silead_ts_data *data = i2c_get_clientdata(client);
+	int error;
+
+	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
+					  SILEAD_CMD_RESET);
+	if (error)
+		goto i2c_write_err;
+	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+	error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
+					data->max_fingers);
+	if (error)
+		goto i2c_write_err;
+	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+	error = i2c_smbus_write_byte_data(client, SILEAD_REG_CLOCK,
+					  SILEAD_CLOCK);
+	if (error)
+		goto i2c_write_err;
+	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
+					  SILEAD_CMD_START);
+	if (error)
+		goto i2c_write_err;
+	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+	return 0;
+
+i2c_write_err:
+	dev_err(&client->dev, "Registers clear error %d\n", error);
+	return error;
+}
+
+static int silead_ts_reset(struct i2c_client *client)
+{
+	int error;
+
+	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
+					  SILEAD_CMD_RESET);
+	if (error)
+		goto i2c_write_err;
+	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+	error = i2c_smbus_write_byte_data(client, SILEAD_REG_CLOCK,
+					  SILEAD_CLOCK);
+	if (error)
+		goto i2c_write_err;
+	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+	error = i2c_smbus_write_byte_data(client, SILEAD_REG_POWER,
+					  SILEAD_CMD_START);
+	if (error)
+		goto i2c_write_err;
+	usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
+
+	return 0;
+
+i2c_write_err:
+	dev_err(&client->dev, "Chip reset error %d\n", error);
+	return error;
+}
+
+static int silead_ts_startup(struct i2c_client *client)
+{
+	int error;
+
+	error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET, 0x00);
+	if (error) {
+		dev_err(&client->dev, "Startup error %d\n", error);
+		return error;
+	}
+
+	msleep(SILEAD_STARTUP_SLEEP);
+
+	return 0;
+}
+
+static int silead_ts_load_fw(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct silead_ts_data *data = i2c_get_clientdata(client);
+	unsigned int fw_size, i;
+	const struct firmware *fw;
+	struct silead_fw_data *fw_data;
+	int error;
+
+	dev_dbg(dev, "Firmware file name: %s", data->fw_name);
+
+	error = request_firmware(&fw, data->fw_name, dev);
+	if (error) {
+		dev_err(dev, "Firmware request error %d\n", error);
+		return error;
+	}
+
+	fw_size = fw->size / sizeof(*fw_data);
+	fw_data = (struct silead_fw_data *)fw->data;
+
+	for (i = 0; i < fw_size; i++) {
+		error = i2c_smbus_write_i2c_block_data(client,
+						       fw_data[i].offset,
+						       4,
+						       (u8 *)&fw_data[i].val);
+		if (error) {
+			dev_err(dev, "Firmware load error %d\n", error);
+			break;
+		}
+	}
+
+	release_firmware(fw);
+	return error ?: 0;
+}
+
+static u32 silead_ts_get_status(struct i2c_client *client)
+{
+	int error;
+	__le32 status;
+
+	error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_STATUS,
+					      sizeof(status), (u8 *)&status);
+	if (error < 0) {
+		dev_err(&client->dev, "Status read error %d\n", error);
+		return error;
+	}
+
+	return le32_to_cpu(status);
+}
+
+static int silead_ts_get_id(struct i2c_client *client)
+{
+	struct silead_ts_data *data = i2c_get_clientdata(client);
+	__le32 chip_id;
+	int error;
+
+	error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_ID,
+					      sizeof(chip_id), (u8 *)&chip_id);
+	if (error < 0) {
+		dev_err(&client->dev, "Chip ID read error %d\n", error);
+		return error;
+	}
+
+	data->chip_id = le32_to_cpu(chip_id);
+	dev_info(&client->dev, "Silead chip ID: 0x%8X", data->chip_id);
+
+	return 0;
+}
+
+static int silead_ts_setup(struct i2c_client *client)
+{
+	int error;
+	u32 status;
+
+	silead_ts_set_power(client, SILEAD_POWER_OFF);
+	silead_ts_set_power(client, SILEAD_POWER_ON);
+
+	error = silead_ts_get_id(client);
+	if (error)
+		return error;
+
+	error = silead_ts_init(client);
+	if (error)
+		return error;
+
+	error = silead_ts_reset(client);
+	if (error)
+		return error;
+
+	error = silead_ts_load_fw(client);
+	if (error)
+		return error;
+
+	error = silead_ts_startup(client);
+	if (error)
+		return error;
+
+	status = silead_ts_get_status(client);
+	if (status != SILEAD_STATUS_OK) {
+		dev_err(&client->dev,
+			"Initialization error, status: 0x%X\n", status);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static irqreturn_t silead_ts_threaded_irq_handler(int irq, void *id)
+{
+	struct silead_ts_data *data = id;
+	struct i2c_client *client = data->client;
+
+	silead_ts_read_data(client);
+
+	return IRQ_HANDLED;
+}
+
+static void silead_ts_read_props(struct i2c_client *client)
+{
+	struct silead_ts_data *data = i2c_get_clientdata(client);
+	struct device *dev = &client->dev;
+	const char *str;
+	int error;
+
+	error = device_property_read_u32(dev, "silead,max-fingers",
+					 &data->max_fingers);
+	if (error) {
+		dev_dbg(dev, "Max fingers read error %d\n", error);
+		data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
+	}
+
+	error = device_property_read_string(dev, "touchscreen-fw-name", &str);
+	if (!error)
+		snprintf(data->fw_name, sizeof(data->fw_name), "%s", str);
+	else
+		dev_dbg(dev, "Firmware file name read error. Using default.");
+}
+
+#ifdef CONFIG_ACPI
+static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
+					 const struct i2c_device_id *id)
+{
+	const struct acpi_device_id *acpi_id;
+	struct device *dev = &data->client->dev;
+	int i;
+
+	if (ACPI_HANDLE(dev)) {
+		acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+		if (!acpi_id)
+			return -ENODEV;
+
+		snprintf(data->fw_name, sizeof(data->fw_name), "%s.fw",
+			acpi_id->id);
+
+		for (i = 0; i < strlen(data->fw_name); i++)
+			data->fw_name[i] = tolower(data->fw_name[i]);
+	} else {
+		snprintf(data->fw_name, sizeof(data->fw_name), "%s.fw",
+			id->name);
+	}
+
+	return 0;
+}
+#else
+static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
+					 const struct i2c_device_id *id)
+{
+	snprintf(data->fw_name, sizeof(data->fw_name), "%s.fw", id->name);
+	return 0;
+}
+#endif
+
+static int silead_ts_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
+{
+	struct silead_ts_data *data;
+	struct device *dev = &client->dev;
+	int error;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_I2C |
+				     I2C_FUNC_SMBUS_READ_I2C_BLOCK |
+				     I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
+		dev_err(dev, "I2C functionality check failed\n");
+		return -ENXIO;
+	}
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	data->client = client;
+
+	error = silead_ts_set_default_fw_name(data, id);
+	if (error)
+		return error;
+
+	silead_ts_read_props(client);
+
+	/* We must have the IRQ provided by DT or ACPI subsytem */
+	if (client->irq <= 0)
+		return -ENODEV;
+
+	/* Power GPIO pin */
+	data->gpio_power = gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
+	if (IS_ERR(data->gpio_power)) {
+		if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER)
+			dev_err(dev, "Shutdown GPIO request failed\n");
+		return PTR_ERR(data->gpio_power);
+	}
+
+	error = silead_ts_setup(client);
+	if (error)
+		return error;
+
+	error = silead_ts_request_input_dev(data);
+	if (error)
+		return error;
+
+	error = devm_request_threaded_irq(dev, client->irq,
+					  NULL, silead_ts_threaded_irq_handler,
+					  IRQF_ONESHOT, client->name, data);
+	if (error) {
+		if (error != -EPROBE_DEFER)
+			dev_err(dev, "IRQ request failed %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int __maybe_unused silead_ts_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	silead_ts_set_power(client, SILEAD_POWER_OFF);
+	return 0;
+}
+
+static int __maybe_unused silead_ts_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int error, status;
+
+	silead_ts_set_power(client, SILEAD_POWER_ON);
+
+	error = silead_ts_reset(client);
+	if (error)
+		return error;
+
+	error = silead_ts_startup(client);
+	if (error)
+		return error;
+
+	status = silead_ts_get_status(client);
+	if (status != SILEAD_STATUS_OK) {
+		dev_err(dev, "Resume error, status: 0x%02x\n", status);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume);
+
+static const struct i2c_device_id silead_ts_id[] = {
+	{ "gsl1680", 0 },
+	{ "gsl1688", 0 },
+	{ "gsl3670", 0 },
+	{ "gsl3675", 0 },
+	{ "gsl3692", 0 },
+	{ "mssl1680", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, silead_ts_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id silead_ts_acpi_match[] = {
+	{ "GSL1680", 0 },
+	{ "GSL1688", 0 },
+	{ "GSL3670", 0 },
+	{ "GSL3675", 0 },
+	{ "GSL3692", 0 },
+	{ "MSSL1680", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match);
+#endif
+
+static struct i2c_driver silead_ts_driver = {
+	.probe = silead_ts_probe,
+	.id_table = silead_ts_id,
+	.driver = {
+		.name = SILEAD_TS_NAME,
+		.acpi_match_table = ACPI_PTR(silead_ts_acpi_match),
+		.pm = &silead_ts_pm,
+	},
+};
+module_i2c_driver(silead_ts_driver);
+
+MODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>");
+MODULE_DESCRIPTION("Silead I2C touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git b/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c
new file mode 100644
index 0000000..8d93f8c
--- /dev/null
+++ b/drivers/input/touchscreen/sis_i2c.c
@@ -0,0 +1,413 @@
+/*
+ * Touch Screen driver for SiS 9200 family I2C Touch panels
+ *
+ * Copyright (C) 2015 SiS, Inc.
+ * Copyright (C) 2016 Nextfour Group
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/crc-itu-t.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define SIS_I2C_NAME		"sis_i2c_ts"
+
+/*
+ * The I2C packet format:
+ * le16		byte count
+ * u8		Report ID
+ * <contact data - variable length>
+ * u8		Number of contacts
+ * le16		Scan Time (optional)
+ * le16		CRC
+ *
+ * One touch point information consists of 6+ bytes, the order is:
+ * u8		contact state
+ * u8		finger id
+ * le16		x axis
+ * le16		y axis
+ * u8		contact width (optional)
+ * u8		contact height (optional)
+ * u8		pressure (optional)
+ *
+ * Maximum amount of data transmitted in one shot is 64 bytes, if controller
+ * needs to report more contacts than fit in one packet it will send true
+ * number of contacts in first packet and 0 as number of contacts in second
+ * packet.
+ */
+
+#define SIS_MAX_PACKET_SIZE		64
+
+#define SIS_PKT_LEN_OFFSET		0
+#define SIS_PKT_REPORT_OFFSET		2 /* Report ID/type */
+#define SIS_PKT_CONTACT_OFFSET		3 /* First contact */
+
+#define SIS_SCAN_TIME_LEN		2
+
+/* Supported report types */
+#define SIS_ALL_IN_ONE_PACKAGE		0x10
+#define SIS_PKT_IS_TOUCH(x)		(((x) & 0x0f) == 0x01)
+#define SIS_PKT_IS_HIDI2C(x)		(((x) & 0x0f) == 0x06)
+
+/* Contact properties within report */
+#define SIS_PKT_HAS_AREA(x)		((x) & BIT(4))
+#define SIS_PKT_HAS_PRESSURE(x)		((x) & BIT(5))
+#define SIS_PKT_HAS_SCANTIME(x)		((x) & BIT(6))
+
+/* Contact size */
+#define SIS_BASE_LEN_PER_CONTACT	6
+#define SIS_AREA_LEN_PER_CONTACT	2
+#define SIS_PRESSURE_LEN_PER_CONTACT	1
+
+/* Offsets within contact data */
+#define SIS_CONTACT_STATUS_OFFSET	0
+#define SIS_CONTACT_ID_OFFSET		1 /* Contact ID */
+#define SIS_CONTACT_X_OFFSET		2
+#define SIS_CONTACT_Y_OFFSET		4
+#define SIS_CONTACT_WIDTH_OFFSET	6
+#define SIS_CONTACT_HEIGHT_OFFSET	7
+#define SIS_CONTACT_PRESSURE_OFFSET(id)	(SIS_PKT_HAS_AREA(id) ? 8 : 6)
+
+/* Individual contact state */
+#define SIS_STATUS_UP			0x0
+#define SIS_STATUS_DOWN			0x3
+
+/* Touchscreen parameters */
+#define SIS_MAX_FINGERS			10
+#define SIS_MAX_X			4095
+#define SIS_MAX_Y			4095
+#define SIS_MAX_PRESSURE		255
+
+/* Resolution diagonal */
+#define SIS_AREA_LENGTH_LONGER		5792
+/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/
+#define SIS_AREA_LENGTH_SHORT		5792
+#define SIS_AREA_UNIT			(5792 / 32)
+
+struct sis_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input;
+
+	struct gpio_desc *attn_gpio;
+	struct gpio_desc *reset_gpio;
+
+	u8 packet[SIS_MAX_PACKET_SIZE];
+};
+
+static int sis_read_packet(struct i2c_client *client, u8 *buf,
+			   unsigned int *num_contacts,
+			   unsigned int *contact_size)
+{
+	int count_idx;
+	int ret;
+	u16 len;
+	u16 crc, pkg_crc;
+	u8 report_id;
+
+	ret = i2c_master_recv(client, buf, SIS_MAX_PACKET_SIZE);
+	if (ret <= 0)
+		return -EIO;
+
+	len = get_unaligned_le16(&buf[SIS_PKT_LEN_OFFSET]);
+	if (len > SIS_MAX_PACKET_SIZE) {
+		dev_err(&client->dev,
+			"%s: invalid packet length (%d vs %d)\n",
+			__func__, len, SIS_MAX_PACKET_SIZE);
+		return -E2BIG;
+	}
+
+	if (len < 10)
+		return -EINVAL;
+
+	report_id = buf[SIS_PKT_REPORT_OFFSET];
+	count_idx  = len - 1;
+	*contact_size = SIS_BASE_LEN_PER_CONTACT;
+
+	if (report_id != SIS_ALL_IN_ONE_PACKAGE) {
+		if (SIS_PKT_IS_TOUCH(report_id)) {
+			/*
+			 * Calculate CRC ignoring packet length
+			 * in the beginning and CRC transmitted
+			 * at the end of the packet.
+			 */
+			crc = crc_itu_t(0, buf + 2, len - 2 - 2);
+			pkg_crc = get_unaligned_le16(&buf[len - 2]);
+
+			if (crc != pkg_crc) {
+				dev_err(&client->dev,
+					"%s: CRC Error (%d vs %d)\n",
+					__func__, crc, pkg_crc);
+				return -EINVAL;
+			}
+
+			count_idx -= 2;
+
+		} else if (!SIS_PKT_IS_HIDI2C(report_id)) {
+			dev_err(&client->dev,
+				"%s: invalid packet ID %#02x\n",
+				__func__, report_id);
+			return -EINVAL;
+		}
+
+		if (SIS_PKT_HAS_SCANTIME(report_id))
+			count_idx -= SIS_SCAN_TIME_LEN;
+
+		if (SIS_PKT_HAS_AREA(report_id))
+			*contact_size += SIS_AREA_LEN_PER_CONTACT;
+		if (SIS_PKT_HAS_PRESSURE(report_id))
+			*contact_size += SIS_PRESSURE_LEN_PER_CONTACT;
+	}
+
+	*num_contacts = buf[count_idx];
+	return 0;
+}
+
+static int sis_ts_report_contact(struct sis_ts_data *ts, const u8 *data, u8 id)
+{
+	struct input_dev *input = ts->input;
+	int slot;
+	u8 status = data[SIS_CONTACT_STATUS_OFFSET];
+	u8 pressure;
+	u8 height, width;
+	u16 x, y;
+
+	if (status != SIS_STATUS_DOWN && status != SIS_STATUS_UP) {
+		dev_err(&ts->client->dev, "Unexpected touch status: %#02x\n",
+			data[SIS_CONTACT_STATUS_OFFSET]);
+		return -EINVAL;
+	}
+
+	slot = input_mt_get_slot_by_key(input, data[SIS_CONTACT_ID_OFFSET]);
+	if (slot < 0)
+		return -ENOENT;
+
+	input_mt_slot(input, slot);
+	input_mt_report_slot_state(input, MT_TOOL_FINGER,
+				   status == SIS_STATUS_DOWN);
+
+	if (status == SIS_STATUS_DOWN) {
+		pressure = height = width = 1;
+		if (id != SIS_ALL_IN_ONE_PACKAGE) {
+			if (SIS_PKT_HAS_AREA(id)) {
+				width = data[SIS_CONTACT_WIDTH_OFFSET];
+				height = data[SIS_CONTACT_HEIGHT_OFFSET];
+			}
+
+			if (SIS_PKT_HAS_PRESSURE(id))
+				pressure =
+					data[SIS_CONTACT_PRESSURE_OFFSET(id)];
+		}
+
+		x = get_unaligned_le16(&data[SIS_CONTACT_X_OFFSET]);
+		y = get_unaligned_le16(&data[SIS_CONTACT_Y_OFFSET]);
+
+		input_report_abs(input, ABS_MT_TOUCH_MAJOR,
+				 width * SIS_AREA_UNIT);
+		input_report_abs(input, ABS_MT_TOUCH_MINOR,
+				 height * SIS_AREA_UNIT);
+		input_report_abs(input, ABS_MT_PRESSURE, pressure);
+		input_report_abs(input, ABS_MT_POSITION_X, x);
+		input_report_abs(input, ABS_MT_POSITION_Y, y);
+	}
+
+	return 0;
+}
+
+static void sis_ts_handle_packet(struct sis_ts_data *ts)
+{
+	const u8 *contact;
+	unsigned int num_to_report = 0;
+	unsigned int num_contacts;
+	unsigned int num_reported;
+	unsigned int contact_size;
+	int error;
+	u8 report_id;
+
+	do {
+		error = sis_read_packet(ts->client, ts->packet,
+					&num_contacts, &contact_size);
+		if (error)
+			break;
+
+		if (num_to_report == 0) {
+			num_to_report = num_contacts;
+		} else if (num_contacts != 0) {
+			dev_err(&ts->client->dev,
+				"%s: nonzero (%d) point count in tail packet\n",
+				__func__, num_contacts);
+			break;
+		}
+
+		report_id = ts->packet[SIS_PKT_REPORT_OFFSET];
+		contact = &ts->packet[SIS_PKT_CONTACT_OFFSET];
+		num_reported = 0;
+
+		while (num_to_report > 0) {
+			error = sis_ts_report_contact(ts, contact, report_id);
+			if (error)
+				break;
+
+			contact += contact_size;
+			num_to_report--;
+			num_reported++;
+
+			if (report_id != SIS_ALL_IN_ONE_PACKAGE &&
+			    num_reported >= 5) {
+				/*
+				 * The remainder of contacts is sent
+				 * in the 2nd packet.
+				 */
+				break;
+			}
+		}
+	} while (num_to_report > 0);
+
+	input_mt_sync_frame(ts->input);
+	input_sync(ts->input);
+}
+
+static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id)
+{
+	struct sis_ts_data *ts = dev_id;
+
+	do {
+		sis_ts_handle_packet(ts);
+	} while (ts->attn_gpio && gpiod_get_value_cansleep(ts->attn_gpio));
+
+	return IRQ_HANDLED;
+}
+
+static void sis_ts_reset(struct sis_ts_data *ts)
+{
+	if (ts->reset_gpio) {
+		/* Get out of reset */
+		usleep_range(1000, 2000);
+		gpiod_set_value(ts->reset_gpio, 1);
+		usleep_range(1000, 2000);
+		gpiod_set_value(ts->reset_gpio, 0);
+		msleep(100);
+	}
+}
+
+static int sis_ts_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct sis_ts_data *ts;
+	struct input_dev *input;
+	int error;
+
+	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+
+	ts->attn_gpio = devm_gpiod_get_optional(&client->dev,
+						"attn", GPIOD_IN);
+	if (IS_ERR(ts->attn_gpio)) {
+		error = PTR_ERR(ts->attn_gpio);
+		if (error != -EPROBE_DEFER)
+			dev_err(&client->dev,
+				"Failed to get attention GPIO: %d\n", error);
+		return error;
+	}
+
+	ts->reset_gpio = devm_gpiod_get_optional(&client->dev,
+						 "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ts->reset_gpio)) {
+		error = PTR_ERR(ts->reset_gpio);
+		if (error != -EPROBE_DEFER)
+			dev_err(&client->dev,
+				"Failed to get reset GPIO: %d\n", error);
+		return error;
+	}
+
+	sis_ts_reset(ts);
+
+	ts->input = input = devm_input_allocate_device(&client->dev);
+	if (!input) {
+		dev_err(&client->dev, "Failed to allocate input device\n");
+		return -ENOMEM;
+	}
+
+	input->name = "SiS Touchscreen";
+	input->id.bustype = BUS_I2C;
+
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0);
+	input_set_abs_params(input, ABS_MT_PRESSURE, 0, SIS_MAX_PRESSURE, 0, 0);
+	input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
+			     0, SIS_AREA_LENGTH_LONGER, 0, 0);
+	input_set_abs_params(input, ABS_MT_TOUCH_MINOR,
+			     0, SIS_AREA_LENGTH_SHORT, 0, 0);
+
+	error = input_mt_init_slots(input, SIS_MAX_FINGERS, INPUT_MT_DIRECT);
+	if (error) {
+		dev_err(&client->dev,
+			"Failed to initialize MT slots: %d\n", error);
+		return error;
+	}
+
+	error = devm_request_threaded_irq(&client->dev, client->irq,
+					  NULL, sis_ts_irq_handler,
+					  IRQF_ONESHOT,
+					  client->name, ts);
+	if (error) {
+		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+		return error;
+	}
+
+	error = input_register_device(ts->input);
+	if (error) {
+		dev_err(&client->dev,
+			"Failed to register input device: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id sis_ts_dt_ids[] = {
+	{ .compatible = "sis,9200-ts" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sis_ts_dt_ids);
+#endif
+
+static const struct i2c_device_id sis_ts_id[] = {
+	{ SIS_I2C_NAME,	0 },
+	{ "9200-ts",	0 },
+	{ /* sentinel */  }
+};
+MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+
+static struct i2c_driver sis_ts_driver = {
+	.driver = {
+		.name	= SIS_I2C_NAME,
+		.of_match_table = of_match_ptr(sis_ts_dt_ids),
+	},
+	.probe		= sis_ts_probe,
+	.id_table	= sis_ts_id,
+};
+module_i2c_driver(sis_ts_driver);
+
+MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Mika Penttilä <mika.penttila@nextfour.com>");
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
index 4857943..d07dd29 100644
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -115,7 +115,6 @@
 struct sun4i_ts_data {
 	struct device *dev;
 	struct input_dev *input;
-	struct thermal_zone_device *tz;
 	void __iomem *base;
 	unsigned int irq;
 	bool ignore_fifo_data;
@@ -366,10 +365,7 @@ static int sun4i_ts_probe(struct platform_device *pdev)
 	if (IS_ERR(hwmon))
 		return PTR_ERR(hwmon);
 
-	ts->tz = thermal_zone_of_sensor_register(ts->dev, 0, ts,
-						 &sun4i_ts_tz_ops);
-	if (IS_ERR(ts->tz))
-		ts->tz = NULL;
+	devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, &sun4i_ts_tz_ops);
 
 	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
 
@@ -377,7 +373,6 @@ static int sun4i_ts_probe(struct platform_device *pdev)
 		error = input_register_device(ts->input);
 		if (error) {
 			writel(0, ts->base + TP_INT_FIFOC);
-			thermal_zone_of_sensor_unregister(ts->dev, ts->tz);
 			return error;
 		}
 	}
@@ -394,8 +389,6 @@ static int sun4i_ts_remove(struct platform_device *pdev)
 	if (ts->input)
 		input_unregister_device(ts->input);
 
-	thermal_zone_of_sensor_unregister(ts->dev, ts->tz);
-
 	/* Deactivate all IRQs */
 	writel(0, ts->base + TP_INT_FIFOC);
 
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 880c40b..4ea4757 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -126,7 +126,7 @@ struct sur40_image_header {
 #define VIDEO_PACKET_SIZE  16384
 
 /* polling interval (ms) */
-#define POLL_INTERVAL 4
+#define POLL_INTERVAL 1
 
 /* maximum number of contacts FIXME: this is a guess? */
 #define MAX_CONTACTS 64
@@ -151,7 +151,6 @@ struct sur40_state {
 	struct mutex lock;
 
 	struct vb2_queue queue;
-	struct vb2_alloc_ctx *alloc_ctx;
 	struct list_head buf_list;
 	spinlock_t qlock;
 	int sequence;
@@ -448,7 +447,7 @@ static void sur40_process_video(struct sur40_state *sur40)
 
 	/* return error if streaming was stopped in the meantime */
 	if (sur40->sequence == -1)
-		goto err_poll;
+		return;
 
 	/* mark as finished */
 	new_buf->vb.vb2_buf.timestamp = ktime_get_ns();
@@ -580,19 +579,13 @@ static int sur40_probe(struct usb_interface *interface,
 	sur40->queue = sur40_queue;
 	sur40->queue.drv_priv = sur40;
 	sur40->queue.lock = &sur40->lock;
+	sur40->queue.dev = sur40->dev;
 
 	/* initialize the queue */
 	error = vb2_queue_init(&sur40->queue);
 	if (error)
 		goto err_unreg_v4l2;
 
-	sur40->alloc_ctx = vb2_dma_sg_init_ctx(sur40->dev);
-	if (IS_ERR(sur40->alloc_ctx)) {
-		dev_err(sur40->dev, "Can't allocate buffer context");
-		error = PTR_ERR(sur40->alloc_ctx);
-		goto err_unreg_v4l2;
-	}
-
 	sur40->vdev = sur40_video_device;
 	sur40->vdev.v4l2_dev = &sur40->v4l2;
 	sur40->vdev.lock = &sur40->lock;
@@ -633,7 +626,6 @@ static void sur40_disconnect(struct usb_interface *interface)
 
 	video_unregister_device(&sur40->vdev);
 	v4l2_device_unregister(&sur40->v4l2);
-	vb2_dma_sg_cleanup_ctx(sur40->alloc_ctx);
 
 	input_unregister_polled_device(sur40->input);
 	input_free_polled_device(sur40->input);
@@ -653,13 +645,10 @@ static void sur40_disconnect(struct usb_interface *interface)
  */
 static int sur40_queue_setup(struct vb2_queue *q,
 		       unsigned int *nbuffers, unsigned int *nplanes,
-		       unsigned int sizes[], void *alloc_ctxs[])
+		       unsigned int sizes[], struct device *alloc_devs[])
 {
-	struct sur40_state *sur40 = vb2_get_drv_priv(q);
-
 	if (q->num_buffers + *nbuffers < 3)
 		*nbuffers = 3 - q->num_buffers;
-	alloc_ctxs[0] = sur40->alloc_ctx;
 
 	if (*nplanes)
 		return sizes[0] < sur40_video_format.sizeimage ? -EINVAL : 0;
@@ -736,6 +725,7 @@ static int sur40_start_streaming(struct vb2_queue *vq, unsigned int count)
 static void sur40_stop_streaming(struct vb2_queue *vq)
 {
 	struct sur40_state *sur40 = vb2_get_drv_priv(vq);
+	vb2_wait_for_all_buffers(vq);
 	sur40->sequence = -1;
 
 	/* Release all active buffers */
@@ -793,7 +783,6 @@ static int sur40_vidioc_enum_fmt(struct file *file, void *priv,
 {
 	if (f->index != 0)
 		return -EINVAL;
-	strlcpy(f->description, "8-bit greyscale", sizeof(f->description));
 	f->pixelformat = V4L2_PIX_FMT_GREY;
 	f->flags = 0;
 	return 0;
diff --git b/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
new file mode 100644
index 0000000..e12fb9b
--- /dev/null
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -0,0 +1,427 @@
+/*
+ *  Driver for Ntrig/Microsoft Touchscreens over SPI
+ *
+ *  Copyright (c) 2016 Red Hat Inc.
+ */
+
+/*
+ * 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; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+
+#include <asm/unaligned.h>
+
+#define SURFACE3_PACKET_SIZE	264
+
+#define SURFACE3_REPORT_TOUCH	0xd2
+#define SURFACE3_REPORT_PEN	0x16
+
+struct surface3_ts_data {
+	struct spi_device *spi;
+	struct gpio_desc *gpiod_rst[2];
+	struct input_dev *input_dev;
+	struct input_dev *pen_input_dev;
+	int pen_tool;
+
+	u8 rd_buf[SURFACE3_PACKET_SIZE]		____cacheline_aligned;
+};
+
+struct surface3_ts_data_finger {
+	u8 status;
+	__le16 tracking_id;
+	__le16 x;
+	__le16 cx;
+	__le16 y;
+	__le16 cy;
+	__le16 width;
+	__le16 height;
+	u32 padding;
+} __packed;
+
+struct surface3_ts_data_pen {
+	u8 status;
+	__le16 x;
+	__le16 y;
+	__le16 pressure;
+	u8 padding;
+} __packed;
+
+static int surface3_spi_read(struct surface3_ts_data *ts_data)
+{
+	struct spi_device *spi = ts_data->spi;
+
+	memset(ts_data->rd_buf, 0, sizeof(ts_data->rd_buf));
+	return spi_read(spi, ts_data->rd_buf, sizeof(ts_data->rd_buf));
+}
+
+static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
+				   struct surface3_ts_data_finger *finger)
+{
+	int st = finger->status & 0x01;
+	int slot;
+
+	slot = input_mt_get_slot_by_key(ts_data->input_dev,
+				get_unaligned_le16(&finger->tracking_id));
+	if (slot < 0)
+		return;
+
+	input_mt_slot(ts_data->input_dev, slot);
+	input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, st);
+	if (st) {
+		input_report_abs(ts_data->input_dev,
+				 ABS_MT_POSITION_X,
+				 get_unaligned_le16(&finger->x));
+		input_report_abs(ts_data->input_dev,
+				 ABS_MT_POSITION_Y,
+				 get_unaligned_le16(&finger->y));
+		input_report_abs(ts_data->input_dev,
+				 ABS_MT_WIDTH_MAJOR,
+				 get_unaligned_le16(&finger->width));
+		input_report_abs(ts_data->input_dev,
+				 ABS_MT_WIDTH_MINOR,
+				 get_unaligned_le16(&finger->height));
+	}
+}
+
+static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data)
+{
+	u16 timestamp;
+	unsigned int i;
+	timestamp = get_unaligned_le16(&data[15]);
+
+	for (i = 0; i < 13; i++) {
+		struct surface3_ts_data_finger *finger;
+
+		finger = (struct surface3_ts_data_finger *)&data[17 +
+				i * sizeof(struct surface3_ts_data_finger)];
+
+		/*
+		 * When bit 5 of status is 1, it marks the end of the report:
+		 * - touch present: 0xe7
+		 * - touch released: 0xe4
+		 * - nothing valuable: 0xff
+		 */
+		if (finger->status & 0x10)
+			break;
+
+		surface3_spi_report_touch(ts_data, finger);
+	}
+
+	input_mt_sync_frame(ts_data->input_dev);
+	input_sync(ts_data->input_dev);
+}
+
+static void surface3_spi_report_pen(struct surface3_ts_data *ts_data,
+				    struct surface3_ts_data_pen *pen)
+{
+	struct input_dev *dev = ts_data->pen_input_dev;
+	int st = pen->status;
+	int prox = st & 0x01;
+	int rubber = st & 0x18;
+	int tool = (prox && rubber) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+
+	/* fake proximity out to switch tools */
+	if (ts_data->pen_tool != tool) {
+		input_report_key(dev, ts_data->pen_tool, 0);
+		input_sync(dev);
+		ts_data->pen_tool = tool;
+	}
+
+	input_report_key(dev, BTN_TOUCH, st & 0x12);
+
+	input_report_key(dev, ts_data->pen_tool, prox);
+
+	if (st) {
+		input_report_key(dev,
+				 BTN_STYLUS,
+				 st & 0x04);
+
+		input_report_abs(dev,
+				 ABS_X,
+				 get_unaligned_le16(&pen->x));
+		input_report_abs(dev,
+				 ABS_Y,
+				 get_unaligned_le16(&pen->y));
+		input_report_abs(dev,
+				 ABS_PRESSURE,
+				 get_unaligned_le16(&pen->pressure));
+	}
+}
+
+static void surface3_spi_process_pen(struct surface3_ts_data *ts_data, u8 *data)
+{
+	struct surface3_ts_data_pen *pen;
+
+	pen = (struct surface3_ts_data_pen *)&data[15];
+
+	surface3_spi_report_pen(ts_data, pen);
+	input_sync(ts_data->pen_input_dev);
+}
+
+static void surface3_spi_process(struct surface3_ts_data *ts_data)
+{
+	const char header[] = {
+		0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e, 0x01
+	};
+	u8 *data = ts_data->rd_buf;
+
+	if (memcmp(header, data, sizeof(header)))
+		dev_err(&ts_data->spi->dev,
+			"%s header error: %*ph, ignoring...\n",
+			__func__, (int)sizeof(header), data);
+
+	switch (data[9]) {
+	case SURFACE3_REPORT_TOUCH:
+		surface3_spi_process_touch(ts_data, data);
+		break;
+	case SURFACE3_REPORT_PEN:
+		surface3_spi_process_pen(ts_data, data);
+		break;
+	default:
+		dev_err(&ts_data->spi->dev,
+			"%s unknown packet type: %x, ignoring...\n",
+			__func__, data[9]);
+		break;
+	}
+}
+
+static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
+{
+	struct surface3_ts_data *data = dev_id;
+
+	if (surface3_spi_read(data))
+		return IRQ_HANDLED;
+
+	dev_dbg(&data->spi->dev, "%s received -> %*ph\n",
+		__func__, SURFACE3_PACKET_SIZE, data->rd_buf);
+	surface3_spi_process(data);
+
+	return IRQ_HANDLED;
+}
+
+static void surface3_spi_power(struct surface3_ts_data *data, bool on)
+{
+	gpiod_set_value(data->gpiod_rst[0], on);
+	gpiod_set_value(data->gpiod_rst[1], on);
+	/* let the device settle a little */
+	msleep(20);
+}
+
+/**
+ * surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT
+ *
+ * @ts: surface3_spi_ts_data pointer
+ */
+static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
+{
+	int error;
+	struct device *dev;
+	struct gpio_desc *gpiod;
+	int i;
+
+	dev = &data->spi->dev;
+
+	/* Get the reset lines GPIO pin number */
+	for (i = 0; i < 2; i++) {
+		gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW);
+		if (IS_ERR(gpiod)) {
+			error = PTR_ERR(gpiod);
+			if (error != -EPROBE_DEFER)
+				dev_err(dev,
+					"Failed to get power GPIO %d: %d\n",
+					i,
+					error);
+			return error;
+		}
+
+		data->gpiod_rst[i] = gpiod;
+	}
+
+	return 0;
+}
+
+static int surface3_spi_create_touch_input(struct surface3_ts_data *data)
+{
+	struct input_dev *input;
+	int error;
+
+	input = devm_input_allocate_device(&data->spi->dev);
+	if (!input)
+		return -ENOMEM;
+
+	data->input_dev = input;
+
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, 9600, 0, 0);
+	input_abs_set_res(input, ABS_MT_POSITION_X, 40);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 7200, 0, 0);
+	input_abs_set_res(input, ABS_MT_POSITION_Y, 48);
+	input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 1024, 0, 0);
+	input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 1024, 0, 0);
+	input_mt_init_slots(input, 10, INPUT_MT_DIRECT);
+
+	input->name = "Surface3 SPI Capacitive TouchScreen";
+	input->phys = "input/ts";
+	input->id.bustype = BUS_SPI;
+	input->id.vendor = 0x045e;	/* Microsoft */
+	input->id.product = 0x0001;
+	input->id.version = 0x0000;
+
+	error = input_register_device(input);
+	if (error) {
+		dev_err(&data->spi->dev,
+			"Failed to register input device: %d", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int surface3_spi_create_pen_input(struct surface3_ts_data *data)
+{
+	struct input_dev *input;
+	int error;
+
+	input = devm_input_allocate_device(&data->spi->dev);
+	if (!input)
+		return -ENOMEM;
+
+	data->pen_input_dev = input;
+	data->pen_tool = BTN_TOOL_PEN;
+
+	__set_bit(INPUT_PROP_DIRECT, input->propbit);
+	__set_bit(INPUT_PROP_POINTER, input->propbit);
+	input_set_abs_params(input, ABS_X, 0, 9600, 0, 0);
+	input_abs_set_res(input, ABS_X, 40);
+	input_set_abs_params(input, ABS_Y, 0, 7200, 0, 0);
+	input_abs_set_res(input, ABS_Y, 48);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 1024, 0, 0);
+	input_set_capability(input, EV_KEY, BTN_TOUCH);
+	input_set_capability(input, EV_KEY, BTN_STYLUS);
+	input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
+	input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
+
+	input->name = "Surface3 SPI Pen Input";
+	input->phys = "input/ts";
+	input->id.bustype = BUS_SPI;
+	input->id.vendor = 0x045e;     /* Microsoft */
+	input->id.product = 0x0002;
+	input->id.version = 0x0000;
+
+	error = input_register_device(input);
+	if (error) {
+		dev_err(&data->spi->dev,
+			"Failed to register input device: %d", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int surface3_spi_probe(struct spi_device *spi)
+{
+	struct surface3_ts_data *data;
+	int error;
+
+	/* Set up SPI*/
+	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_0;
+	error = spi_setup(spi);
+	if (error)
+		return error;
+
+	data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->spi = spi;
+	spi_set_drvdata(spi, data);
+
+	error = surface3_spi_get_gpio_config(data);
+	if (error)
+		return error;
+
+	surface3_spi_power(data, true);
+	surface3_spi_power(data, false);
+	surface3_spi_power(data, true);
+
+	error = surface3_spi_create_touch_input(data);
+	if (error)
+		return error;
+
+	error = surface3_spi_create_pen_input(data);
+	if (error)
+		return error;
+
+	error = devm_request_threaded_irq(&spi->dev, spi->irq,
+					  NULL, surface3_spi_irq_handler,
+					  IRQF_ONESHOT,
+					  "Surface3-irq", data);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static int __maybe_unused surface3_spi_suspend(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct surface3_ts_data *data = spi_get_drvdata(spi);
+
+	disable_irq(data->spi->irq);
+
+	surface3_spi_power(data, false);
+
+	return 0;
+}
+
+static int __maybe_unused surface3_spi_resume(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct surface3_ts_data *data = spi_get_drvdata(spi);
+
+	surface3_spi_power(data, true);
+
+	enable_irq(data->spi->irq);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
+			 surface3_spi_suspend,
+			 surface3_spi_resume);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id surface3_spi_acpi_match[] = {
+	{ "MSHW0037", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, surface3_spi_acpi_match);
+#endif
+
+static struct spi_driver surface3_spi_driver = {
+	.driver = {
+		.name	= "Surface3-spi",
+		.acpi_match_table = ACPI_PTR(surface3_spi_acpi_match),
+		.pm = &surface3_spi_pm_ops,
+	},
+	.probe = surface3_spi_probe,
+};
+
+module_spi_driver(surface3_spi_driver);
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
+MODULE_DESCRIPTION("Surface 3 SPI touchscreen driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index a21a07c..7953381 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -406,7 +406,7 @@ static int titsc_probe(struct platform_device *pdev)
 	int err;
 
 	/* Allocate memory for device */
-	ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL);
+	ts_dev = kzalloc(sizeof(*ts_dev), GFP_KERNEL);
 	input_dev = input_allocate_device();
 	if (!ts_dev || !input_dev) {
 		dev_err(&pdev->dev, "failed to allocate memory.\n");
@@ -487,8 +487,7 @@ static int titsc_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int titsc_suspend(struct device *dev)
+static int __maybe_unused titsc_suspend(struct device *dev)
 {
 	struct titsc *ts_dev = dev_get_drvdata(dev);
 	struct ti_tscadc_dev *tscadc_dev;
@@ -504,7 +503,7 @@ static int titsc_suspend(struct device *dev)
 	return 0;
 }
 
-static int titsc_resume(struct device *dev)
+static int __maybe_unused titsc_resume(struct device *dev)
 {
 	struct titsc *ts_dev = dev_get_drvdata(dev);
 	struct ti_tscadc_dev *tscadc_dev;
@@ -521,14 +520,7 @@ static int titsc_resume(struct device *dev)
 	return 0;
 }
 
-static const struct dev_pm_ops titsc_pm_ops = {
-	.suspend = titsc_suspend,
-	.resume  = titsc_resume,
-};
-#define TITSC_PM_OPS (&titsc_pm_ops)
-#else
-#define TITSC_PM_OPS NULL
-#endif
+static SIMPLE_DEV_PM_OPS(titsc_pm_ops, titsc_suspend, titsc_resume);
 
 static const struct of_device_id ti_tsc_dt_ids[] = {
 	{ .compatible = "ti,am3359-tsc", },
@@ -541,7 +533,7 @@ static struct platform_driver ti_tsc_driver = {
 	.remove	= titsc_remove,
 	.driver	= {
 		.name   = "TI-am335x-tsc",
-		.pm	= TITSC_PM_OPS,
+		.pm	= &titsc_pm_ops,
 		.of_match_table = ti_tsc_dt_ids,
 	},
 };
diff --git a/drivers/input/touchscreen/ts4800-ts.c b/drivers/input/touchscreen/ts4800-ts.c
index 3c3dd78..fed73ee 100644
--- a/drivers/input/touchscreen/ts4800-ts.c
+++ b/drivers/input/touchscreen/ts4800-ts.c
@@ -118,6 +118,13 @@ static int ts4800_parse_dt(struct platform_device *pdev,
 		return -ENODEV;
 	}
 
+	ts->regmap = syscon_node_to_regmap(syscon_np);
+	of_node_put(syscon_np);
+	if (IS_ERR(ts->regmap)) {
+		dev_err(dev, "cannot get parent's regmap\n");
+		return PTR_ERR(ts->regmap);
+	}
+
 	error = of_property_read_u32_index(np, "syscon", 1, &reg);
 	if (error < 0) {
 		dev_err(dev, "no offset in syscon\n");
@@ -134,12 +141,6 @@ static int ts4800_parse_dt(struct platform_device *pdev,
 
 	ts->bit = BIT(bit);
 
-	ts->regmap = syscon_node_to_regmap(syscon_np);
-	if (IS_ERR(ts->regmap)) {
-		dev_err(dev, "cannot get parent's regmap\n");
-		return PTR_ERR(ts->regmap);
-	}
-
 	return 0;
 }
 
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c
index dfa7f1c..b7059ed 100644
--- a/drivers/input/touchscreen/tsc200x-core.c
+++ b/drivers/input/touchscreen/tsc200x-core.c
@@ -568,7 +568,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0);
 
 	if (np)
-		touchscreen_parse_properties(input_dev, false);
+		touchscreen_parse_properties(input_dev, false, NULL);
 
 	input_dev->open = tsc200x_open;
 	input_dev->close = tsc200x_close;
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index b6fc4bd..85e9572 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -518,13 +518,21 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename,
 		w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
 
 		__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
-		input_mt_init_slots(dev, 2, 0);
+		error = input_mt_init_slots(dev, 2, 0);
+		if (error) {
+			dev_err(&w8001->serio->dev,
+				"failed to initialize MT slots: %d\n", error);
+			return error;
+		}
+
 		input_set_abs_params(dev, ABS_MT_POSITION_X,
 					0, touch.x, 0, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_Y,
 					0, touch.y, 0, 0);
 		input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
 					0, MT_TOOL_MAX, 0, 0);
+		input_abs_set_res(dev, ABS_MT_POSITION_X, touch.panel_res);
+		input_abs_set_res(dev, ABS_MT_POSITION_Y, touch.panel_res);
 
 		strlcat(basename, " 2FG", basename_sz);
 		if (w8001->max_pen_x && w8001->max_pen_y)
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index d32b544..ca19130 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -24,8 +24,12 @@
 #include <linux/slab.h>
 #include <linux/regmap.h>
 #include <linux/err.h>
+#include <linux/input.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/interrupt.h>
 
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps65217.h>
@@ -162,6 +166,82 @@ static const struct of_device_id tps65217_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tps65217_of_match);
 
+static irqreturn_t tps65217_irq(int irq, void *irq_data)
+{
+	struct tps65217 *tps = irq_data;
+	unsigned int int_reg = 0, status_reg = 0;
+
+	tps65217_reg_read(tps, TPS65217_REG_INT, &int_reg);
+	tps65217_reg_read(tps, TPS65217_REG_STATUS, &status_reg);
+	if (status_reg)
+		dev_dbg(tps->dev, "status now: 0x%X\n", status_reg);
+
+	if (!int_reg)
+		return IRQ_NONE;
+
+	if (int_reg & TPS65217_INT_PBI) {
+		/* Handle push button */
+		dev_dbg(tps->dev, "power button status change\n");
+		input_report_key(tps->pwr_but, KEY_POWER,
+				status_reg & TPS65217_STATUS_PB);
+		input_sync(tps->pwr_but);
+	}
+	if (int_reg & TPS65217_INT_ACI) {
+		/* Handle AC power status change */
+		dev_dbg(tps->dev, "AC power status change\n");
+		/* Press KEY_POWER when AC not present */
+		input_report_key(tps->pwr_but, KEY_POWER,
+				~status_reg & TPS65217_STATUS_ACPWR);
+		input_sync(tps->pwr_but);
+	}
+	if (int_reg & TPS65217_INT_USBI) {
+		/* Handle USB power status change */
+		dev_dbg(tps->dev, "USB power status change\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int tps65217_probe_pwr_but(struct tps65217 *tps)
+{
+	int ret;
+	unsigned int int_reg;
+
+	tps->pwr_but = devm_input_allocate_device(tps->dev);
+	if (!tps->pwr_but) {
+		dev_err(tps->dev,
+			"Failed to allocated pwr_but input device\n");
+		return -ENOMEM;
+	}
+
+	tps->pwr_but->evbit[0] = BIT_MASK(EV_KEY);
+	tps->pwr_but->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+	tps->pwr_but->name = "tps65217_pwr_but";
+	ret = input_register_device(tps->pwr_but);
+	if (ret) {
+		/* NOTE: devm managed device */
+		dev_err(tps->dev, "Failed to register button device\n");
+		return ret;
+	}
+	ret = devm_request_threaded_irq(tps->dev,
+		tps->irq, NULL, tps65217_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+		"tps65217", tps);
+	if (ret != 0) {
+		dev_err(tps->dev, "Failed to request IRQ %d\n", tps->irq);
+		return ret;
+	}
+
+	/* enable the power button interrupt */
+	ret = tps65217_reg_read(tps, TPS65217_REG_INT, &int_reg);
+	if (ret < 0) {
+		dev_err(tps->dev, "Failed to read INT reg\n");
+		return ret;
+	}
+	int_reg &= ~TPS65217_INT_PBM;
+	tps65217_reg_write(tps, TPS65217_REG_INT, int_reg, TPS65217_PROTECT_NONE);
+	return 0;
+}
+
 static int tps65217_probe(struct i2c_client *client,
 				const struct i2c_device_id *ids)
 {
@@ -169,10 +249,13 @@ static int tps65217_probe(struct i2c_client *client,
 	unsigned int version;
 	unsigned long chip_id = ids->driver_data;
 	const struct of_device_id *match;
+	struct device_node *node;
 	bool status_off = false;
+	int irq = -1, irq_gpio = -1;
 	int ret;
 
-	if (client->dev.of_node) {
+	node = client->dev.of_node;
+	if (node) {
 		match = of_match_device(tps65217_of_match, &client->dev);
 		if (!match) {
 			dev_err(&client->dev,
@@ -180,8 +263,31 @@ static int tps65217_probe(struct i2c_client *client,
 			return -EINVAL;
 		}
 		chip_id = (unsigned long)match->data;
-		status_off = of_property_read_bool(client->dev.of_node,
+		status_off = of_property_read_bool(node,
 					"ti,pmic-shutdown-controller");
+
+		/* at first try to get irq via OF method */
+		irq = irq_of_parse_and_map(node, 0);
+		if (irq <= 0) {
+			irq = -1;
+			irq_gpio = of_get_named_gpio(node, "irq-gpio", 0);
+			if (irq_gpio >= 0) {
+				/* valid gpio; convert to irq */
+				ret = devm_gpio_request_one(&client->dev,
+					irq_gpio, GPIOF_DIR_IN,
+					"tps65217-gpio-irq");
+				if (ret != 0)
+					dev_warn(&client->dev, "Failed to "
+						"request gpio #%d\n", irq_gpio);
+				irq = gpio_to_irq(irq_gpio);
+				if (irq <= 0) {
+					dev_warn(&client->dev, "Failed to "
+						"convert gpio #%d to irq\n",
+						irq_gpio);
+					irq = -1;
+				}
+			}
+		}
 	}
 
 	if (!chip_id) {
@@ -205,6 +311,18 @@ static int tps65217_probe(struct i2c_client *client,
 		return ret;
 	}
 
+	tps->irq = irq;
+	tps->irq_gpio = irq_gpio;
+
+	/* we got an irq, request it */
+	if (tps->irq >= 0) {
+		ret = tps65217_probe_pwr_but(tps);
+		if (ret < 0) {
+			dev_err(tps->dev, "Failed to probe pwr_but\n");
+			return ret;
+		}
+	}
+
 	ret = mfd_add_devices(tps->dev, -1, tps65217s,
 			      ARRAY_SIZE(tps65217s), NULL, 0, NULL);
 	if (ret < 0) {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index cea7320..b6f0467 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -842,6 +842,36 @@ config PANEL_BOOT_MESSAGE
 	  An empty message will only clear the display at driver init time. Any other
 	  printf()-formatted message is valid with newline and escape codes.
 
+config BONE_CAPEMGR
+	tristate "Beaglebone cape manager"
+	depends on ARCH_OMAP2PLUS && OF
+	select EEPROM
+	select OF_OVERLAY
+	help
+	  Say Y here to include support for automatic loading of
+	  beaglebone capes. Select M to build as a module which
+	  will be named bone_capemgr.
+
+config DEV_OVERLAYMGR
+	tristate "Device overlay manager"
+	depends on OF
+	select OF_OVERLAY
+	default n
+	help
+	  Say Y here to include support for the automagical dev
+	  overlay manager.
+
+config TIEQEP
+	tristate "EQEP Hardware quadrature encoder controller"
+	depends on SOC_AM33XX
+	select PWM_TIPWMSS
+	help
+	  Driver support for the EQEP quadrature encoder controller AM33XX
+	  TI SOC
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called tieqep.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
@@ -851,7 +881,9 @@ source "drivers/misc/altera-stapl/Kconfig"
 source "drivers/misc/mei/Kconfig"
 source "drivers/misc/vmw_vmci/Kconfig"
 source "drivers/misc/mic/Kconfig"
+source "drivers/misc/cape_bone_argus/Kconfig"
 source "drivers/misc/genwqe/Kconfig"
+source "drivers/misc/cape/Kconfig"
 source "drivers/misc/echo/Kconfig"
 source "drivers/misc/cxl/Kconfig"
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 22827d5..8429887 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -51,10 +51,15 @@ obj-$(CONFIG_ALTERA_STAPL)	+=altera-stapl/
 obj-$(CONFIG_INTEL_MEI)		+= mei/
 obj-$(CONFIG_VMWARE_VMCI)	+= vmw_vmci/
 obj-$(CONFIG_LATTICE_ECP3_CONFIG)	+= lattice-ecp3-config.o
+obj-$(CONFIG_TIEQEP)		+= tieqep.o
 obj-$(CONFIG_SRAM)		+= sram.o
 obj-y				+= mic/
+obj-y				+= cape_bone_argus/
 obj-$(CONFIG_GENWQE)		+= genwqe/
+obj-y				+= cape/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
 obj-$(CONFIG_PANEL)             += panel.o
+obj-$(CONFIG_BONE_CAPEMGR)	+= bone_capemgr.o
+obj-$(CONFIG_DEV_OVERLAYMGR)	+= devovmgr.o
diff --git b/drivers/misc/bone_capemgr.c b/drivers/misc/bone_capemgr.c
new file mode 100644
index 0000000..094ea75
--- /dev/null
+++ b/drivers/misc/bone_capemgr.c
@@ -0,0 +1,1884 @@
+/*
+ * TI Beaglebone cape manager
+ *
+ * Copyright (C) 2012 Texas Instruments Inc.
+ * Copyright (C) 2012-2015 Konsulko Group.
+ * Author: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+ *
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/firmware.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/memory.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/nvmem-consumer.h>
+
+/* disabled capes */
+static char *disable_partno;
+module_param(disable_partno, charp, 0444);
+MODULE_PARM_DESC(disable_partno,
+		"Comma delimited list of PART-NUMBER[:REV] of disabled capes");
+
+/* enable capes */
+static char *enable_partno;
+module_param(enable_partno, charp, 0444);
+MODULE_PARM_DESC(enable_partno,
+		"Comma delimited list of PART-NUMBER[:REV] of enabled capes");
+
+/* delay to scan on boot until rootfs appears */
+static int boot_scan_period = 1000;
+module_param(boot_scan_period, int, 0444);
+MODULE_PARM_DESC(boot_scan_period,
+		"boot scan period until rootfs firmware is available");
+
+struct capemgr_info;
+
+struct slot_ee_attribute {
+	struct device_attribute devattr;
+	unsigned int field;
+	struct bone_cape_slot *slot;	/* this is filled when instantiated */
+};
+#define to_slot_ee_attribute(x) \
+	container_of((x), struct slot_ee_attribute, devattr)
+
+struct bbrd_ee_attribute {
+	struct device_attribute devattr;
+	unsigned int field;
+};
+#define to_bbrd_ee_attribute(x) \
+	container_of((x), struct bbrd_ee_attribute, devattr)
+
+struct bone_cape_slot {
+	struct list_head	node;
+	struct capemgr_info	*info;
+	int			slotno;
+	struct nvmem_cell	*nvmem_cell;
+
+	char			text_id[256];
+	char			signature[256];
+	/* quick access */
+	char			board_name[32+1];
+	char			version[4+1];
+	char			manufacturer[16+1];
+	char			part_number[16+1];
+
+	/* attribute group */
+	char			*ee_attr_name;
+	int			ee_attrs_count;
+	struct slot_ee_attribute *ee_attrs;
+	struct attribute	**ee_attrs_tab;
+	struct attribute_group	attrgroup;
+
+	/* state flags */
+	unsigned int		probed : 1;
+	unsigned int		probe_failed : 1;
+	unsigned int		override : 1;
+	unsigned int		loading : 1;
+	unsigned int		loaded : 1;
+	unsigned int		retry_loading : 1;
+	unsigned int		disabled : 1;
+
+	char			*dtbo;
+	const struct firmware	*fw;
+	struct device_node	*overlay;
+	int			overlay_id;
+
+	/* loader thread */
+	struct task_struct	*loader_thread;
+
+	/* load priority */
+	int priority;
+};
+
+struct bone_baseboard {
+
+	/* from the matched boardmap node */
+	char			*compatible_name;
+
+	/* filled in by reading the eeprom */
+	char			signature[256];
+	char			text_id[64+1];
+
+	/* quick access */
+	char			board_name[8+1];
+	char			revision[4+1];
+	char			serial_number[12+1];
+
+	/* access to the eeprom */
+	struct nvmem_cell	*nvmem_cell;
+};
+
+struct capemgr_info {
+	struct platform_device	*pdev;
+
+	atomic_t next_slot_nr;
+	struct list_head	slot_list;
+	struct mutex		slots_list_mutex;
+
+	/* baseboard EEPROM data */
+	struct bone_baseboard	baseboard;
+
+	/* wait queue for keeping the priorities straight */
+	wait_queue_head_t	load_wq;
+};
+
+static int bone_slot_fill_override(struct bone_cape_slot *slot,
+		const char *part_number, const char *version);
+static struct bone_cape_slot *capemgr_add_slot(
+		struct capemgr_info *info, const char *slot_name,
+		const char *part_number, const char *version, int prio);
+static int capemgr_remove_slot_no_lock(struct bone_cape_slot *slot);
+static int capemgr_remove_slot(struct bone_cape_slot *slot);
+static int capemgr_load_slot(struct bone_cape_slot *slot);
+static int capemgr_unload_slot(struct bone_cape_slot *slot);
+
+/* baseboard EEPROM field definition */
+#define BBRD_EE_FIELD_HEADER		0
+#define BBRD_EE_FIELD_BOARD_NAME	1
+#define BBRD_EE_FIELD_REVISION		2
+#define BBRD_EE_FIELD_SERIAL_NUMBER	3
+#define BBRD_EE_FIELD_CONFIG_OPTION	4
+#define BBRD_EE_FILED_RSVD1		5
+#define BBRD_EE_FILED_RSVD2		6
+#define BBRD_EE_FILED_RSVD3		7
+
+/* cape EEPROM field definitions */
+#define CAPE_EE_FIELD_HEADER		0
+#define CAPE_EE_FIELD_EEPROM_REV	1
+#define CAPE_EE_FIELD_BOARD_NAME	2
+#define CAPE_EE_FIELD_VERSION		3
+#define CAPE_EE_FIELD_MANUFACTURER	4
+#define CAPE_EE_FIELD_PART_NUMBER	5
+#define CAPE_EE_FIELD_NUMBER_OF_PINS	6
+#define CAPE_EE_FIELD_SERIAL_NUMBER	7
+#define CAPE_EE_FIELD_PIN_USAGE		8
+#define CAPE_EE_FIELD_VDD_3V3EXP	9
+#define CAPE_EE_FIELD_VDD_5V		10
+#define CAPE_EE_FIELD_SYS_5V		11
+#define CAPE_EE_FIELD_DC_SUPPLIED	12
+#define CAPE_EE_FIELD_FIELDS_NR		13
+
+#define EE_FIELD_MAKE_HEADER(p)	\
+	({ \
+		const u8 *_p = (p); \
+		(((u32)_p[0] << 24) | ((u32)_p[1] << 16) | \
+		 ((u32)_p[2] <<  8) |  (u32)_p[3]); \
+	})
+
+#define EE_FIELD_HEADER_VALID	0xaa5533ee
+
+struct ee_field {
+	const char	*name;
+	int		start;
+	int		size;
+	unsigned int	ascii : 1;
+	unsigned int	strip_trailing_dots : 1;
+	const char	*override;
+};
+
+/* baseboard EEPROM definitions */
+static const struct ee_field bbrd_sig_fields[] = {
+	[BBRD_EE_FIELD_HEADER] = {
+		.name		= "header",
+		.start		= 0,
+		.size		= 4,
+		.ascii		= 0,
+		.override	= "\xaa\x55\x33\xee",	/* AA 55 33 EE */
+	},
+	[BBRD_EE_FIELD_BOARD_NAME] = {
+		.name		= "board-name",
+		.start		= 4,
+		.size		= 8,
+		.ascii		= 1,
+		.strip_trailing_dots = 1,
+		.override	= "Board Name",
+	},
+	[BBRD_EE_FIELD_REVISION] = {
+		.name		= "revision",
+		.start		= 12,
+		.size		= 4,
+		.ascii		= 1,
+		.override	= "00A0",
+	},
+	[BBRD_EE_FIELD_SERIAL_NUMBER] = {
+		.name		= "serial-number",
+		.start		= 16,
+		.size		= 12,
+		.ascii		= 1,
+		.override	= "0000000000",
+	},
+	[BBRD_EE_FIELD_CONFIG_OPTION] = {
+		.name		= "config-option",
+		.start		= 28,
+		.size		= 32,
+	},
+};
+
+/* cape EEPROM definitions */
+static const struct ee_field cape_sig_fields[] = {
+	[CAPE_EE_FIELD_HEADER] = {
+		.name		= "header",
+		.start		= 0,
+		.size		= 4,
+		.ascii		= 0,
+		.override	= "\xaa\x55\x33\xee",	/* AA 55 33 EE */
+	},
+	[CAPE_EE_FIELD_EEPROM_REV] = {
+		.name		= "eeprom-format-revision",
+		.start		= 4,
+		.size		= 2,
+		.ascii		= 1,
+		.override	= "A0",
+	},
+	[CAPE_EE_FIELD_BOARD_NAME] = {
+		.name		= "board-name",
+		.start		= 6,
+		.size		= 32,
+		.ascii		= 1,
+		.strip_trailing_dots = 1,
+		.override	= "Override Board Name",
+	},
+	[CAPE_EE_FIELD_VERSION] = {
+		.name		= "version",
+		.start		= 38,
+		.size		= 4,
+		.ascii		= 1,
+		.override	= "00A0",
+	},
+	[CAPE_EE_FIELD_MANUFACTURER] = {
+		.name		= "manufacturer",
+		.start		= 42,
+		.size		= 16,
+		.ascii		= 1,
+		.strip_trailing_dots = 1,
+		.override	= "Override Manuf",
+	},
+	[CAPE_EE_FIELD_PART_NUMBER] = {
+		.name		= "part-number",
+		.start		= 58,
+		.size		= 16,
+		.ascii		= 1,
+		.strip_trailing_dots = 1,
+		.override	= "Override Part#",
+	},
+	[CAPE_EE_FIELD_NUMBER_OF_PINS] = {
+		.name		= "number-of-pins",
+		.start		= 74,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[CAPE_EE_FIELD_SERIAL_NUMBER] = {
+		.name		= "serial-number",
+		.start		= 76,
+		.size		= 12,
+		.ascii		= 1,
+		.override	= "0000000000",
+	},
+	[CAPE_EE_FIELD_PIN_USAGE] = {
+		.name		= "pin-usage",
+		.start		= 88,
+		.size		= 140,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[CAPE_EE_FIELD_VDD_3V3EXP] = {
+		.name		= "vdd-3v3exp",
+		.start		= 228,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[CAPE_EE_FIELD_VDD_5V] = {
+		.name		= "vdd-5v",
+		.start		= 230,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[CAPE_EE_FIELD_SYS_5V] = {
+		.name		= "sys-5v",
+		.start		= 232,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+	[CAPE_EE_FIELD_DC_SUPPLIED] = {
+		.name		= "dc-supplied",
+		.start		= 234,
+		.size		= 2,
+		.ascii		= 0,
+		.override	= NULL,
+	},
+};
+
+static char *ee_field_get(const struct ee_field *sig_field,
+		const void *data, int field, char *buf, int bufsz)
+{
+	int len;
+
+	/* enough space? */
+	if (bufsz < sig_field->size + sig_field->ascii)
+		return NULL;
+
+	memcpy(buf, (char *)data + sig_field->start, sig_field->size);
+
+	/* terminate ascii field */
+	if (sig_field->ascii)
+		buf[sig_field->size] = '\0';
+
+	if (sig_field->strip_trailing_dots) {
+		len = strlen(buf);
+		while (len > 1 && buf[len - 1] == '.')
+			buf[--len] = '\0';
+	}
+
+	return buf;
+}
+
+char *bbrd_ee_field_get(const void *data,
+		int field, char *buf, int bufsz)
+{
+	if ((unsigned int)field >= ARRAY_SIZE(bbrd_sig_fields))
+		return NULL;
+
+	return ee_field_get(&bbrd_sig_fields[field], data, field, buf, bufsz);
+}
+
+char *cape_ee_field_get(const void *data,
+		int field, char *buf, int bufsz)
+{
+	if ((unsigned int)field >= ARRAY_SIZE(cape_sig_fields))
+		return NULL;
+
+	return ee_field_get(&cape_sig_fields[field], data, field, buf, bufsz);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id capemgr_of_match[] = {
+	{
+		.compatible = "ti,bone-capemgr",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, capemgr_of_match);
+
+#endif
+
+static int bone_baseboard_scan(struct bone_baseboard *bbrd)
+{
+	struct capemgr_info *info = container_of(bbrd,
+			struct capemgr_info, baseboard);
+	const u8 *p;
+	int ret;
+	size_t len;
+
+	p = nvmem_cell_read(bbrd->nvmem_cell, &len);
+	if (IS_ERR(p)) {
+		ret = PTR_ERR(p);
+		dev_err(&info->pdev->dev,
+			"Cannot read cell (ret=%d)\n", ret);
+		return ret;
+	}
+	if (len < sizeof(bbrd->signature)) {
+		dev_info(&info->pdev->dev,
+			"Short read %d (should be >= %d bytes)\n",
+			len, sizeof(bbrd->signature));
+		return -EINVAL;
+	}
+	memcpy(bbrd->signature, p, sizeof(bbrd->signature));
+
+	p = bbrd->signature;
+	if (EE_FIELD_MAKE_HEADER(p) != EE_FIELD_HEADER_VALID) {
+		dev_err(&info->pdev->dev, "Invalid board signature '%08x'\n",
+			EE_FIELD_MAKE_HEADER(p));
+		return -ENODEV;
+	}
+
+	bbrd_ee_field_get(bbrd->signature,
+			BBRD_EE_FIELD_BOARD_NAME,
+			bbrd->board_name, sizeof(bbrd->board_name));
+	bbrd_ee_field_get(bbrd->signature,
+			BBRD_EE_FIELD_REVISION,
+			bbrd->revision, sizeof(bbrd->revision));
+	bbrd_ee_field_get(bbrd->signature,
+			BBRD_EE_FIELD_SERIAL_NUMBER,
+			bbrd->serial_number, sizeof(bbrd->serial_number));
+
+	/* board_name,version,manufacturer,part_number */
+	snprintf(bbrd->text_id, sizeof(bbrd->text_id) - 1,
+			"%s,%s,%s", bbrd->board_name, bbrd->revision,
+			bbrd->serial_number);
+
+	/* terminate always */
+	bbrd->text_id[sizeof(bbrd->text_id) - 1] = '\0';
+
+	return 0;
+}
+
+static int bone_slot_scan(struct bone_cape_slot *slot)
+{
+	struct capemgr_info *info = slot->info;
+	const u8 *p;
+	int r;
+	ssize_t len;
+
+	/* need to read EEPROM? */
+	if (slot->probed)
+		goto slot_fail_check;
+
+	slot->probed = 1;
+
+	if (!slot->override) {
+
+		p = nvmem_cell_read(slot->nvmem_cell, &len);
+		if (IS_ERR(p)) {
+			r = PTR_ERR(p);
+			slot->probe_failed = 1;
+
+			/* timeout is normal when no cape is present */
+			if (r != -ETIMEDOUT)
+				dev_err(&info->pdev->dev,
+					"Cannot read cell (ret=%d)\n", r);
+			return r;
+		}
+		if (len < sizeof(slot->signature)) {
+			dev_info(&info->pdev->dev,
+				"Short read %d (should be >= %d bytes)\n",
+				len, sizeof(slot->signature));
+			return -EINVAL;
+		}
+		memcpy(slot->signature, p, sizeof(slot->signature));
+
+	} else
+		dev_info(&info->pdev->dev,
+			"Using override eeprom data at slot %d\n",
+			slot->slotno);
+
+	p = slot->signature;
+	if (EE_FIELD_MAKE_HEADER(p) != EE_FIELD_HEADER_VALID) {
+		dev_err(&info->pdev->dev,
+			"Invalid signature '%08x' at slot %d\n",
+			EE_FIELD_MAKE_HEADER(p), slot->slotno);
+		slot->probe_failed = 1;
+		return -ENODEV;
+	}
+
+	cape_ee_field_get(slot->signature,
+			CAPE_EE_FIELD_BOARD_NAME,
+			slot->board_name, sizeof(slot->board_name));
+	cape_ee_field_get(slot->signature,
+			CAPE_EE_FIELD_VERSION,
+			slot->version, sizeof(slot->version));
+	cape_ee_field_get(slot->signature,
+			CAPE_EE_FIELD_MANUFACTURER,
+			slot->manufacturer, sizeof(slot->manufacturer));
+	cape_ee_field_get(slot->signature,
+			CAPE_EE_FIELD_PART_NUMBER,
+			slot->part_number, sizeof(slot->part_number));
+
+	/* board_name,version,manufacturer,part_number */
+	snprintf(slot->text_id, sizeof(slot->text_id) - 1,
+			"%s,%s,%s,%s", slot->board_name, slot->version,
+			slot->manufacturer, slot->part_number);
+
+	/* terminate always */
+	slot->text_id[sizeof(slot->text_id) - 1] = '\0';
+
+slot_fail_check:
+	/* slot has failed and we don't support hotpluging */
+	if (slot->probe_failed)
+		return -ENODEV;
+
+	return 0;
+}
+
+/* return 0 if not matched,, 1 if matched */
+static int bone_match_cape(const char *match,
+		const char *part_number, const char *version)
+{
+	char *tmp_part_number, *tmp_version;
+	char *buf, *s, *e, *sn;
+	int found;
+
+	if (match == NULL || part_number == NULL)
+		return 0;
+
+	/* copy the argument to work on it */
+	buf = kstrdup(match, GFP_KERNEL);
+
+	/* no memory, too bad... */
+	if (buf == NULL)
+		return 0;
+
+	found = 0;
+	s = buf;
+	e = s + strlen(s);
+	while (s < e) {
+		/* find comma separator */
+		sn = strchr(s, ',');
+		if (sn != NULL)
+			*sn++ = '\0';
+		else
+			sn = e;
+		tmp_part_number = s;
+		tmp_version = strchr(tmp_part_number, ':');
+		if (tmp_version != NULL)
+			*tmp_version++ = '\0';
+		s = sn;
+
+		/* the part names must match */
+		if (strcmp(tmp_part_number, part_number) != 0)
+			continue;
+
+		/* if there's no version, match any */
+		if (version == NULL || tmp_version == NULL ||
+			strcmp(version, tmp_version) == 0) {
+			found = 1;
+			break;
+		}
+	}
+
+	kfree(buf);
+
+	return found;
+}
+
+/* helper method */
+static int of_multi_prop_cmp(const struct property *prop, const char *value)
+{
+	const char *cp;
+	int cplen, vlen, l;
+
+	/* check if it's directly compatible */
+	cp = prop->value;
+	cplen = prop->length;
+	vlen = strlen(value);
+
+	while (cplen > 0) {
+		/* compatible? */
+		if (of_compat_cmp(cp, value, vlen) == 0)
+			return 0;
+		l = strlen(cp) + 1;
+		cp += l;
+		cplen -= l;
+	}
+	return -1;
+}
+
+static ssize_t slot_ee_attr_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct slot_ee_attribute *ee_attr = to_slot_ee_attribute(attr);
+	struct bone_cape_slot *slot = ee_attr->slot;
+	const struct ee_field *sig_field;
+	int i, len;
+	char *p, *s;
+	u16 val;
+
+	/* add newline for ascii fields */
+	sig_field = &cape_sig_fields[ee_attr->field];
+
+	len = sig_field->size + sig_field->ascii;
+	p = kmalloc(len, GFP_KERNEL);
+	if (p == NULL)
+		return -ENOMEM;
+
+	s = cape_ee_field_get(slot->signature, ee_attr->field, p, len);
+	if (s == NULL)
+		return -EINVAL;
+
+	/* add newline for ascii fields and return */
+	if (sig_field->ascii) {
+		len = sprintf(buf, "%s\n", s);
+		goto out;
+	}
+
+	/* case by case handling */
+	switch (ee_attr->field) {
+	case CAPE_EE_FIELD_HEADER:
+		len = sprintf(buf, "%02x %02x %02x %02x\n",
+				s[0], s[1], s[2], s[3]);
+		break;
+
+		/* 2 bytes */
+	case CAPE_EE_FIELD_NUMBER_OF_PINS:
+	case CAPE_EE_FIELD_VDD_3V3EXP:
+	case CAPE_EE_FIELD_VDD_5V:
+	case CAPE_EE_FIELD_SYS_5V:
+	case CAPE_EE_FIELD_DC_SUPPLIED:
+		/* the bone is LE */
+		val = s[0] & (s[1] << 8);
+		len = sprintf(buf, "%u\n", (unsigned int)val & 0xffff);
+		break;
+
+	case CAPE_EE_FIELD_PIN_USAGE:
+
+		len = 0;
+		for (i = 0; i < sig_field->size / 2; i++) {
+			/* the bone is LE */
+			val = s[0] & (s[1] << 8);
+			sprintf(buf, "%04x\n", val);
+			buf += 5;
+			len += 5;
+			s += 2;
+		}
+
+		break;
+
+	default:
+		*buf = '\0';
+		len = 0;
+		break;
+	}
+
+out:
+	kfree(p);
+
+	return len;
+}
+
+#define SLOT_EE_ATTR(_name, _field) \
+	{ \
+		.devattr = __ATTR(_name, S_IRUGO, slot_ee_attr_show, NULL), \
+		.field = CAPE_EE_FIELD_##_field, \
+		.slot = NULL, \
+	}
+
+static const struct slot_ee_attribute slot_ee_attrs[] = {
+	SLOT_EE_ATTR(header, HEADER),
+	SLOT_EE_ATTR(eeprom-format-revision, EEPROM_REV),
+	SLOT_EE_ATTR(board-name, BOARD_NAME),
+	SLOT_EE_ATTR(version, VERSION),
+	SLOT_EE_ATTR(manufacturer, MANUFACTURER),
+	SLOT_EE_ATTR(part-number, PART_NUMBER),
+	SLOT_EE_ATTR(number-of-pins, NUMBER_OF_PINS),
+	SLOT_EE_ATTR(serial-number, SERIAL_NUMBER),
+	SLOT_EE_ATTR(pin-usage, PIN_USAGE),
+	SLOT_EE_ATTR(vdd-3v3exp, VDD_3V3EXP),
+	SLOT_EE_ATTR(vdd-5v, VDD_5V),
+	SLOT_EE_ATTR(sys-5v, SYS_5V),
+	SLOT_EE_ATTR(dc-supplied, DC_SUPPLIED),
+};
+
+static int bone_cape_slot_sysfs_register(struct bone_cape_slot *slot)
+{
+	struct capemgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	struct slot_ee_attribute *ee_attr;
+	struct attribute_group *attrgroup;
+	int i, err, sz;
+
+	slot->ee_attr_name = kasprintf(GFP_KERNEL, "slot-%d", slot->slotno);
+	if (slot->ee_attr_name == NULL) {
+		dev_err(dev, "slot #%d: Failed to allocate ee_attr_name\n",
+				slot->slotno);
+		err = -ENOMEM;
+		goto err_fail_no_ee_attr_name;
+	}
+
+	slot->ee_attrs_count = ARRAY_SIZE(slot_ee_attrs);
+
+	sz = slot->ee_attrs_count * sizeof(*slot->ee_attrs);
+	slot->ee_attrs = kmalloc(sz, GFP_KERNEL);
+	if (slot->ee_attrs == NULL) {
+		dev_err(dev, "slot #%d: Failed to allocate ee_attrs\n",
+				slot->slotno);
+		err = -ENOMEM;
+		goto err_fail_no_ee_attrs;
+	}
+
+	attrgroup = &slot->attrgroup;
+	memset(attrgroup, 0, sizeof(*attrgroup));
+	attrgroup->name = slot->ee_attr_name;
+
+	sz = sizeof(*slot->ee_attrs_tab) * (slot->ee_attrs_count + 1);
+	attrgroup->attrs = kmalloc(sz, GFP_KERNEL);
+	if (attrgroup->attrs == NULL) {
+		dev_err(dev, "slot #%d: Failed to allocate ee_attrs_tab\n",
+				slot->slotno);
+		err = -ENOMEM;
+		goto err_fail_no_ee_attrs_tab;
+	}
+	/* copy everything over */
+	memcpy(slot->ee_attrs, slot_ee_attrs, sizeof(slot_ee_attrs));
+
+	/* bind this attr to the slot */
+	for (i = 0; i < slot->ee_attrs_count; i++) {
+		ee_attr = &slot->ee_attrs[i];
+		ee_attr->slot = slot;
+		attrgroup->attrs[i] = &ee_attr->devattr.attr;
+	}
+	attrgroup->attrs[i] = NULL;
+
+	/* make lockdep happy */
+	for (i = 0; i < slot->ee_attrs_count; i++) {
+		ee_attr = &slot->ee_attrs[i];
+		sysfs_attr_init(&ee_attr->devattr.attr);
+	}
+
+	err = sysfs_create_group(&dev->kobj, attrgroup);
+	if (err != 0) {
+		dev_err(dev, "slot #%d: Failed to allocate ee_attrs_tab\n",
+				slot->slotno);
+		err = -ENOMEM;
+		goto err_fail_no_ee_attrs_group;
+	}
+
+	return 0;
+
+err_fail_no_ee_attrs_group:
+	kfree(slot->ee_attrs_tab);
+err_fail_no_ee_attrs_tab:
+	kfree(slot->ee_attrs);
+err_fail_no_ee_attrs:
+	kfree(slot->ee_attr_name);
+err_fail_no_ee_attr_name:
+	return err;
+}
+
+static void bone_cape_slot_sysfs_unregister(struct bone_cape_slot *slot)
+{
+	struct capemgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+
+	sysfs_remove_group(&dev->kobj, &slot->attrgroup);
+	kfree(slot->ee_attrs_tab);
+	kfree(slot->ee_attrs);
+	kfree(slot->ee_attr_name);
+}
+
+static ssize_t bbrd_ee_attr_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct bbrd_ee_attribute *ee_attr = to_bbrd_ee_attribute(attr);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct capemgr_info *info = platform_get_drvdata(pdev);
+	struct bone_baseboard *bbrd = &info->baseboard;
+	const struct ee_field *sig_field;
+	u16 val;
+	int i, len;
+	char *p, *s;
+
+	/* add newline for ascii fields */
+	sig_field = &bbrd_sig_fields[ee_attr->field];
+
+	len = sig_field->size + sig_field->ascii;
+	p = kmalloc(len, GFP_KERNEL);
+	if (p == NULL)
+		return -ENOMEM;
+
+	s = bbrd_ee_field_get(bbrd->signature, ee_attr->field, p, len);
+	if (s == NULL)
+		return -EINVAL;
+
+	/* add newline for ascii fields and return */
+	if (sig_field->ascii) {
+		len = sprintf(buf, "%s\n", s);
+		goto out;
+	}
+
+	/* case by case handling */
+	switch (ee_attr->field) {
+	case BBRD_EE_FIELD_HEADER:
+		len = sprintf(buf, "%02x %02x %02x %02x\n",
+				s[0], s[1], s[2], s[3]);
+		break;
+
+	case BBRD_EE_FIELD_CONFIG_OPTION:
+		len = 0;
+		for (i = 0; i < sig_field->size / 2; i++) {
+			/* the bone is LE */
+			val = s[0] & (s[1] << 8);
+			sprintf(buf, "%04x\n", val);
+			buf += 5;
+			len += 5;
+			s += 2;
+		}
+		break;
+
+	default:
+		*buf = '\0';
+		len = 0;
+		break;
+	}
+
+out:
+	kfree(p);
+
+	return len;
+}
+
+#define BBRD_EE_ATTR(_name, _field) \
+	{ \
+		.devattr = __ATTR(_name, 0440, bbrd_ee_attr_show, NULL), \
+		.field = BBRD_EE_FIELD_##_field, \
+	}
+
+static struct bbrd_ee_attribute bbrd_ee_attrs[] = {
+	BBRD_EE_ATTR(header, HEADER),
+	BBRD_EE_ATTR(board-name, BOARD_NAME),
+	BBRD_EE_ATTR(revision, REVISION),
+	BBRD_EE_ATTR(serial-number, SERIAL_NUMBER),
+	BBRD_EE_ATTR(config-option, CONFIG_OPTION),
+};
+
+static struct attribute *bbrd_attrs_flat[] = {
+	&bbrd_ee_attrs[BBRD_EE_FIELD_HEADER].devattr.attr,
+	&bbrd_ee_attrs[BBRD_EE_FIELD_BOARD_NAME].devattr.attr,
+	&bbrd_ee_attrs[BBRD_EE_FIELD_REVISION].devattr.attr,
+	&bbrd_ee_attrs[BBRD_EE_FIELD_SERIAL_NUMBER].devattr.attr,
+	&bbrd_ee_attrs[BBRD_EE_FIELD_CONFIG_OPTION].devattr.attr,
+	NULL,
+};
+
+static const struct attribute_group bbrd_attr_group = {
+	.name	= "baseboard",
+	.attrs	= bbrd_attrs_flat,
+};
+
+static ssize_t slots_show(struct device *dev, struct device_attribute *attr,
+		char *buf);
+static ssize_t slots_store(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count);
+
+static DEVICE_ATTR(slots, 0644, slots_show, slots_store);
+
+static struct attribute *root_attrs_flat[] = {
+	&dev_attr_slots.attr,
+	NULL,
+};
+
+static const struct attribute_group root_attr_group = {
+	.attrs = root_attrs_flat,
+};
+
+static const struct attribute_group *attr_groups[] = {
+	&root_attr_group,
+	&bbrd_attr_group,
+	NULL,
+};
+
+static ssize_t slots_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct capemgr_info *info = platform_get_drvdata(pdev);
+	struct bone_cape_slot *slot;
+	ssize_t len, sz;
+
+	mutex_lock(&info->slots_list_mutex);
+	sz = 0;
+	list_for_each_entry(slot, &info->slot_list, node) {
+
+		len = sprintf(buf, "%2d: %c%c%c%c%c%c %3d %s\n",
+				slot->slotno,
+				slot->probed       ? 'P' : '-',
+				slot->probe_failed ? 'F' : '-',
+				slot->override     ? 'O' : '-',
+				slot->loading	   ? 'l' : '-',
+				slot->loaded	   ? 'L' : '-',
+				slot->disabled     ? 'D' : '-',
+				slot->overlay_id, slot->text_id);
+
+		buf += len;
+		sz += len;
+	}
+	mutex_unlock(&info->slots_list_mutex);
+
+	return sz;
+}
+
+static ssize_t slots_store(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct capemgr_info *info = platform_get_drvdata(pdev);
+	struct bone_cape_slot *slot;
+	struct device_node *pnode, *node;
+	char *s, *part_number, *version;
+	int ret;
+	int slotno;
+
+	/* check for remove slot */
+	if (strlen(buf) > 0 && buf[0] == '-') {
+		ret = kstrtoint(buf + 1, 10, &slotno);
+		if (ret != 0)
+			return ret;
+
+		/* now load each (take lock to be sure */
+		mutex_lock(&info->slots_list_mutex);
+		list_for_each_entry(slot, &info->slot_list, node) {
+			if (slotno == slot->slotno)
+				goto found;
+		}
+
+		mutex_unlock(&info->slots_list_mutex);
+		return -ENODEV;
+found:
+		/* the hardware slots just get unloaded */
+		if (!slot->override) {
+			ret = capemgr_unload_slot(slot);
+			if (ret == 0)
+				dev_info(&pdev->dev,
+					"Unloaded slot #%d\n", slotno);
+			else
+				dev_err(&pdev->dev,
+					"Failed to unload slot #%d\n", slotno);
+		} else {
+			ret = capemgr_remove_slot_no_lock(slot);
+			if (ret == 0)
+				dev_info(&pdev->dev,
+					"Removed slot #%d\n", slotno);
+			else
+				dev_err(&pdev->dev,
+					"Failed to remove slot #%d\n", slotno);
+		}
+		mutex_unlock(&info->slots_list_mutex);
+
+		return ret == 0 ? strlen(buf) : ret;
+	}
+
+	part_number = kstrdup(buf, GFP_KERNEL);
+	if (part_number == NULL)
+		return -ENOMEM;
+
+	/* remove trailing spaces dots and newlines */
+	s = part_number + strlen(part_number);
+	while (s > part_number &&
+			(isspace(s[-1]) || s[-1] == '\n' || s[-1] == '.'))
+		*--s = '\0';
+
+	version = strchr(part_number, ':');
+	if (version != NULL)
+		*version++ = '\0';
+
+	dev_info(&pdev->dev, "part_number '%s', version '%s'\n",
+			part_number, version ? version : "N/A");
+
+	pnode = pdev->dev.of_node;
+	node = NULL;
+	slot = NULL;
+	ret = 0;
+
+	/* no specific slot found, try immediate */
+	slot = capemgr_add_slot(info, NULL, part_number, version, 0);
+
+	if (IS_ERR_OR_NULL(slot)) {
+		dev_err(&pdev->dev, "Failed to add slot #%d\n",
+			atomic_read(&info->next_slot_nr) - 1);
+		ret = slot ? PTR_ERR(slot) : -ENODEV;
+		slot = NULL;
+		goto err_fail;
+	}
+
+	kfree(part_number);
+
+	ret = capemgr_load_slot(slot);
+	if (ret != 0)
+		capemgr_remove_slot(slot);
+
+	return ret == 0 ? strlen(buf) : ret;
+err_fail:
+	of_node_put(node);
+	kfree(part_number);
+	return ret;
+}
+
+/* verify the overlay */
+static int capemgr_verify_overlay(struct bone_cape_slot *slot)
+{
+	struct capemgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	struct bone_baseboard *bbrd = &info->baseboard;
+	struct device_node *node = slot->overlay;
+	struct property *prop;
+	struct bone_cape_slot *slotn;
+	int err, counta, countb, i, j;
+	const char *ra, *rb;
+
+	/* validate */
+	if (node == NULL) {
+		dev_err(dev, "slot #%d: No overlay for '%s'\n",
+				slot->slotno, slot->part_number);
+		return -EINVAL;
+	}
+
+	/* check if the slot is compatible with the board */
+	prop = of_find_property(node, "compatible", NULL);
+
+	/* no compatible property? */
+	if (prop == NULL) {
+		dev_err(dev, "slot #%d: No compatible property for '%s'\n",
+				slot->slotno, slot->part_number);
+		return -EINVAL;
+	}
+
+	/* verify that the cape is baseboard compatible */
+	if (of_multi_prop_cmp(prop, bbrd->compatible_name) != 0) {
+		dev_err(dev, "slot #%d: Incompatible with baseboard for '%s'\n",
+				slot->slotno, slot->part_number);
+		return -EINVAL;
+	}
+
+	/* count the strings */
+	counta = of_property_count_strings(node, "exclusive-use");
+	/* no valid property, or no resources; no matter, it's OK */
+	if (counta <= 0)
+		return 0;
+
+	/* and now check if there's a resource conflict */
+	err = 0;
+	mutex_lock(&info->slots_list_mutex);
+	for (i = 0; i < counta; i++) {
+
+		ra = NULL;
+		err = of_property_read_string_index(node, "exclusive-use",
+				i, &ra);
+		if (err != 0) {
+			dev_err(dev, "slot #%d: Could not read string #%d\n",
+					slot->slotno, i);
+			break;
+		}
+
+		list_for_each_entry(slotn, &info->slot_list, node) {
+
+			/* don't check against self */
+			if (slot == slotn)
+				continue;
+
+			/* only check against loaded or loading slots */
+			if (!slotn->loaded && !slotn->loading)
+				continue;
+
+			countb = of_property_count_strings(slotn->overlay,
+					"exclusive-use");
+			/* no valid property, or resources; it's OK */
+			if (countb <= 0)
+				continue;
+
+
+			for (j = 0; j < countb; j++) {
+
+				/* count the resources */
+				rb = NULL;
+				err = of_property_read_string_index(
+					slotn->overlay, "exclusive-use",
+						j, &rb);
+				if (err != 0) {
+					/* error, but we don't care */
+					err = 0;
+					break;
+				}
+
+				/* ignore case; just in case ;) */
+				if (strcasecmp(ra, rb) == 0) {
+
+					/* resource conflict */
+					err = -EEXIST;
+					dev_err(dev,
+						"slot #%d: %s conflict %s (#%d:%s)\n",
+						slot->slotno,
+						slot->part_number, ra,
+						slotn->slotno,
+						slotn->part_number);
+					goto out;
+				}
+			}
+		}
+	}
+out:
+	mutex_unlock(&info->slots_list_mutex);
+
+	return err;
+}
+
+static int capemgr_load_slot(struct bone_cape_slot *slot)
+{
+	struct capemgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	const char *dtbo;
+	int err;
+
+	if (slot->probe_failed) {
+		dev_err(dev, "slot #%d: probe failed for '%s'\n",
+			slot->slotno, slot->part_number);
+		return -ENODEV;
+	}
+
+	if (slot->loaded) {
+		dev_err(dev, "slot #%d: already loaded for '%s'\n",
+			slot->slotno, slot->part_number);
+		return -EAGAIN;
+	}
+
+	/* make sure we don't leak this on repeated calls */
+	kfree(slot->dtbo);
+	slot->dtbo = NULL;
+
+	dev_dbg(dev, "slot #%d: Requesting part number/version based '%s-%s.dtbo\n",
+			slot->slotno, slot->part_number, slot->version);
+
+	/* request the part number + .dtbo*/
+	slot->dtbo = kasprintf(GFP_KERNEL, "%s-%s.dtbo",
+			slot->part_number, slot->version);
+	if (slot->dtbo == NULL) {
+		dev_err(dev, "slot #%d: Failed to get dtbo '%s'\n",
+				slot->slotno, dtbo);
+		return -ENOMEM;
+	}
+
+	dev_dbg(dev, "slot #%d: Requesting firmware '%s' for board-name '%s', version '%s'%s\n",
+			slot->slotno,
+			slot->dtbo, slot->board_name, slot->version,
+			system_state == SYSTEM_BOOTING ? " - booting" : "");
+
+	err = request_firmware_direct(&slot->fw, slot->dtbo, dev);
+	if (err != 0) {
+		dev_dbg(dev, "failed to load firmware '%s'\n", slot->dtbo);
+		goto err_fail_no_fw;
+	}
+
+	dev_dbg(dev, "slot #%d: dtbo '%s' loaded; converting to live tree\n",
+			slot->slotno, slot->dtbo);
+
+	of_fdt_unflatten_tree((unsigned long *)slot->fw->data, &slot->overlay);
+	if (slot->overlay == NULL) {
+		dev_err(dev, "slot #%d: Failed to unflatten\n",
+				slot->slotno);
+		err = -EINVAL;
+		goto err_fail;
+	}
+
+	/* mark it as detached */
+	of_node_set_flag(slot->overlay, OF_DETACHED);
+
+	/* perform resolution */
+	err = of_resolve_phandles(slot->overlay);
+	if (err != 0) {
+		dev_err(dev, "slot #%d: Failed to resolve tree\n",
+				slot->slotno);
+		goto err_fail;
+	}
+
+	err = capemgr_verify_overlay(slot);
+	if (err != 0) {
+		dev_err(dev, "slot #%d: Failed verification\n",
+				slot->slotno);
+		goto err_fail;
+	}
+
+	err = of_overlay_create(slot->overlay);
+	if (err < 0) {
+		dev_err(dev, "slot #%d: Failed to create overlay\n",
+				slot->slotno);
+		goto err_fail;
+	}
+	slot->overlay_id = err;
+
+	slot->loading = 0;
+	slot->loaded = 1;
+
+	dev_info(dev, "slot #%d: dtbo '%s' loaded; overlay id #%d\n",
+			slot->slotno, slot->dtbo, slot->overlay_id);
+
+	return 0;
+
+err_fail:
+
+	/* TODO: free the overlay, we can't right now cause
+	 * the unflatten method does not track it */
+	slot->overlay = NULL;
+
+	release_firmware(slot->fw);
+	slot->fw = NULL;
+
+err_fail_no_fw:
+	slot->loading = 0;
+	return err;
+}
+
+static int capemgr_unload_slot(struct bone_cape_slot *slot)
+{
+	if (!slot->loaded || slot->overlay_id == -1)
+		return -EINVAL;
+
+	of_overlay_destroy(slot->overlay_id);
+	slot->overlay_id = -1;
+
+	slot->loaded = 0;
+
+	return 0;
+
+}
+
+/* slots_list_mutex must be taken */
+static int capemgr_remove_slot_no_lock(struct bone_cape_slot *slot)
+{
+	struct capemgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	int ret;
+
+	if (slot == NULL)
+		return 0;
+
+	if (slot->loaded && slot->overlay_id >= 0) {
+		/* unload just in case */
+		ret = capemgr_unload_slot(slot);
+		if (ret != 0) {
+			dev_err(dev, "Unable to unload slot #%d\n",
+				slot->slotno);
+			return ret;
+		}
+	}
+
+	/* if probed OK, remove the sysfs nodes */
+	if (slot->probed && !slot->probe_failed)
+		bone_cape_slot_sysfs_unregister(slot);
+
+	/* remove it from the list */
+	list_del(&slot->node);
+
+	if (slot->nvmem_cell)
+		nvmem_cell_put(slot->nvmem_cell);
+	devm_kfree(dev, slot);
+	return 0;
+}
+
+static int capemgr_remove_slot(struct bone_cape_slot *slot)
+{
+	struct capemgr_info *info = slot->info;
+	int ret;
+
+	mutex_lock(&info->slots_list_mutex);
+	ret = capemgr_remove_slot_no_lock(slot);
+	mutex_unlock(&info->slots_list_mutex);
+
+	return ret;
+}
+
+static int bone_slot_fill_override(struct bone_cape_slot *slot,
+		const char *part_number, const char *version)
+{
+	const struct ee_field *sig_field;
+	int i, len, has_part_number;
+	char *p;
+
+	slot->probe_failed = 0;
+	slot->probed = 0;
+
+	/* zero out signature */
+	memset(slot->signature, 0,
+			sizeof(slot->signature));
+
+	/* first, fill in all with override defaults */
+	for (i = 0; i < ARRAY_SIZE(cape_sig_fields); i++) {
+
+		sig_field = &cape_sig_fields[i];
+
+		/* point to the entry */
+		p = slot->signature + sig_field->start;
+
+		if (sig_field->override)
+			memcpy(p, sig_field->override,
+					sig_field->size);
+		else
+			memset(p, 0, sig_field->size);
+	}
+
+	/* if a part_number is supplied use it */
+	len = part_number ? strlen(part_number) : 0;
+	if (len > 0) {
+		sig_field = &cape_sig_fields[CAPE_EE_FIELD_PART_NUMBER];
+
+		/* point to the entry */
+		p = slot->signature + sig_field->start;
+
+		/* copy and zero out any remainder */
+		if (len > sig_field->size)
+			len = sig_field->size;
+		memcpy(p, part_number, len);
+		if (len < sig_field->size)
+			memset(p + len, 0, sig_field->size - len);
+
+		has_part_number = 1;
+	}
+
+	/* if a version is supplied use it */
+	len = version ? strlen(version) : 0;
+	if (len > 0) {
+		sig_field = &cape_sig_fields[CAPE_EE_FIELD_VERSION];
+
+		/* point to the entry */
+		p = slot->signature + sig_field->start;
+
+		/* copy and zero out any remainder */
+		if (len > sig_field->size)
+			len = sig_field->size;
+		memcpy(p, version, len);
+		if (len < sig_field->size)
+			memset(p + len, 0, sig_field->size - len);
+	}
+
+	/* we must have a part number */
+	if (!has_part_number)
+		return -EINVAL;
+
+	slot->override = 1;
+
+	return 0;
+}
+
+static struct bone_cape_slot *
+capemgr_add_slot(struct capemgr_info *info, const char *slot_name,
+		const char *part_number, const char *version, int prio)
+{
+	struct bone_cape_slot *slot;
+	struct device *dev = &info->pdev->dev;
+	int slotno;
+	int ret;
+
+	slotno = atomic_inc_return(&info->next_slot_nr) - 1;
+
+	slot = devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL);
+	if (slot == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	slot->info = info;
+	slot->slotno = slotno;
+	slot->priority = prio;
+	slot->overlay_id = -1;
+
+	if (slot_name) {
+		slot->nvmem_cell = nvmem_cell_get(dev, slot_name);
+		if (IS_ERR(slot->nvmem_cell)) {
+			ret = PTR_ERR(slot->nvmem_cell);
+			if (ret != -EPROBE_DEFER)
+				dev_err(dev, "Failed to get slot eeprom cell\n");
+			slot->nvmem_cell = NULL;
+			goto err_out;
+		}
+	} else {
+		dev_info(dev, "slot #%d: override\n", slotno);
+
+		/* fill in everything with defaults first */
+		ret = bone_slot_fill_override(slot, part_number, version);
+		if (ret != 0) {
+			dev_err(dev, "slot #%d: override failed\n", slotno);
+			goto err_out;
+		}
+	}
+
+	ret = bone_slot_scan(slot);
+	if (ret != 0) {
+
+		if (!slot->probe_failed) {
+			dev_err(dev, "slot #%d: scan failed\n",
+					slotno);
+			goto err_out;
+		}
+
+		dev_err(dev, "slot #%d: No cape found\n", slotno);
+		/* but all is fine */
+	} else {
+
+		dev_info(dev, "slot #%d: '%s'\n",
+				slotno, slot->text_id);
+
+		ret = bone_cape_slot_sysfs_register(slot);
+		if (ret != 0) {
+			dev_err(dev, "slot #%d: sysfs register failed\n",
+					slotno);
+			goto err_out;
+		}
+
+	}
+
+	/* add to the slot list */
+	mutex_lock(&info->slots_list_mutex);
+	list_add_tail(&slot->node, &info->slot_list);
+	mutex_unlock(&info->slots_list_mutex);
+
+	return slot;
+
+err_out:
+	if (slot->nvmem_cell)
+		nvmem_cell_put(slot->nvmem_cell);
+	devm_kfree(dev, slot);
+	return ERR_PTR(ret);
+}
+
+/* return 1 if it makes sense to retry loading */
+static int retry_loading_condition(struct bone_cape_slot *slot)
+{
+	struct capemgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	struct bone_cape_slot *slotn;
+	int ret;
+
+	dev_dbg(dev, "loader: retry_loading slot-%d %s:%s (prio %d)\n",
+			slot->slotno, slot->part_number, slot->version,
+			slot->priority);
+
+	mutex_lock(&info->slots_list_mutex);
+	ret = 0;
+	list_for_each_entry(slotn, &info->slot_list, node) {
+		/* if same slot or not loading skip */
+		if (!slotn->loading || slotn->retry_loading)
+			continue;
+		/* at least one cape is still loading (without retrying) */
+		ret = 1;
+	}
+	mutex_unlock(&info->slots_list_mutex);
+	return ret;
+}
+
+/* return 1 if this slot is clear to try to load now */
+static int clear_to_load_condition(struct bone_cape_slot *slot)
+{
+	struct capemgr_info *info = slot->info;
+	int my_prio = slot->priority;
+	struct device *dev = &info->pdev->dev;
+	int ret;
+
+	dev_dbg(dev, "loader: check slot-%d %s:%s (prio %d)\n", slot->slotno,
+			slot->part_number, slot->version, slot->priority);
+
+	mutex_lock(&info->slots_list_mutex);
+	ret = 1;
+	list_for_each_entry(slot, &info->slot_list, node) {
+		/* if any slot is loading with lowest priority */
+		if (!slot->loading)
+			continue;
+		if (slot->priority < my_prio) {
+			ret = 0;
+			break;
+		}
+	}
+	mutex_unlock(&info->slots_list_mutex);
+	return ret;
+}
+
+static int capemgr_loader(void *data)
+{
+	struct bone_cape_slot *slot = data;
+	struct capemgr_info *info = slot->info;
+	struct device *dev = &info->pdev->dev;
+	int ret, done, other_loading, booting;
+
+	done = 0;
+
+	slot->retry_loading = 0;
+
+	dev_dbg(dev, "loader: before slot-%d %s:%s (prio %d)\n", slot->slotno,
+			slot->part_number, slot->version, slot->priority);
+
+	/*
+	 * We have a basic priority based arbitration system
+	 * Slots have priorities, so the lower priority ones
+	 * should start loading first. So each time we end up
+	 * here.
+	 */
+	ret = wait_event_interruptible(info->load_wq,
+			clear_to_load_condition(slot));
+	if (ret < 0) {
+		dev_warn(dev, "loader, Signal pending\n");
+		return ret;
+	}
+
+	dev_dbg(dev, "loader: after slot-%d %s:%s (prio %d)\n", slot->slotno,
+			slot->part_number, slot->version, slot->priority);
+
+	/* using the return value */
+	ret = capemgr_load_slot(slot);
+
+	/* wake up all just in case */
+	wake_up_interruptible_all(&info->load_wq);
+
+	if (ret == 0)
+		goto done;
+
+	dev_dbg(dev, "loader: retrying slot-%d %s:%s (prio %d)\n", slot->slotno,
+			slot->part_number, slot->version, slot->priority);
+
+	/* first attempt has failed; now try each time there's any change */
+	slot->retry_loading = 1;
+
+	for (;;) {
+		booting = (system_state == SYSTEM_BOOTING);
+		other_loading = retry_loading_condition(slot);
+		if (!booting && !other_loading)
+			break;
+
+		/* simple wait for someone to kick us */
+		if (other_loading) {
+			DEFINE_WAIT(__wait);
+
+			prepare_to_wait(&info->load_wq, &__wait,
+					TASK_INTERRUPTIBLE);
+			finish_wait(&info->load_wq, &__wait);
+		} else {
+			/* always delay when booting */
+			msleep(boot_scan_period);
+		}
+
+		if (signal_pending(current)) {
+			dev_warn(dev, "loader, Signal pending\n");
+			ret = -ERESTARTSYS;
+			goto done;
+		}
+
+		/* using the return value */
+		ret = capemgr_load_slot(slot);
+		if (ret == 0)
+			goto done;
+
+		/* wake up all just in case */
+		wake_up_interruptible_all(&info->load_wq);
+	}
+
+done:
+	slot->loading = 0;
+	slot->retry_loading = 0;
+
+	if (ret == 0) {
+		dev_dbg(dev, "loader: done slot-%d %s:%s (prio %d)\n",
+			slot->slotno, slot->part_number, slot->version,
+			slot->priority);
+	} else {
+		dev_err(dev, "loader: failed to load slot-%d %s:%s (prio %d)\n",
+			slot->slotno, slot->part_number, slot->version,
+			slot->priority);
+
+		/* if it's a override slot remove it */
+		if (slot->override)
+			capemgr_remove_slot(slot);
+	}
+
+	return ret;
+}
+
+static int
+capemgr_probe(struct platform_device *pdev)
+{
+	struct capemgr_info *info;
+	struct bone_baseboard *bbrd;
+	struct bone_cape_slot *slot;
+	struct device_node *pnode = pdev->dev.of_node;
+	struct device_node *baseboardmaps_node;
+	struct device_node *node;
+	const char *part_number;
+	const char *version;
+	const char *board_name;
+	const char *compatible_name;
+	char slot_name[16];
+	u32 slots_nr;
+	int i, ret, len, prio;
+	long val;
+	char *wbuf, *s, *p, *e;
+
+	/* we don't use platform_data at all; we require OF */
+	if (pnode == NULL)
+		return -ENOTSUPP;
+
+	info = devm_kzalloc(&pdev->dev,
+			sizeof(struct capemgr_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->pdev = pdev;
+	platform_set_drvdata(pdev, info);
+
+	atomic_set(&info->next_slot_nr, 0);
+	INIT_LIST_HEAD(&info->slot_list);
+	mutex_init(&info->slots_list_mutex);
+
+	init_waitqueue_head(&info->load_wq);
+
+	baseboardmaps_node = NULL;
+
+	/* find the baseboard */
+	bbrd = &info->baseboard;
+
+	baseboardmaps_node = of_get_child_by_name(pnode, "baseboardmaps");
+	if (baseboardmaps_node == NULL) {
+		dev_err(&pdev->dev, "Failed to get baseboardmaps node");
+		ret = -ENODEV;
+		goto err_exit;
+	}
+
+	bbrd->nvmem_cell = nvmem_cell_get(&pdev->dev, "baseboard");
+	if (IS_ERR(bbrd->nvmem_cell)) {
+		ret = PTR_ERR(bbrd->nvmem_cell);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Failed to get baseboard eeprom cell\n");
+		bbrd->nvmem_cell = NULL;
+		goto err_exit;
+	}
+
+	ret = bone_baseboard_scan(bbrd);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to scan baseboard eeprom\n");
+		goto err_exit;
+	}
+
+	dev_info(&pdev->dev, "Baseboard: '%s'\n", bbrd->text_id);
+
+	board_name = NULL;
+	compatible_name = NULL;
+	for_each_child_of_node(baseboardmaps_node, node) {
+		/* there must be board-name */
+		if (of_property_read_string(node, "board-name",
+					&board_name) != 0 ||
+		    of_property_read_string(node, "compatible-name",
+					&compatible_name) != 0)
+			continue;
+
+		if (strcmp(bbrd->board_name, board_name) == 0)
+			break;
+	}
+	of_node_put(baseboardmaps_node);
+	baseboardmaps_node = NULL;
+
+	if (node == NULL) {
+		dev_err(&pdev->dev, "Failed to find compatible map for %s\n",
+				bbrd->board_name);
+		ret = -ENODEV;
+		goto err_exit;
+	}
+	bbrd->compatible_name = kstrdup(compatible_name, GFP_KERNEL);
+	if (bbrd->compatible_name == NULL) {
+		ret = -ENOMEM;
+		goto err_exit;
+	}
+	of_node_put(node);
+
+	/* get slot number */
+	ret = of_property_read_u32(pnode, "#slots", &slots_nr);
+	if (ret != 0)
+		slots_nr = 0;
+
+	dev_info(&pdev->dev, "compatible-baseboard=%s - #slots=%d\n",
+			bbrd->compatible_name, slots_nr);
+
+	for (i = 0; i < slots_nr; i++) {
+		snprintf(slot_name, sizeof(slot_name), "slot%d", i);
+		slot = capemgr_add_slot(info, slot_name, NULL, NULL, 0);
+		if (IS_ERR(slot)) {
+			dev_err(&pdev->dev, "Failed to add slot #%d\n",
+				atomic_read(&info->next_slot_nr));
+			ret = PTR_ERR(slot);
+			goto err_exit;
+		}
+	}
+
+	/* iterate over enable_partno (if there) */
+	if (enable_partno && strlen(enable_partno) > 0) {
+
+		/* allocate a temporary buffer */
+		wbuf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
+		if (wbuf == NULL) {
+			ret = -ENOMEM;
+			goto err_exit;
+		}
+
+		/* add any enable_partno capes */
+		s = enable_partno;
+		while (*s) {
+			/* form is PART[:REV[:PRIO]],PART.. */
+			p = strchr(s, ',');
+			if (p == NULL)
+				e = s + strlen(s);
+			else
+				e = p;
+
+			/* copy to temp buffer */
+			len = e - s;
+			if (len >= PAGE_SIZE - 1)
+				len = PAGE_SIZE - 1;
+			memcpy(wbuf, s, len);
+			wbuf[len] = '\0';
+
+			/* move to the next */
+			s = *e ? e + 1 : e;
+
+			part_number = wbuf;
+
+			/* default version is NULL & prio is 0 */
+			version = NULL;
+			prio = 0;
+
+			/* now split the rev & prio part */
+			p = strchr(wbuf, ':');
+			if (p != NULL) {
+				*p++ = '\0';
+				if (*p != ':')
+					version = p;
+				p = strchr(p, ':');
+				if (p != NULL) {
+					*p++ = '\0';
+					ret = kstrtol(p, 10, &val);
+					if (ret == 0)
+						prio = val;
+				}
+			}
+
+			dev_info(&pdev->dev,
+				"enabled_partno PARTNO '%s' VER '%s' PR '%d'\n",
+					part_number,
+					version ? version : "N/A", prio);
+
+			/* only immediate slots are allowed here */
+			slot = capemgr_add_slot(info, NULL,
+					part_number, version, prio);
+
+			/* we continue even in case of an error */
+			if (IS_ERR_OR_NULL(slot)) {
+				dev_warn(&pdev->dev, "Failed to add slot #%d\n",
+					atomic_read(&info->next_slot_nr) - 1);
+			}
+		}
+
+		devm_kfree(&pdev->dev, wbuf);
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (IS_ERR_VALUE(ret)) {
+		dev_err(&pdev->dev, "Failed to pm_runtime_get_sync()\n");
+		goto err_exit;
+	}
+
+	pm_runtime_put(&pdev->dev);
+
+	/* it is safe to create the attribute groups */
+	ret = sysfs_create_groups(&pdev->dev.kobj, attr_groups);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to create sysfs attributes\n");
+		goto err_exit;
+	}
+	/* automatically cleared by driver core now */
+	pdev->dev.groups = attr_groups;
+
+	/* now load each (take lock to be sure */
+	mutex_lock(&info->slots_list_mutex);
+
+	list_for_each_entry(slot, &info->slot_list, node) {
+
+		/* if matches the disabled ones skip */
+		if (bone_match_cape(disable_partno, slot->part_number,
+					slot->version)) {
+			dev_info(&pdev->dev,
+				"Skipping loading of disabled cape with part# %s\n",
+				slot->part_number);
+			slot->disabled = 1;
+			continue;
+		}
+
+		if (!slot->probe_failed && !slot->loaded)
+			slot->loading = 1;
+	}
+
+	/* now start the loader thread(s) (all at once) */
+	list_for_each_entry(slot, &info->slot_list, node) {
+
+		if (!slot->loading)
+			continue;
+
+		slot->loader_thread = kthread_run(capemgr_loader,
+				slot, "capemgr-loader-%d",
+				slot->slotno);
+		if (IS_ERR(slot->loader_thread)) {
+			dev_warn(&pdev->dev, "slot #%d: Failed to start loader\n",
+					slot->slotno);
+			slot->loader_thread = NULL;
+		}
+	}
+	mutex_unlock(&info->slots_list_mutex);
+
+	dev_info(&pdev->dev, "initialized OK.\n");
+
+	return 0;
+
+err_exit:
+	if (bbrd->nvmem_cell)
+		nvmem_cell_put(bbrd->nvmem_cell);
+	of_node_put(baseboardmaps_node);
+	platform_set_drvdata(pdev, NULL);
+	devm_kfree(&pdev->dev, info);
+
+	return ret;
+}
+
+static int capemgr_remove(struct platform_device *pdev)
+{
+	struct capemgr_info *info = platform_get_drvdata(pdev);
+	struct bone_baseboard *bbrd = &info->baseboard;
+	struct bone_cape_slot *slot, *slotn;
+	int ret;
+
+	mutex_lock(&info->slots_list_mutex);
+	list_for_each_entry_safe(slot, slotn, &info->slot_list, node)
+		capemgr_remove_slot_no_lock(slot);
+	mutex_unlock(&info->slots_list_mutex);
+
+	platform_set_drvdata(pdev, NULL);
+
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	if (bbrd->nvmem_cell)
+		nvmem_cell_put(bbrd->nvmem_cell);
+	devm_kfree(&pdev->dev, info);
+
+	return 0;
+}
+
+static struct platform_driver capemgr_driver = {
+	.probe		= capemgr_probe,
+	.remove		= capemgr_remove,
+	.driver		= {
+		.name	= "bone_capemgr",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(capemgr_of_match),
+	},
+};
+
+module_platform_driver(capemgr_driver);
+
+MODULE_AUTHOR("Pantelis Antoniou");
+MODULE_DESCRIPTION("Beaglebone cape manager");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bone_capemgr");
diff --git b/drivers/misc/cape/Kconfig b/drivers/misc/cape/Kconfig
new file mode 100644
index 0000000..a2ef85e
--- /dev/null
+++ b/drivers/misc/cape/Kconfig
@@ -0,0 +1,5 @@
+#
+# Capes
+#
+
+source "drivers/misc/cape/beaglebone/Kconfig"
diff --git b/drivers/misc/cape/Makefile b/drivers/misc/cape/Makefile
new file mode 100644
index 0000000..7c4eb96
--- /dev/null
+++ b/drivers/misc/cape/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for cape like devices
+#
+
+obj-y				+= beaglebone/
diff --git b/drivers/misc/cape/beaglebone/Kconfig b/drivers/misc/cape/beaglebone/Kconfig
new file mode 100644
index 0000000..eeb6782
--- /dev/null
+++ b/drivers/misc/cape/beaglebone/Kconfig
@@ -0,0 +1,10 @@
+#
+# Beaglebone capes
+#
+
+config BEAGLEBONE_PINMUX_HELPER
+	tristate "Beaglebone Pinmux Helper"
+	depends on ARCH_OMAP2PLUS && OF
+	default n
+	help
+	  Say Y here to include support for the pinmux helper
diff --git b/drivers/misc/cape/beaglebone/Makefile b/drivers/misc/cape/beaglebone/Makefile
new file mode 100644
index 0000000..7f4617a
--- /dev/null
+++ b/drivers/misc/cape/beaglebone/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for beaglebone capes
+#
+
+obj-$(CONFIG_BEAGLEBONE_PINMUX_HELPER)	+= bone-pinmux-helper.o
diff --git b/drivers/misc/cape/beaglebone/bone-pinmux-helper.c b/drivers/misc/cape/beaglebone/bone-pinmux-helper.c
new file mode 100644
index 0000000..d81363a
--- /dev/null
+++ b/drivers/misc/cape/beaglebone/bone-pinmux-helper.c
@@ -0,0 +1,242 @@
+/*
+ * Pinmux helper driver
+ *
+ * Copyright (C) 2013 Pantelis Antoniou <panto@antoniou-consulting.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+
+static const struct of_device_id bone_pinmux_helper_of_match[] = {
+	{
+		.compatible = "bone-pinmux-helper",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bone_pinmux_helper_of_match);
+
+struct pinmux_helper_data {
+	struct pinctrl *pinctrl;
+	char *selected_state_name;
+};
+
+static ssize_t pinmux_helper_show_state(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pinmux_helper_data *data = platform_get_drvdata(pdev);
+	const char *name;
+
+	name = data->selected_state_name;
+	if (name == NULL || strlen(name) == 0)
+		name = "none";
+	return sprintf(buf, "%s\n", name);
+}
+
+static ssize_t pinmux_helper_store_state(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pinmux_helper_data *data = platform_get_drvdata(pdev);
+	struct pinctrl_state *state;
+	char *state_name;
+	char *s;
+	int err;
+
+	/* duplicate (as a null terminated string) */
+	state_name = kmalloc(count + 1, GFP_KERNEL);
+	if (state_name == NULL)
+		return -ENOMEM;
+	memcpy(state_name, buf, count);
+	state_name[count] = '\0';
+
+	/* and chop off newline */
+	s = strchr(state_name, '\n');
+	if (s != NULL)
+		*s = '\0';
+
+	/* try to select default state at first (if it exists) */
+	state = pinctrl_lookup_state(data->pinctrl, state_name);
+	if (!IS_ERR(state)) {
+		err = pinctrl_select_state(data->pinctrl, state);
+		if (err != 0)
+			dev_err(dev, "Failed to select state %s\n",
+					state_name);
+	} else {
+		dev_err(dev, "Failed to find state %s\n", state_name);
+		err = PTR_RET(state);
+	}
+
+	if (err == 0) {
+		kfree(data->selected_state_name);
+		data->selected_state_name = state_name;
+	}
+
+	return err ? err : count;
+}
+
+static DEVICE_ATTR(state, S_IWUSR | S_IRUGO,
+		   pinmux_helper_show_state, pinmux_helper_store_state);
+
+static struct attribute *pinmux_helper_attributes[] = {
+	&dev_attr_state.attr,
+	NULL
+};
+
+static const struct attribute_group pinmux_helper_attr_group = {
+	.attrs = pinmux_helper_attributes,
+};
+
+static int bone_pinmux_helper_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pinmux_helper_data *data;
+	struct pinctrl_state *state;
+	char *state_name;
+	const char *mode_name;
+	int mode_len;
+	int err;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (data == NULL) {
+		dev_err(dev, "Failed to allocate data\n");
+		err = -ENOMEM;
+		goto err_no_mem;
+	}
+
+	state_name = kmalloc(strlen(PINCTRL_STATE_DEFAULT) + 1,
+			GFP_KERNEL);
+	if (state_name == NULL) {
+		dev_err(dev, "Failed to allocate state name\n");
+		err = -ENOMEM;
+		goto err_no_state_mem;
+	}
+	data->selected_state_name = state_name;
+	strcpy(data->selected_state_name, PINCTRL_STATE_DEFAULT);
+
+	platform_set_drvdata(pdev, data);
+
+	data->pinctrl = devm_pinctrl_get(dev);
+	if (IS_ERR(data->pinctrl)) {
+		dev_err(dev, "Failed to get pinctrl\n");
+		err = PTR_RET(data->pinctrl);
+		goto err_no_pinctrl;
+	}
+
+	/* See if an initial mode is specified in the device tree */
+	mode_name = of_get_property(dev->of_node, "mode", &mode_len);
+
+	err = -1;
+	if (mode_name != NULL ) {
+		state_name = kmalloc(mode_len + 1, GFP_KERNEL);
+		if (state_name == NULL) {
+			dev_err(dev, "Failed to allocate state name\n");
+			err = -ENOMEM;
+			goto err_no_mode_mem;
+		}
+		strncpy(state_name, mode_name, mode_len);
+
+		/* try to select requested mode */
+		state = pinctrl_lookup_state(data->pinctrl, state_name);
+		if (!IS_ERR(state)) {
+			err = pinctrl_select_state(data->pinctrl, state);
+			if (err != 0) {
+				dev_warn(dev, "Unable to select requested mode %s\n", state_name);
+				kfree(state_name);
+			} else {
+				kfree(data->selected_state_name);
+				data->selected_state_name = state_name;
+				dev_notice(dev, "Set initial pinmux mode to %s\n", state_name);
+			}
+		}
+	}
+
+	/* try to select default state if mode_name failed */
+	if ( err != 0) {
+		state = pinctrl_lookup_state(data->pinctrl,
+				data->selected_state_name);
+		if (!IS_ERR(state)) {
+			err = pinctrl_select_state(data->pinctrl, state);
+			if (err != 0) {
+				dev_err(dev, "Failed to select default state\n");
+				goto err_no_state;
+			}
+		} else {
+			data->selected_state_name = '\0';
+		}
+	}
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&dev->kobj, &pinmux_helper_attr_group);
+	if (err) {
+		dev_err(dev, "Failed to create sysfs group\n");
+		goto err_no_sysfs;
+	}
+
+	return 0;
+
+err_no_sysfs:
+err_no_state:
+err_no_mode_mem:
+	devm_pinctrl_put(data->pinctrl);
+err_no_pinctrl:
+	devm_kfree(dev, data->selected_state_name);
+err_no_state_mem:
+	devm_kfree(dev, data);
+err_no_mem:
+	return err;
+}
+
+static int bone_pinmux_helper_remove(struct platform_device *pdev)
+{
+	struct pinmux_helper_data *data = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+
+	sysfs_remove_group(&dev->kobj, &pinmux_helper_attr_group);
+	kfree(data->selected_state_name);
+	devm_pinctrl_put(data->pinctrl);
+	devm_kfree(dev, data);
+
+	return 0;
+}
+
+struct platform_driver bone_pinmux_helper_driver = {
+	.probe		= bone_pinmux_helper_probe,
+	.remove		= bone_pinmux_helper_remove,
+	.driver = {
+		.name		= "bone-pinmux-helper",
+		.owner		= THIS_MODULE,
+		.of_match_table	= bone_pinmux_helper_of_match,
+	},
+};
+
+module_platform_driver(bone_pinmux_helper_driver);
+
+MODULE_AUTHOR("Pantelis Antoniou");
+MODULE_DESCRIPTION("Beaglebone pinmux helper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bone-pinmux-helper");
diff --git b/drivers/misc/cape_bone_argus/Kconfig b/drivers/misc/cape_bone_argus/Kconfig
new file mode 100644
index 0000000..1b39661
--- /dev/null
+++ b/drivers/misc/cape_bone_argus/Kconfig
@@ -0,0 +1,7 @@
+comment "Argus cape driver for beaglebone black"
+
+config CAPE_BONE_ARGUS
+	tristate "Argus Cape Driver"
+	default M
+	help
+	    Argus Cape Driver
diff --git b/drivers/misc/cape_bone_argus/Makefile b/drivers/misc/cape_bone_argus/Makefile
new file mode 100644
index 0000000..5482562
--- /dev/null
+++ b/drivers/misc/cape_bone_argus/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for Argus cape
+#
+
+obj-$(CONFIG_CAPE_BONE_ARGUS)	+= cape_bone_argus.o
diff --git b/drivers/misc/cape_bone_argus/cape_bone_argus.c b/drivers/misc/cape_bone_argus/cape_bone_argus.c
new file mode 100644
index 0000000..c434218
--- /dev/null
+++ b/drivers/misc/cape_bone_argus/cape_bone_argus.c
@@ -0,0 +1,415 @@
+/* -*- linux-c -*- */
+
+/* Linux Kernel Module for Breakaway Systems UPS control.
+ *
+ * PUBLIC DOMAIN
+ */
+
+#include <linux/syscalls.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mount.h>
+#include <linux/workqueue.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_gpio.h>
+
+/* Module to sync file systems leaving them mounted read-only,
+ * then signal the UPS that it is safe to remove
+ * power, and finally halt the processor.
+ * Also to allow kicking the watchdog from user mode.
+ */
+#undef DEBUG_ARGUS
+
+#define N_GPIOS 9		/* Total number of GPIOS used */
+
+#define REQ_GPIO_IDX 0		/* Indices got GPIOS */
+#define ACK_GPIO_IDX 1
+#define WDG_GPIO_IDX 2
+#define LED1_GREEN_IDX 3
+#define LED1_RED_IDX 4
+#define LED2_GREEN_IDX 5
+#define LED2_RED_IDX 6
+#define GEN_OUT1_IDX 7
+#define GEN_OUT2_IDX 8
+
+static struct argus_ups_info {	/* As there is only one UPS device we can make this static */
+	struct fasync_struct *async_queue; /* asynchronous readers */
+	struct platform_device *pdev;
+	struct pwm_device *pwm_dev;
+	struct gpio gpios[N_GPIOS];
+} info = {NULL, NULL, NULL, /* Some fields filled in by device tree, probe, etc. */
+     {
+	     {-1, GPIOF_IN, "Powerdown request"},
+	     {-1, GPIOF_OUT_INIT_LOW, "Powerdown acknowledge" },
+	     {-1, GPIOF_OUT_INIT_LOW, "Watchdog"},
+	     {-1, GPIOF_OUT_INIT_LOW, "LED 1 Green"},
+	     {-1, GPIOF_OUT_INIT_LOW, "LED 1 Red"},
+	     {-1, GPIOF_OUT_INIT_LOW, "LED 2 Green"},
+	     {-1, GPIOF_OUT_INIT_LOW, "LED 2 Red"},
+	     {-1, GPIOF_OUT_INIT_LOW, "General Output #1"},
+	     {-1, GPIOF_OUT_INIT_LOW, "General Output #2"}
+     },
+};
+
+
+static const struct of_device_id argus_ups_of_ids[] = {
+	{ .compatible = "argus-ups" },
+	{ }
+};
+
+static int argus_ups_major;     /* Major device number */
+
+static struct class *argus_ups_class; /* /sys/class */
+
+dev_t argus_ups_dev;            /* Device number */
+
+static struct cdev *argus_ups_cdev; /* Character device details */
+
+static void argus_ups_function(struct work_struct *ignored); /* Work function */
+
+static DECLARE_DELAYED_WORK(argus_ups_work, argus_ups_function); /* Kernel workqueue glue */
+
+static struct workqueue_struct *argus_ups_workqueue; /* Kernel workqueue */
+
+static int debug = 0;
+module_param(debug, int, S_IRUGO);
+MODULE_PARM_DESC(debug, "Debug flag");
+
+static int shutdown = 1;
+module_param(shutdown, int, S_IRUGO);
+MODULE_PARM_DESC(shutdown, "Shutdown flag");
+
+#ifdef DEBUG_ARGUS
+static char* fs_type_names[] = {"vfat", "ext4"}; /* File system names that may need syncing. */
+#endif
+
+/* Just kick watchdog */
+
+static ssize_t argus_ups_write(struct file *filp, const char __user *buf, size_t count,
+                loff_t *f_pos)
+{
+	int i;
+        if (debug >= 3) {
+            printk("Writing to watchdog - count:%d\n", count);
+        }
+	for (i = 0; i < count; i++) {
+		gpio_set_value(info.gpios[WDG_GPIO_IDX].gpio, 1); /* Set it */
+		msleep(10);                       /* Wait */
+		gpio_set_value(info.gpios[WDG_GPIO_IDX].gpio, 0); /* End clearing it */
+		msleep(10);
+	}
+	return count;                     /* Always returns what we sent, regardsless */
+}
+
+static long argus_ups_ioctl(struct file *file,
+			   unsigned int ioctl,
+			   unsigned long param)
+{
+	if (debug >= 4) {
+		printk(KERN_ERR "ioctl: %d, param: %ld\n", ioctl, param);
+	}
+	switch(ioctl) {
+	case 10001: {
+		debug = param;
+		printk("Debug set to %d\n", debug);
+		break;
+	}
+	case 10002: {
+		unsigned char value = param & 0x0F;
+		unsigned char mask = (param >> 4) & 0x0F;
+		int i;		/* Loop iterator */
+		if (mask == 0) {
+			printk(KERN_ERR "Pointless mask of zero!\n");
+		}
+		for (i = 0; i < 4; i++) { /* For all four LEDS */
+			if (mask & (1 << i)) { /* Only masked values */
+				if (value & (1 << i)) { /* On - so gpio is hi */
+					if (debug >= 4) {
+						printk("Setting %d hi, ",
+						       info.gpios[LED1_GREEN_IDX + i].gpio);
+					}
+					gpio_set_value(info.gpios[LED1_GREEN_IDX + i].gpio, 1);
+				}
+				else {	/* Off - so gpio is lo */
+					if (debug >= 4) {
+						printk("Setting %d lo, ",
+						       info.gpios[LED1_GREEN_IDX + i].gpio);
+					}
+					gpio_set_value(info.gpios[LED1_GREEN_IDX + i].gpio, 0);
+				}
+			}
+		}
+		if (debug >= 4) {
+			printk("\n");
+		}
+		break;
+	}
+	case 10003: {
+		gpio_set_value(info.gpios[GEN_OUT1_IDX].gpio, param & 1);
+		break;
+	}
+	case 10004: {
+		gpio_set_value(info.gpios[GEN_OUT2_IDX].gpio, param & 1);
+		break;
+	}
+	default:
+	{
+		printk(KERN_ERR "Invalid ioctl %d\n", ioctl);
+		return -1;
+	}
+	}
+	return 0;
+}
+
+static int argus_ups_fasync(int fd, struct file *filp, int mode)
+{
+	printk(KERN_ERR "In argus_ups_fasync() fd:%d, filp:%p, mode:%d\n", fd, filp, mode);
+	return fasync_helper(fd, filp, mode, &info.async_queue);
+}
+
+static struct file_operations argus_ups_fops = { /* Only file operation is to kick watchdog via a write */
+	.owner =    THIS_MODULE,
+	.llseek =   NULL,
+	.read =     NULL,
+	.unlocked_ioctl = argus_ups_ioctl,
+	.write =    argus_ups_write,
+	.open =     NULL,
+	.release =  NULL,
+	.fasync = argus_ups_fasync,
+};
+
+#ifdef DEBUG_ARGUS
+static void remount_sb(struct super_block *sb)
+{
+	int flags =  MS_RDONLY;
+	int result = sb->s_op->remount_fs(sb, &flags, "");
+	if (debug) {
+		printk("Processing superblock %p\n", sb);
+		printk("Remount operation returned %d\n", result);
+	}
+}
+#endif
+
+static void argus_ups_function(struct work_struct *ignored)
+{
+	static int testdata = 0;       /* Data for test */
+	int i;                      /* Iterator */
+	testdata++;
+	if (!gpio_get_value(info.gpios[REQ_GPIO_IDX].gpio)) {
+                queue_delayed_work(argus_ups_workqueue, &argus_ups_work, HZ/100); /* Re-queue in 10mS*/
+		return;
+        }
+	printk(KERN_ERR "Request received\n");
+	if (debug) {
+		printk("Shutdown request received from UPS\n");
+	}
+	if (!shutdown) {
+		printk("Shutdown request ignored\n");
+		return;
+	}
+
+	if (debug) {
+		printk("Sending async kill SIGIO to %p\n", info.async_queue);
+	}
+	if (info.async_queue) { /* Try and tell usermode to halt system */
+		kill_fasync(&info.async_queue, SIGIO, POLL_IN);
+	}
+	gpio_set_value(info.gpios[LED1_GREEN_IDX].gpio, 0); /* Turn off green LED1 */
+	for (i = 0; i < 300; i++) { /* Toggle acknowledge at 10 Hz for 15 seconds */
+		if (debug >= 2) {
+			printk("Waiting for first shutdown request:%d\n", i);
+		}
+		gpio_set_value(info.gpios[ACK_GPIO_IDX].gpio, i & 1); /* Toggle acknowledge */
+		gpio_set_value(info.gpios[LED1_RED_IDX].gpio, i & 1); /* and LED1 red */
+		msleep(50); /* Wait in 50ms increments */
+	}
+
+	{
+		char *argv[] = { "/sbin/halt", NULL };
+		static char *envp[] = {
+			"HOME=/",
+			"TERM=linux",
+			"PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin", NULL };
+
+		call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC );
+	}
+	for (i = 0; i < 300; i++) { /* Toggle acknowledge at 10 Hz for 15 more seconds */
+		if (debug >= 2) {
+			printk("Waiting for second shutdown request:%d\n", i);
+		}
+		gpio_set_value(info.gpios[ACK_GPIO_IDX].gpio, i & 1); /* Toggle acknowledge */
+		gpio_set_value(info.gpios[LED1_RED_IDX].gpio, i & 1); /* and LED1 red */
+		msleep(50); /* Wait in 50ms increments */
+	}
+	printk(KERN_ERR "Usermode failed to halt system\n");
+	kernel_halt();	       /* Last resort - may give some oopss */
+}
+
+
+static int argus_ups_probe(struct platform_device *pdev) /* Entry point */
+{
+	struct pinctrl *pinctrl;
+	struct device_node *pnode = pdev->dev.of_node;
+	int i;
+	int ret;
+        printk("Init UPS module - debug=%d, shutdown=%d\n",
+	       debug, shutdown);
+	platform_set_drvdata(pdev, &info);
+	info.pdev = pdev;
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		dev_warn(&pdev->dev,
+			"pins are not configured from the driver\n");
+		return -1;
+	}
+	ret = of_property_read_u32(pnode, "debug", &debug);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Unable to read debug parameter\n");
+	}
+	else {
+		printk("Debug parameter read from DT:%d\n", debug);
+	}
+
+	ret = of_property_read_u32(pnode, "shutdown", &shutdown);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Unable to read shutdown parameter\n");
+	}
+	else {
+		printk("Shutdown parameter read from DT:%d\n", shutdown);
+	}
+
+	ret = of_gpio_count(pnode);
+
+	if (ret != N_GPIOS) {
+		printk(KERN_ERR "Wrong number of gpios");
+		return -1;
+	}
+
+	for (i = 0; i < of_gpio_count(pnode); i++) {
+		ret = of_get_gpio_flags(pnode, i, NULL);
+		if (debug) {
+			printk("GPIO#%d:%d\n", i, ret);
+		}
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(&pdev->dev, "unable to get GPIO %d\n", i);
+			goto err_no_gpio;
+		}
+		info.gpios[i].gpio = ret;
+	}
+
+
+        ret = alloc_chrdev_region(&argus_ups_dev, 0, 2, "argus_ups");
+        argus_ups_major = MAJOR(argus_ups_dev);
+        if (ret) {
+		printk(KERN_ERR "Error %d adding argus_ups\n", ret);
+		return -1;
+        }
+	if (debug) {
+		printk("argus_ups major: %d\n", argus_ups_major);
+	}
+        argus_ups_cdev = cdev_alloc(); /* Make this a character device */
+        argus_ups_cdev->ops = &argus_ups_fops; /* File operations */
+        argus_ups_cdev->owner = THIS_MODULE;   /* Top level device */
+        ret = cdev_add(argus_ups_cdev, argus_ups_dev, 1); /* Add it to the kernel */
+        if (ret) {
+		printk(KERN_ERR "cdev_add returned %d\n", ret);
+		unregister_chrdev_region(0, 1);
+		return -1;
+	}
+        ret = gpio_request_array(info.gpios, N_GPIOS);
+	if (ret) {
+		printk(KERN_ERR "Error %d requesting GPIOs\n", ret);
+		unregister_chrdev_region(0, 1);
+		return -1;
+        }
+
+        argus_ups_class = class_create(THIS_MODULE, "argus_ups"); /* /sys/class entry for udev */
+        if (IS_ERR(argus_ups_class)) {
+		printk(KERN_ERR "Error creating argus_ups_class\n");
+		unregister_chrdev_region(0, 1);
+		return -1;
+	}
+	device_create(argus_ups_class, NULL, MKDEV(argus_ups_major, 0), NULL, "argus_ups");
+        argus_ups_workqueue = create_singlethread_workqueue("argus_ups");
+        INIT_DELAYED_WORK(&argus_ups_work, argus_ups_function);
+        queue_delayed_work(argus_ups_workqueue, &argus_ups_work, 0); /* Start work immediately */
+
+        return 0;
+err_no_gpio:
+	return ret;
+
+}
+
+
+static void argus_ups_cleanup(void)
+{
+	printk("Module cleanup called\n");
+        while (cancel_delayed_work(&argus_ups_work) == 0) {
+		flush_workqueue(argus_ups_workqueue); /* Make sure all work is completed */
+	}
+	destroy_workqueue(argus_ups_workqueue);
+	gpio_free_array(info.gpios, N_GPIOS);
+	device_destroy(argus_ups_class, argus_ups_dev);
+	class_destroy(argus_ups_class);
+        unregister_chrdev_region(argus_ups_dev, 1);
+        cdev_del(argus_ups_cdev);
+}
+
+
+
+static int argus_ups_remove(struct platform_device *pdev)
+{
+	printk("In argus_ups_remove()\n");
+	argus_ups_cleanup();
+	printk("After cleanup\n");
+	return 0;
+}
+
+#define ARGUS_UPS_PM_OPS NULL
+
+struct platform_driver argus_ups_driver = {
+	.probe		= argus_ups_probe,
+	.remove		= argus_ups_remove,
+	.driver = {
+		.name		= "argus-ups",
+		.owner		= THIS_MODULE,
+		.pm		= ARGUS_UPS_PM_OPS,
+		.of_match_table = argus_ups_of_ids,
+	},
+};
+
+
+static int __init argus_ups_init(void)
+{
+	return platform_driver_probe(&argus_ups_driver,
+				     argus_ups_probe);
+}
+
+static void __exit argus_ups_exit(void)
+{
+	platform_driver_unregister(&argus_ups_driver);
+	printk("After driver unregister\n");
+}
+
+module_init(argus_ups_init);
+module_exit(argus_ups_exit);
+
+/*
+ * Get rid of taint message.
+ */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Lambert");	/* Who wrote this module? */
+MODULE_DESCRIPTION("Argus UPS control"); /* What does this module do */
+MODULE_ALIAS("platform:argus-ups");
+MODULE_DEVICE_TABLE(of, argus_ups_of_ids);
diff --git b/drivers/misc/devovmgr.c b/drivers/misc/devovmgr.c
new file mode 100644
index 0000000..d5c8d1d
--- /dev/null
+++ b/drivers/misc/devovmgr.c
@@ -0,0 +1,1306 @@
+/*
+ * Device overlay manager
+ *
+ * Copyright (C) 2015 Konsulko Group
+ * Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+ *
+ * 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.
+ */
+#include <linux/ctype.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/spinlock.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/configfs.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/limits.h>
+#include <linux/file.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/pci.h>
+#include <linux/usb.h>
+#include <linux/mod_devicetable.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+
+enum dovmgr_type {
+	ITEM_PCI,
+	ITEM_USB
+};
+
+struct dovmgr_item;
+
+struct dovmgr_dev_item {
+	struct dovmgr_item *item;
+	struct list_head node;
+	struct device *dev;
+	const struct firmware *fw;
+	struct device_node *overlay;
+	int overlay_id;
+	struct work_struct work;
+};
+
+struct dovmgr_item {
+	struct config_item item;
+	char *path;
+	bool enable;
+	char *overlay_name;
+	struct mutex dev_item_mutex;
+	struct list_head dev_item_list;
+	enum dovmgr_type type;
+	union {
+		struct pci_device_id pci;
+		struct usb_device_id usb;
+	};
+};
+
+struct config_group dovmgr_pci_group;
+struct config_group dovmgr_usb_group;
+
+static inline struct dovmgr_item *to_dovmgr_item(struct config_item *cfsitem)
+{
+	if (!cfsitem)
+		return NULL;
+
+	return container_of(cfsitem, struct dovmgr_item, item);
+}
+
+static int dovmgr_notifier_action(struct config_group *group,
+		unsigned long action, struct device *dev,
+		int (*do_match)(struct dovmgr_item *item, struct device *dev),
+		int (*do_action)(struct dovmgr_item *item, unsigned long action,
+			struct device *dev))
+{
+	struct config_item *cfsitem;
+	struct dovmgr_item *item;
+	int ret;
+
+	/* only handle device notifiers */
+	if (action != BUS_NOTIFY_ADD_DEVICE &&
+		action != BUS_NOTIFY_DEL_DEVICE &&
+		action != BUS_NOTIFY_REMOVED_DEVICE)
+		return 0;
+
+	ret = 0;
+	list_for_each_entry(cfsitem, &group->cg_children, ci_entry) {
+		item = to_dovmgr_item(cfsitem);
+		if (!item->enable || !(*do_match)(item, dev))
+			continue;
+
+		ret = (*do_action)(item, action, dev);
+		if (ret != 0)
+			break;
+	}
+	return ret;
+}
+
+#if IS_ENABLED(CONFIG_PCI)
+/* copy of drivers/pci/pci.h */
+static inline const struct pci_device_id *
+pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
+{
+	if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
+	    (id->device == PCI_ANY_ID || id->device == dev->device) &&
+	    (id->subvendor == PCI_ANY_ID ||
+		id->subvendor == dev->subsystem_vendor) &&
+	    (id->subdevice == PCI_ANY_ID ||
+		id->subdevice == dev->subsystem_device) &&
+	    !((id->class ^ dev->class) & id->class_mask))
+		return id;
+	return NULL;
+}
+
+static int dovmgr_pci_item_match(struct dovmgr_item *item, struct device *dev)
+{
+	struct pci_dev *pdev;
+
+	BUG_ON(item->type != ITEM_PCI);
+	pdev = to_pci_dev(dev);
+
+	return pci_match_one_device(&item->pci, pdev) != NULL;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_USB)
+/* in drivers/usb/core/driver.c */
+extern int usb_match_device(struct usb_device *dev,
+		const struct usb_device_id *id);
+
+static int dovmgr_usb_item_match(struct dovmgr_item *item, struct device *dev)
+{
+	struct usb_device *udev;
+
+	BUG_ON(item->type != ITEM_USB);
+	udev = to_usb_device(dev);
+
+	return usb_match_device(udev, &item->usb);
+}
+#endif
+
+static struct dovmgr_dev_item *dovmgr_lookup_dev_item(struct dovmgr_item *item,
+		struct device *dev)
+{
+	struct dovmgr_dev_item *ditem;
+
+	list_for_each_entry(ditem, &item->dev_item_list, node)
+		if (ditem->dev == dev)
+			return ditem;
+	return NULL;
+}
+
+static void dovmgr_item_work_func(struct work_struct *work)
+{
+	struct dovmgr_dev_item *ditem = container_of(work,
+			struct dovmgr_dev_item, work);
+	struct dovmgr_item *item = ditem->item;
+	struct device *dev;
+	struct device_node *np;
+	int err;
+
+	mutex_lock(&item->dev_item_mutex);
+
+	dev = ditem->dev;
+	np = dev->of_node;
+	if (!dev || !np || !item->overlay_name || ditem->overlay_id >= 0)
+		goto out_unlock;
+
+	pr_info("%s: %s %s\n", __func__,
+		kobject_name(&dev->kobj), of_node_full_name(np));
+
+	err = request_firmware_direct(&ditem->fw, item->overlay_name, dev);
+	if (err != 0) {
+		pr_err("%s: %s failed to load firmware '%s'\n", __func__,
+			kobject_name(&dev->kobj), item->overlay_name);
+		goto out_unlock;
+	}
+
+	of_fdt_unflatten_tree((void *)ditem->fw->data, &ditem->overlay);
+	if (ditem->overlay == NULL) {
+		pr_err("%s: %s failed to load firmware '%s'\n", __func__,
+			kobject_name(&dev->kobj), item->overlay_name);
+		goto out_release_fw;
+	}
+
+	/* mark it as detached */
+	of_node_set_flag(ditem->overlay, OF_DETACHED);
+
+	/* perform resolution */
+	err = of_resolve_phandles(ditem->overlay);
+	if (err != 0) {
+		pr_err("%s: %s failed to resolve tree\n", __func__,
+			kobject_name(&dev->kobj));
+		goto out_release_overlay;
+	}
+
+	err = of_overlay_create_target_root(ditem->overlay, np);
+	if (err < 0) {
+		pr_err("%s: %s failed to create overlay\n", __func__,
+			kobject_name(&dev->kobj));
+		goto out_release_overlay;
+	}
+	ditem->overlay_id = err;
+
+out_unlock:
+	mutex_unlock(&item->dev_item_mutex);
+	return;
+
+out_release_overlay:
+	/* TODO: free the overlay, we can't right now cause
+	 * the unflatten method does not track it */
+	ditem->overlay = NULL;
+out_release_fw:
+	release_firmware(ditem->fw);
+	ditem->fw = NULL;
+	goto out_unlock;
+}
+
+/* dev item list mutex lock must be held */
+static int dovmgr_add_dev_item(struct dovmgr_item *item, struct device *dev)
+{
+	struct dovmgr_dev_item *ditem;
+
+	/* first make sure there's no duplicate */
+	if (dovmgr_lookup_dev_item(item, dev))
+		return -EEXIST;
+
+	/* add the device item */
+	ditem = kzalloc(sizeof(*ditem), GFP_KERNEL);
+	if (!ditem)
+		return -ENOMEM;
+	ditem->overlay_id = -1;
+	ditem->dev = get_device(dev);
+	INIT_WORK(&ditem->work, dovmgr_item_work_func);
+	ditem->item = item;
+
+	list_add_tail(&ditem->node, &item->dev_item_list);
+
+	pr_info("%s: added device %s from item's %s list\n", __func__,
+			kobject_name(&dev->kobj),
+			config_item_name(&item->item));
+
+	/* now schedule the overlay application */
+	if (item->overlay_name)
+		schedule_work(&ditem->work);
+
+	return 0;
+}
+
+static int dovmgr_remove_dev_item(struct dovmgr_item *item, struct device *dev)
+{
+	struct dovmgr_dev_item *ditem;
+
+	/* find it */
+	ditem = dovmgr_lookup_dev_item(item, dev);
+	if (!ditem)
+		return -ENODEV;
+
+	if (work_pending(&ditem->work))
+		cancel_work_sync(&ditem->work);
+
+	if (ditem->overlay_id >= 0) {
+		of_overlay_destroy(ditem->overlay_id);
+		ditem->overlay_id = -1;
+
+	}
+
+	if (ditem->overlay) {
+		/* TODO: free the overlay, we can't right now cause
+		* the unflatten method does not track it */
+		ditem->overlay = NULL;
+	}
+
+	if (ditem->fw) {
+		/* TODO release_firmware(ditem->fw); */
+		release_firmware(ditem->fw);
+		ditem->fw = NULL;
+	}
+
+	put_device(ditem->dev);
+	list_del(&ditem->node);
+
+	kfree(ditem);
+
+	pr_info("%s: removed device %s from item's %s list\n", __func__,
+			kobject_name(&dev->kobj),
+			config_item_name(&item->item));
+
+	return 0;
+}
+
+static int dovmgr_item_notify(struct dovmgr_item *item,
+		unsigned long action, struct device *dev)
+{
+	int ret;
+
+	ret = 0;
+	mutex_lock(&item->dev_item_mutex);
+
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		pr_info("%s: BUS_NOTIFY_ADD_DEVICE for %s\n", __func__,
+				kobject_name(&dev->kobj));
+
+		ret = dovmgr_add_dev_item(item, dev);
+		if (ret != 0)
+			goto out_unlock;
+
+		break;
+
+	case BUS_NOTIFY_DEL_DEVICE:
+		pr_info("%s: BUS_NOTIFY_DEL_DEVICE for %s\n", __func__,
+				kobject_name(&dev->kobj));
+		break;
+
+	case BUS_NOTIFY_REMOVED_DEVICE:
+		pr_info("%s: BUS_NOTIFY_REMOVE_DEVICE for %s\n", __func__,
+				kobject_name(&dev->kobj));
+
+		ret = dovmgr_remove_dev_item(item, dev);
+		if (ret != 0)
+			goto out_unlock;
+
+		break;
+	}
+
+out_unlock:
+	mutex_unlock(&item->dev_item_mutex);
+
+	return ret;
+}
+
+#if IS_ENABLED(CONFIG_PCI)
+static int dovmgr_pci_add_iterator(struct device *dev, void *data)
+{
+	struct dovmgr_item *item = data;
+
+	/* do add match */
+	if (!item->enable || !dovmgr_pci_item_match(item, dev))
+		return 0;
+
+	pr_info("%s: dev=%s\n", __func__, kobject_name(&dev->kobj));
+
+	return dovmgr_item_notify(item, BUS_NOTIFY_ADD_DEVICE, dev);
+}
+
+static int dovmgr_pci_removed_iterator(struct device *dev, void *data)
+{
+	struct dovmgr_item *item = data;
+
+	/* do add match */
+	if (item->enable || !dovmgr_pci_item_match(item, dev))
+		return 0;
+
+	pr_info("%s: dev=%s\n", __func__, kobject_name(&dev->kobj));
+
+	return dovmgr_item_notify(item, BUS_NOTIFY_REMOVED_DEVICE, dev);
+}
+#endif
+
+#if IS_ENABLED(CONFIG_USB)
+static int dovmgr_usb_add_iterator(struct device *dev, void *data)
+{
+	struct dovmgr_item *item = data;
+
+	/* do add match */
+	if (item->enable || !dovmgr_usb_item_match(item, dev))
+		return 0;
+
+	pr_info("%s: dev=%s\n", __func__, kobject_name(&dev->kobj));
+
+	return dovmgr_item_notify(item, BUS_NOTIFY_ADD_DEVICE, dev);
+}
+
+static int dovmgr_usb_removed_iterator(struct device *dev, void *data)
+{
+	struct dovmgr_item *item = data;
+
+	/* do add match */
+	if (!item->enable || !dovmgr_usb_item_match(item, dev))
+		return 0;
+
+	pr_info("%s: dev=%s\n", __func__, kobject_name(&dev->kobj));
+
+	return dovmgr_item_notify(item, BUS_NOTIFY_REMOVED_DEVICE, dev);
+}
+#endif
+
+static int dovmgr_item_set_enable(struct dovmgr_item *item, bool new_enable)
+{
+	int ret;
+
+	if (new_enable == item->enable)
+		return 0;
+
+	item->enable = new_enable;
+	switch (item->type) {
+#if IS_ENABLED(CONFIG_PCI)
+	case ITEM_PCI:
+		ret = bus_for_each_dev(&pci_bus_type, NULL, item,
+			new_enable ? dovmgr_pci_add_iterator :
+					dovmgr_pci_removed_iterator);
+		if (ret != 0)
+			return ret;
+		break;
+#endif
+#if IS_ENABLED(CONFIG_USB)
+	case ITEM_USB:
+		ret = bus_for_each_dev(&usb_bus_type, NULL, item,
+			new_enable ? dovmgr_usb_add_iterator :
+					dovmgr_usb_removed_iterator);
+		if (ret != 0)
+			return ret;
+		break;
+#endif
+	default:
+		break;
+	}
+	return 0;
+}
+
+
+static ssize_t dovmgr_item_str_show(struct dovmgr_item *item,
+		char *page, char **strp)
+{
+	return snprintf(page, PAGE_SIZE, "%s\n",
+			*strp ? *strp : "");
+}
+
+static ssize_t dovmgr_item_str_store(struct dovmgr_item *item,
+		const char *page, size_t count, char **strp)
+{
+	const char *s;
+	int len;
+
+	/* copy to path buffer (and make sure it's always zero terminated */
+	len = strnlen(page, PAGE_SIZE);
+	if (len >= PAGE_SIZE)
+		return -EINVAL;
+	s = page + len;
+	while (len > 0 && *--s == '\n')
+		len--;
+	if (len == 0)
+		return -EINVAL;
+
+	if (*strp)
+		kfree(*strp);
+	*strp = kmalloc(len + 1, GFP_KERNEL);
+	if (!*strp)
+		return -ENOMEM;
+	memcpy(*strp, page, len);
+	(*strp)[len + 1] = '\0';
+
+	return count;
+}
+
+static ssize_t dovmgr_item_path_show(struct config_item *citem, char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return dovmgr_item_str_show(item, page, &item->path);
+}
+
+static ssize_t dovmgr_item_path_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return dovmgr_item_str_store(item, page, count, &item->path);
+}
+
+static ssize_t dovmgr_item_enable_show(struct config_item *citem, char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return snprintf(page, PAGE_SIZE, "%u\n", !!item->enable);
+}
+
+static ssize_t dovmgr_item_enable_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	int ret;
+	unsigned int val;
+
+	ret = kstrtouint(page, 0, &val);
+	if (ret != 0)
+		return ret;
+
+	ret = dovmgr_item_set_enable(item, !!val);
+	if (ret != 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t dovmgr_item_overlay_show(struct config_item *citem, char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	ssize_t ret;
+
+	mutex_lock(&item->dev_item_mutex);
+	ret = snprintf(page, PAGE_SIZE, "%s\n", item->overlay_name ?
+			item->overlay_name : "");
+	mutex_unlock(&item->dev_item_mutex);
+	return ret;
+};
+
+
+static ssize_t dovmgr_item_overlay_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	ssize_t ret;
+
+	mutex_lock(&item->dev_item_mutex);
+	kfree(item->overlay_name);
+	item->overlay_name = kstrndup(page, PAGE_SIZE, GFP_KERNEL);
+	if (!item->overlay_name)
+		ret = -ENOMEM;
+	else
+		ret = count;
+	mutex_unlock(&item->dev_item_mutex);
+	return ret;
+}
+
+static ssize_t dovmgr_item_status_show(struct config_item *citem, char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	struct dovmgr_dev_item *ditem;
+	char *p, *e;
+	int len;
+
+	p = page;
+	e = page + PAGE_SIZE;
+
+	mutex_lock(&item->dev_item_mutex);
+	list_for_each_entry(ditem, &item->dev_item_list, node) {
+		len = snprintf(p, e - p, "%s:%s:%d\n",
+			kobject_name(&ditem->dev->kobj),
+			of_node_full_name(ditem->dev->of_node),
+			ditem->overlay_id);
+		p += len;
+		if (p >= e - 1)
+			break;
+	}
+	mutex_unlock(&item->dev_item_mutex);
+
+	return p - page;
+}
+
+CONFIGFS_ATTR(dovmgr_item_, path);
+CONFIGFS_ATTR_RO(dovmgr_item_, status);
+CONFIGFS_ATTR(dovmgr_item_, enable);
+CONFIGFS_ATTR(dovmgr_item_, overlay);
+
+#if IS_ENABLED(CONFIG_PCI)
+static ssize_t dovmgr_item_pci_device_show(struct config_item *citem,
+		char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return snprintf(page, PAGE_SIZE, "0x%04x\n", item->pci.device);
+}
+
+static ssize_t dovmgr_item_pci_device_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	int ret;
+	unsigned int val;
+
+	ret = kstrtouint(page, 0, &val);
+	if (ret != 0)
+		return ret;
+	item->pci.device = val;
+	return count;
+}
+
+static ssize_t dovmgr_item_pci_vendor_show(struct config_item *citem,
+		char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return snprintf(page, PAGE_SIZE, "0x%04x\n", item->pci.vendor);
+}
+
+static ssize_t dovmgr_item_pci_vendor_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	int ret;
+	unsigned int val;
+
+	/* cannot modify when item is enabled */
+	if (item->enable)
+		return -EBUSY;
+
+	ret = kstrtouint(page, 0, &val);
+	if (ret != 0)
+		return ret;
+	item->pci.vendor = val;
+	return count;
+}
+
+static ssize_t dovmgr_item_pci_subdevice_show(struct config_item *citem,
+		char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return snprintf(page, PAGE_SIZE, "0x%08x\n", item->pci.subdevice);
+}
+
+static ssize_t dovmgr_item_pci_subdevice_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	int ret;
+	unsigned int val;
+
+	/* cannot modify when item is enabled */
+	if (item->enable)
+		return -EBUSY;
+
+	ret = kstrtouint(page, 0, &val);
+	if (ret != 0)
+		return ret;
+	item->pci.subdevice = val;
+	return count;
+}
+
+static ssize_t dovmgr_item_pci_subvendor_show(struct config_item *citem,
+		char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return snprintf(page, PAGE_SIZE, "0x%08x\n", item->pci.subvendor);
+}
+
+static ssize_t dovmgr_item_pci_subvendor_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	int ret;
+	unsigned int val;
+
+	/* cannot modify when item is enabled */
+	if (item->enable)
+		return -EBUSY;
+
+	ret = kstrtouint(page, 0, &val);
+	if (ret != 0)
+		return ret;
+	item->pci.subvendor = val;
+	return count;
+}
+
+static ssize_t dovmgr_item_pci_class_show(struct config_item *citem, char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return snprintf(page, PAGE_SIZE, "0x%04x\n", item->pci.class);
+}
+
+static ssize_t dovmgr_item_pci_class_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	int ret;
+	unsigned int val;
+
+	/* cannot modify when item is enabled */
+	if (item->enable)
+		return -EBUSY;
+
+	ret = kstrtouint(page, 0, &val);
+	if (ret != 0)
+		return ret;
+	item->pci.class = val;
+	return count;
+}
+
+static ssize_t dovmgr_item_pci_class_mask_show(struct config_item *citem,
+		char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return snprintf(page, PAGE_SIZE, "0x%04x\n", item->pci.class_mask);
+}
+
+static ssize_t dovmgr_item_pci_class_mask_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	int ret;
+	unsigned int val;
+
+	/* cannot modify when item is enabled */
+	if (item->enable)
+		return -EBUSY;
+
+	ret = kstrtouint(page, 0, &val);
+	if (ret != 0)
+		return ret;
+	item->pci.class_mask = val;
+	return count;
+}
+
+CONFIGFS_ATTR(dovmgr_item_pci_, device);
+CONFIGFS_ATTR(dovmgr_item_pci_, vendor);
+CONFIGFS_ATTR(dovmgr_item_pci_, subdevice);
+CONFIGFS_ATTR(dovmgr_item_pci_, subvendor);
+CONFIGFS_ATTR(dovmgr_item_pci_, class);
+CONFIGFS_ATTR(dovmgr_item_pci_, class_mask);
+#endif
+
+#if IS_ENABLED(CONFIG_USB)
+static ssize_t dovmgr_item_usb_idProduct_show(struct config_item *citem,
+		char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return snprintf(page, PAGE_SIZE, "0x%04x\n",
+			item->usb.idProduct);
+}
+
+static ssize_t dovmgr_item_usb_idProduct_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	int ret;
+	unsigned int val;
+
+	/* cannot modify when item is enabled */
+	if (item->enable)
+		return -EBUSY;
+
+	ret = kstrtouint(page, 0, &val);
+	if (ret != 0)
+		return ret;
+	item->usb.idProduct = val;
+	return count;
+}
+
+static ssize_t dovmgr_item_usb_idVendor_show(struct config_item *citem,
+		char *page)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	return snprintf(page, PAGE_SIZE, "0x%04x\n",
+			item->usb.idVendor);
+}
+
+static ssize_t dovmgr_item_usb_idVendor_store(struct config_item *citem,
+		const char *page, size_t count)
+{
+	struct dovmgr_item *item = to_dovmgr_item(citem);
+	int ret;
+	unsigned int val;
+
+	/* cannot modify when item is enabled */
+	if (item->enable)
+		return -EBUSY;
+
+	ret = kstrtouint(page, 0, &val);
+	if (ret != 0)
+		return ret;
+	item->usb.idVendor = val;
+	return count;
+}
+
+CONFIGFS_ATTR(dovmgr_item_usb_, idProduct);
+CONFIGFS_ATTR(dovmgr_item_usb_, idVendor);
+#endif
+
+#if IS_ENABLED(CONFIG_PCI)
+static struct configfs_attribute *dovmgr_pci_attrs[] = {
+	&dovmgr_item_attr_path,
+	&dovmgr_item_attr_status,
+	&dovmgr_item_attr_enable,
+	&dovmgr_item_attr_overlay,
+	&dovmgr_item_pci_attr_device,
+	&dovmgr_item_pci_attr_vendor,
+	&dovmgr_item_pci_attr_subdevice,
+	&dovmgr_item_pci_attr_subvendor,
+	&dovmgr_item_pci_attr_class,
+	&dovmgr_item_pci_attr_class_mask,
+	NULL,
+};
+#endif
+
+#if IS_ENABLED(CONFIG_USB)
+static struct configfs_attribute *dovmgr_usb_attrs[] = {
+	&dovmgr_item_attr_path,
+	&dovmgr_item_attr_enable,
+	&dovmgr_item_attr_status,
+	&dovmgr_item_attr_overlay,
+	&dovmgr_item_usb_attr_idVendor,
+	&dovmgr_item_usb_attr_idProduct,
+	NULL,
+};
+#endif
+
+static void dovmgr_release(struct config_item *cfsitem)
+{
+	struct dovmgr_item *item = to_dovmgr_item(cfsitem);
+
+	/* disable item (this removes the overlay and all) */
+	dovmgr_item_set_enable(item, false);
+
+	kfree(item->path);
+	kfree(item);
+}
+
+static struct configfs_item_operations dovmgr_item_ops = {
+	.release		= dovmgr_release,
+};
+
+#if IS_ENABLED(CONFIG_PCI)
+static struct config_item_type dovmgr_pci_item_type = {
+	.ct_item_ops	= &dovmgr_item_ops,
+	.ct_attrs	= dovmgr_pci_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+#endif
+
+#if IS_ENABLED(CONFIG_USB)
+static struct config_item_type dovmgr_usb_item_type = {
+	.ct_item_ops	= &dovmgr_item_ops,
+	.ct_attrs	= dovmgr_usb_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+#endif
+
+static struct config_item *dovmgr_group_make_item(
+		struct config_group *group, const char *name,
+		enum dovmgr_type type)
+{
+	struct dovmgr_item *item;
+	struct config_item_type *item_type;
+
+	switch (type) {
+#if IS_ENABLED(CONFIG_PCI)
+	case ITEM_PCI:
+		item_type = &dovmgr_pci_item_type;
+		break;
+#endif
+#if IS_ENABLED(CONFIG_USB)
+	case ITEM_USB:
+		item_type = &dovmgr_usb_item_type;
+		break;
+#endif
+	default:
+		return ERR_PTR(-EINVAL);
+	};
+
+	item = kzalloc(sizeof(*item), GFP_KERNEL);
+	if (!item)
+		return ERR_PTR(-ENOMEM);
+
+	item->type = type;
+	item->enable = false;
+	mutex_init(&item->dev_item_mutex);
+	INIT_LIST_HEAD(&item->dev_item_list);
+
+	switch (type) {
+#if IS_ENABLED(CONFIG_PCI)
+	case ITEM_PCI:
+		/* default for matching device/vendor */
+		item->pci.vendor = PCI_ANY_ID;
+		item->pci.device = PCI_ANY_ID;
+		item->pci.subvendor = PCI_ANY_ID;
+		item->pci.subdevice = PCI_ANY_ID;
+		item->pci.class = 0;
+		item->pci.class_mask = 0;
+		break;
+#endif
+#if IS_ENABLED(CONFIG_USB)
+	case ITEM_USB:
+		/* default */
+		item->usb.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+		break;
+#endif
+	default:
+		return ERR_PTR(-EINVAL);
+	};
+
+	config_item_init_type_name(&item->item, name, item_type);
+	return &item->item;
+}
+
+#if IS_ENABLED(CONFIG_PCI)
+static struct config_item *dovmgr_group_pci_make_item(
+		struct config_group *group, const char *name)
+{
+	return dovmgr_group_make_item(group, name, ITEM_PCI);
+}
+#endif
+
+#if IS_ENABLED(CONFIG_USB)
+static struct config_item *dovmgr_group_usb_make_item(
+		struct config_group *group, const char *name)
+{
+	return dovmgr_group_make_item(group, name, ITEM_USB);
+}
+#endif
+
+static void dovmgr_group_drop_item(struct config_group *group,
+		struct config_item *cfsitem)
+{
+	struct dovmgr_item *item = to_dovmgr_item(cfsitem);
+
+	switch (item->type) {
+#if IS_ENABLED(CONFIG_PCI)
+	case ITEM_PCI:
+		break;
+#endif
+#if IS_ENABLED(CONFIG_USB)
+	case ITEM_USB:
+		break;
+#endif
+	default:
+		break;
+	}
+	config_item_put(&item->item);
+}
+
+#if IS_ENABLED(CONFIG_PCI)
+static struct configfs_group_operations dovmgr_pci_group_ops = {
+	.make_item	= dovmgr_group_pci_make_item,
+	.drop_item	= dovmgr_group_drop_item,
+};
+
+static struct config_item_type dovmgr_pci_type = {
+	.ct_group_ops   = &dovmgr_pci_group_ops,
+	.ct_owner       = THIS_MODULE,
+};
+#endif
+
+#if IS_ENABLED(CONFIG_USB)
+static struct configfs_group_operations dovmgr_usb_group_ops = {
+	.make_item	= dovmgr_group_usb_make_item,
+	.drop_item	= dovmgr_group_drop_item,
+};
+
+static struct config_item_type dovmgr_usb_type = {
+	.ct_group_ops   = &dovmgr_usb_group_ops,
+	.ct_owner       = THIS_MODULE,
+};
+#endif
+
+static struct configfs_group_operations dovmgr_ops = {
+	/* empty - we don't allow anything to be created */
+};
+
+static struct config_item_type dovmgr_type = {
+	.ct_group_ops   = &dovmgr_ops,
+	.ct_owner       = THIS_MODULE,
+};
+
+struct config_group *dovmgr_def_groups[] = {
+#if IS_ENABLED(CONFIG_PCI)
+	&dovmgr_pci_group,
+#endif
+#if IS_ENABLED(CONFIG_USB)
+	&dovmgr_usb_group,
+#endif
+	NULL
+};
+
+static struct configfs_subsystem dovmgr_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_namebuf = "dovmgr",
+			.ci_type = &dovmgr_type,
+		},
+		.default_groups = dovmgr_def_groups,
+	},
+	.su_mutex = __MUTEX_INITIALIZER(dovmgr_subsys.su_mutex),
+};
+
+#if IS_ENABLED(CONFIG_PCI)
+static int pci_dev_instantiate(struct pci_dev *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device *bus_dev;
+	struct of_changeset cset;
+	struct device_node *np, *npb;
+	int ret;
+
+	npb = NULL;
+
+	/* already instantiated */
+	if (dev->of_node) {
+		pr_debug("%s: dev=%s of_node=%s\n", __func__,
+			kobject_name(&dev->kobj),
+			of_node_full_name(dev->of_node));
+		return 0;
+	}
+
+	bus_dev = &pdev->bus->dev;
+
+	pr_debug("%s: %s: %02x:%02x.%02x - node %s%s\n", __func__,
+			kobject_name(&dev->kobj),
+			pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+			bus_dev->of_node ? of_node_full_name(bus_dev->of_node) : "<NULL>",
+			pci_is_bridge(pdev) ? " bridge" : "");
+
+	/* to create the node, the bus must be present */
+	if (!bus_dev->of_node) {
+		pr_err("%s: No node for %s because no bus device node\n",
+			__func__, kobject_name(&dev->kobj));
+		return 0;
+	}
+
+	of_changeset_init(&cset);
+
+	np = of_changeset_create_device_node(&cset, bus_dev->of_node,
+		"%s/pci-%04x-%02x-%02x.%d",
+		of_node_full_name(bus_dev->of_node),
+		pci_domain_nr(pdev->bus), pdev->bus->number,
+		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+	if (IS_ERR(np)) {
+		ret = PTR_ERR(np);
+		goto out_cset_fail;
+	}
+
+	ret = of_changeset_add_property_stringf(&cset, np, "compatible",
+			"pciclass,%04x", (pdev->class >> 8) & 0xffffff);
+	if (ret != 0)
+		goto out_cset_fail;
+
+	ret = of_changeset_add_property_u32(&cset, np, "vendor",
+			pdev->vendor);
+	if (ret != 0)
+		goto out_cset_fail;
+
+	ret = of_changeset_add_property_u32(&cset, np, "device",
+			pdev->device);
+	if (ret != 0)
+		goto out_cset_fail;
+
+	ret = of_changeset_add_property_string(&cset, np, "status", "okay");
+	if (ret != 0)
+		goto out_cset_fail;
+
+	ret = of_changeset_add_property_bool(&cset, np, "auto-generated");
+	if (ret != 0)
+		goto out_cset_fail;
+
+	ret = of_changeset_attach_node(&cset, np);
+	if (ret != 0)
+		goto out_cset_fail;
+
+	/* are we creating a bridge; swell */
+	npb = NULL;
+	if (pci_is_bridge(pdev) && !pdev->subordinate->dev.of_node) {
+
+		pr_debug("%s: %s: bus->dev=%s subordinate=%s\n", __func__,
+			kobject_name(&dev->kobj),
+			kobject_name(&pdev->bus->dev.kobj),
+			kobject_name(&pdev->subordinate->dev.kobj));
+
+		npb = of_changeset_create_device_node(&cset, bus_dev->of_node,
+			"%s/pci-%04x-%02x",
+			of_node_full_name(bus_dev->of_node),
+			pci_domain_nr(pdev->subordinate),
+			pdev->subordinate->number);
+		if (IS_ERR(npb)) {
+			ret = PTR_ERR(npb);
+			goto out_cset_fail;
+		}
+
+		ret = of_changeset_add_property_string(&cset, npb, "compatible", "generic,pci-bus");
+		if (ret != 0)
+			goto out_cset_fail;
+
+		ret = of_changeset_add_property_string(&cset, npb, "device_type", "pci");
+		if (ret != 0)
+			goto out_cset_fail;
+
+		ret = of_changeset_add_property_string(&cset, npb, "status", "okay");
+		if (ret != 0)
+			goto out_cset_fail;
+
+		ret = of_changeset_add_property_bool(&cset, npb, "auto-generated");
+		if (ret != 0)
+			goto out_cset_fail;
+
+		ret = of_changeset_attach_node(&cset, npb);
+		if (ret != 0)
+			goto out_cset_fail;
+	}
+
+	ret = of_changeset_apply(&cset);
+	if (ret != 0)
+		goto out_cset_fail;
+
+	/* permanently commit */
+	of_changeset_destroy(&cset);
+
+	/* bind the node to the device */
+	dev->of_node = np;
+	ret = sysfs_create_link(&dev->kobj, &dev->of_node->kobj,
+			"of_node");
+	if (ret)
+		pr_warn("%s: %s Error %d creating of_node link\n",
+				__func__, kobject_name(&dev->kobj), ret);
+
+	if (npb) {
+		pdev->subordinate->dev.of_node = npb;
+		ret = sysfs_create_link(&pdev->subordinate->dev.kobj, &npb->kobj,
+				"of_node");
+		if (ret)
+			pr_warn("%s: %s Error %d creating of_node link\n",
+					__func__, kobject_name(&dev->kobj), ret);
+	}
+
+
+	return 0;
+
+out_cset_fail:
+	pr_err("%s: %s Failed to apply changeset (err=%d)\n", __func__,
+		kobject_name(&dev->kobj), ret);
+	of_changeset_destroy(&cset);
+	return ret;
+}
+
+static int pci_dev_uninstantiate(struct pci_dev *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np, *npb;
+	struct of_changeset cset;
+	int ret;
+
+	/* device node must exist */
+	np = dev->of_node;
+	if (!np)
+		return 0;
+
+	/* and the auto-generated property */
+	if (!of_property_read_bool(np, "auto-generated"))
+		return 0;
+
+	of_changeset_init(&cset);
+
+	ret = of_changeset_detach_node(&cset, np);
+	if (ret != 0)
+		goto out_cset_fail;
+
+	npb = NULL;
+	if (pci_is_bridge(pdev))
+		npb = pdev->subordinate->dev.of_node;
+
+	if (npb != NULL) {
+		ret = of_changeset_detach_node(&cset, npb);
+		if (ret != 0)
+			goto out_cset_fail;
+	}
+
+	ret = of_changeset_apply(&cset);
+	if (ret != 0)
+		goto out_cset_fail;
+
+	dev->of_node = NULL;
+	if (npb != NULL)
+		pdev->subordinate->dev.of_node = NULL;
+
+	pr_debug("%s: %s: %02x:%02x.%02x\n", __func__,
+			kobject_name(&dev->kobj),
+			pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+	/* TODO iterate over the properties and free */
+
+	return 0;
+
+out_cset_fail:
+	of_changeset_destroy(&cset);
+
+	return ret;
+}
+
+static int dovmgr_pci_notify(struct notifier_block *nb,
+				unsigned long action, void *arg)
+{
+	int ret;
+
+	if (action == BUS_NOTIFY_ADD_DEVICE)
+		pci_dev_instantiate(to_pci_dev(arg));
+
+	ret = dovmgr_notifier_action(&dovmgr_pci_group, action, arg,
+			dovmgr_pci_item_match, dovmgr_item_notify);
+
+	if (action == BUS_NOTIFY_REMOVED_DEVICE)
+		pci_dev_uninstantiate(to_pci_dev(arg));
+
+	return ret;
+}
+
+static struct notifier_block dovmgr_pci_notifier = {
+	.notifier_call = dovmgr_pci_notify,
+};
+
+static int pci_instantiate_iterator(struct device *dev, void *data)
+{
+	return pci_dev_instantiate(to_pci_dev(dev));
+}
+
+static int dovmgr_pci_init(void)
+{
+	int ret;
+
+	config_group_init_type_name(&dovmgr_pci_group, "pci", &dovmgr_pci_type);
+	ret = bus_register_notifier(&pci_bus_type, &dovmgr_pci_notifier);
+	if (ret != 0) {
+		pr_err("%s: bus_register_notifier() failed\n", __func__);
+		return ret;
+	}
+
+	ret = bus_for_each_dev(&pci_bus_type, NULL, NULL,
+			pci_instantiate_iterator);
+	if (ret != 0) {
+		pr_err("%s: bus_for_each_dev() failed\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void dovmgr_pci_cleanup(void)
+{
+	bus_unregister_notifier(&pci_bus_type, &dovmgr_pci_notifier);
+}
+#endif
+
+#if IS_ENABLED(CONFIG_USB)
+static int dovmgr_usb_notify(struct notifier_block *nb,
+				unsigned long action, void *arg)
+{
+	return dovmgr_notifier_action(&dovmgr_usb_group, action, arg,
+			dovmgr_usb_item_match, dovmgr_item_notify);
+}
+
+static struct notifier_block dovmgr_usb_notifier = {
+	.notifier_call = dovmgr_usb_notify,
+};
+
+static int dovmgr_usb_init(void)
+{
+	int ret;
+
+	config_group_init_type_name(&dovmgr_usb_group, "usb", &dovmgr_usb_type);
+	ret = bus_register_notifier(&usb_bus_type, &dovmgr_usb_notifier);
+	if (ret != 0) {
+		pr_err("%s: bus_register_notifier() failed\n", __func__);
+		return ret;
+	}
+	return 0;
+}
+
+static void dovmgr_usb_cleanup(void)
+{
+	bus_unregister_notifier(&usb_bus_type, &dovmgr_usb_notifier);
+}
+#endif
+
+static int __init dovmgr_init(void)
+{
+	int ret;
+
+	config_group_init(&dovmgr_subsys.su_group);
+#if IS_ENABLED(CONFIG_PCI)
+	configfs_add_default_group(&dovmgr_pci_group,
+			&dovmgr_subsys.su_group);
+#endif
+#if IS_ENABLED(CONFIG_USB)
+	configfs_add_default_group(&dovmgr_usb_group,
+			&dovmgr_subsys.su_group);
+#endif
+
+#if IS_ENABLED(CONFIG_PCI)
+	ret = dovmgr_pci_init();
+	if (ret != 0)
+		goto err_no_pci_init;
+#endif
+#if IS_ENABLED(CONFIG_USB)
+	ret = dovmgr_usb_init();
+	if (ret != 0)
+		goto err_no_usb_init;
+#endif
+
+	ret = configfs_register_subsystem(&dovmgr_subsys);
+	if (ret != 0) {
+		pr_err("%s: failed to register subsys\n", __func__);
+		goto err_no_configfs;
+	}
+	pr_info("%s: OK\n", __func__);
+	return 0;
+
+err_no_configfs:
+#if IS_ENABLED(CONFIG_USB)
+	dovmgr_usb_cleanup();
+err_no_usb_init:
+#endif
+#if IS_ENABLED(CONFIG_PCI)
+	dovmgr_pci_cleanup();
+err_no_pci_init:
+#endif
+	return ret;
+}
+late_initcall(dovmgr_init);
diff --git b/drivers/misc/tieqep.c b/drivers/misc/tieqep.c
new file mode 100644
index 0000000..a0652f9
--- /dev/null
+++ b/drivers/misc/tieqep.c
@@ -0,0 +1,766 @@
+/*
+ * TI eQEP driver for AM33xx devices
+ *
+ * Copyright (C) 2013 Nathaniel R. Lewis - http://teknoman117.wordpress.com/
+ * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * sysfs entries
+ *	 - position = absolute - current position; relative - last latched value
+ *	 - mode => 0 - absolute; 1 - relative
+ *	 - period => sampling period for the hardware
+ *	 - enable => 0 - eQEP disabled, 1 - eQEP enabled
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/input.h>
+
+/*
+ * Include the PWMSS subsystem headers, because this unit controls
+ * whether our clock source is enabled, and if eQEP is to be
+ * enabled, we need to start the clock
+ */
+#include "../pwm/pwm-tipwmss.h"
+
+
+/* eQEP register offsets from its base IO address */
+#define QPOSCNT		0x0000
+#define QPOSINIT	0x0004
+#define QPOSMAX		0x0008
+#define QPOSCMP		0x000C
+#define QPOSILAT	0x0010
+#define QPOSSLAT	0x0014
+#define QPOSLAT		0x0018
+#define QUTMR		0x001C
+#define QUPRD		0x0020
+#define QWDTMR		0x0024
+#define QWDPRD		0x0026
+#define QDECCTL		0x0028
+#define QEPCTL		0x002A
+#define QCAPCTL		0x002C
+#define QPOSCTL		0x002E
+#define QEINT		0x0030
+#define QFLG		0x0032
+#define QCLR		0x0034
+#define QFRC		0x0036
+#define QEPSTS		0x0038
+#define QCTMR		0x003A
+#define QCPRD		0x003C
+#define QCTMRLAT	0x003E
+#define QCPRDLAT	0x0040
+#define QREVID		0x005C
+
+#if 0	/* if you wanted another way to modify IP registers... */
+typedef volatile u32	REG32;
+typedef volatile u16	REG16;
+struct EQEP_REGS {
+	REG32	q_poscnt;		/*	0x00	position counter */
+	REG32	q_posinit;		/*	0x04	position counter initialization */
+	REG32	q_posmax;		/*	0x08	maximum position count */
+	REG32	q_poscmp;		/*	0x0C	position compare */
+	REG32	q_posilat;		/*	0x10	index position latch */
+	REG32	q_posslat;		/*	0x14	strobe position latch */
+	REG32	q_poslat;		/*	0x18	position counter latch */
+	REG32	q_utmr;			/*	0x1C	unit timer */
+	REG32	q_uprd;			/*	0x20	unit period */
+	REG16	q_wdtmr;		/*	0x24	watchdog timer */
+	REG16	q_wdprd;		/*	0x26	watchdog period */
+	REG16	q_decctl;		/*	0x28	decoder control */
+	REG16	q_epctl;		/*	0x2A	control register */
+	REG16	q_capctl;		/*	0x2C	capture control */
+	REG16	q_posctl;		/*	0x2E	position compare control */
+	REG16	q_eint;			/*	0x30	interrupt enable */
+	REG16	q_flg;			/*	0x32	interrupt flag */
+	REG16	q_clr;			/*	0x34	interrupt clear */
+	REG16	q_frc;			/*	0x36	interrupt force */
+	REG16	q_epsts;		/*	0x38	status */
+	REG16	q_ctmr;			/*	0x3A	capture timer */
+	REG16	q_cprd;			/*	0x3C	capture period */
+	REG16	q_ctmrlat;		/*	0x3E	capture timer latch */
+	REG16	q_prdlat;		/*	0x40	capture period latch */
+	char	q_fill1[0x5c-0x40];
+	REG32	q_revid;		/*	0x5C	revision id */
+};
+#endif
+
+
+/* Bits for the QDECTL register */
+#define QSRC1		(1 << 15)
+#define QSRC0		(1 << 14)
+#define SOEN		(1 << 13)
+#define SPSEL		(1 << 12)
+#define XCR		(1 << 11)
+#define SWAP		(1 << 10)
+#define IGATE		(1 << 9)
+#define QAP		(1 << 8)
+#define QBP		(1 << 7)
+#define QIP		(1 << 6)
+#define QSP		(1 << 5)
+
+/* Bits for the QEPCTL register */
+#define FREESOFT1	(1 << 15)
+#define FREESOFT0	(1 << 14)
+#define PCRM1		(1 << 13)
+#define PCRM0		(1 << 12)
+#define SEI1		(1 << 11)
+#define SEI0		(1 << 10)
+#define IEI1		(1 << 9)
+#define IEI0		(1 << 8)
+#define SWI		(1 << 7)
+#define SEL		(1 << 6)
+#define IEL1		(1 << 5)
+#define IEL0		(1 << 4)
+#define PHEN		(1 << 3)
+#define QCLM		(1 << 2)
+#define UTE		(1 << 1)
+#define WDE		(1 << 0)
+
+/* Bits for the QCAPCTL register */
+#define CEN		(1 << 15)
+#define CCPS2		(1 << 6)
+#define CCPS0		(1 << 5)
+#define CCPS1		(1 << 4)
+#define UPPS3		(1 << 3)
+#define UPPS2		(1 << 2)
+#define UPPS1		(1 << 1)
+#define UPPS0		(1 << 0)
+
+/* Bits for the QPOSCTL register */
+#define PCSHDW		(1 << 15)
+#define PCLOAD		(1 << 14)
+#define PCPOL		(1 << 13)
+#define PCE		(1 << 12)
+#define PCSPW11		(1 << 11)
+#define PCSPW10		(1 << 10)
+#define PCSPW9		(1 << 9)
+#define PCSPW8		(1 << 8)
+#define PCSPW7		(1 << 7)
+#define PCSPW6		(1 << 6)
+#define PCSPW5		(1 << 5)
+#define PCSPW4		(1 << 4)
+#define PCSPW3		(1 << 3)
+#define PCSPW2		(1 << 2)
+#define PCSPW1		(1 << 1)
+#define PCSPW0		(1 << 0)
+
+/* Bits for the interrupt registers */
+#define EQEP_INTERRUPT_MASK	0x0FFF
+#define UTOF			(1 << 11)
+
+/* Bits to control the clock in the PWMSS subsystem */
+#define PWMSS_EQEPCLK_EN	BIT(4)
+#define PWMSS_EQEPCLK_STOP_REQ	BIT(5)
+#define PWMSS_EQEPCLK_EN_ACK	BIT(4)
+
+/*
+ * Modes for the eQEP unit
+ *	Absolute - the position entry represents the current position of the encoder.
+ *		   Poll this value and it will be notified every period nanoseconds
+ *	Relative - the position entry represents the last latched position of the encoder
+ *		   This value is latched every period nanoseconds and the internal counter
+ *		   is subsequenty reset
+ */
+#define TIEQEP_MODE_ABSOLUTE	0
+#define TIEQEP_MODE_RELATIVE	1
+
+/* Structure defining the characteristics of the eQEP unit */
+struct eqep_chip
+{
+	/* Platform device for this eQEP unit */
+	struct platform_device *pdev;
+
+	/* Pointer to the base of the memory of the eQEP unit */
+	void __iomem	*mmio_base;
+
+	/* SYSCLKOUT to the eQEP unit */
+	u32		clk_rate;
+
+	/* IRQ for the eQEP unit */
+	u16		irq;
+
+	/* Mode of the eQEP unit */
+	u8		op_mode;
+
+	/* work stuct for the notify userspace work */
+	struct work_struct notify_work;
+
+	/* Backup for driver suspension */
+	u16		prior_qepctl;
+	u16		prior_qeint;
+};
+
+/* Notify userspace work */
+static void notify_handler(struct work_struct *work)
+{
+	/* Get a reference to the eQEP driver */
+	struct eqep_chip *eqep = container_of(work, struct eqep_chip, notify_work);
+
+	/* Notify the userspace */
+	sysfs_notify(&eqep->pdev->dev.kobj, NULL, "position");
+}
+
+/* eQEP Interrupt handler */
+static irqreturn_t eqep_irq_handler(int irq, void *dev_id)
+{
+	/* Get the instance information */
+	struct platform_device	*pdev = dev_id;
+	struct eqep_chip	*eqep = platform_get_drvdata(pdev);
+
+	/* Get the interrupt flags */
+	u16 iflags = readw(eqep->mmio_base + QFLG) & EQEP_INTERRUPT_MASK;
+
+	/* Check the interrupt source(s) */
+	if (iflags & UTOF) {
+		/* Handle the unit timer overflow interrupt by notifying any potential pollers */
+		schedule_work(&eqep->notify_work);
+	}
+
+	/* Clear interrupt flags (write back triggered flags to the clear register) */
+	writew(iflags, eqep->mmio_base + QCLR);
+
+	/* Return that the IRQ was handled successfully */
+	return IRQ_HANDLED;
+}
+
+/* Function to read whether the eQEP unit is enabled or disabled */
+static ssize_t eqep_get_enabled(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	/* Get the instance structure */
+	struct eqep_chip *eqep = dev_get_drvdata(dev);
+
+	/* Read the qep control register and mask all but the enabled bit */
+	u16 enabled = readw(eqep->mmio_base + QEPCTL) & PHEN;
+
+	/* Return the target in string format */
+	return sprintf(buf, "%u\n", (enabled) ? 1 : 0);
+}
+
+/* Function to set if the eQEP is enabled */
+static ssize_t eqep_set_enabled(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	/* Get the instance structure */
+	int	rc;
+	u16	val;
+	u8	enabled;
+	struct eqep_chip *eqep = dev_get_drvdata(dev);
+
+	/* Convert the input string to an 8 bit uint */
+	if ((rc = kstrtou8(buf, 0, &enabled)))
+		return rc;
+
+	/* Get the existing state of QEPCTL */
+	val = readw(eqep->mmio_base + QEPCTL);
+
+	/* If we passed a number that is not 0, enable the eQEP */
+	if (enabled)
+		/* Enable the eQEP (Set PHEN in QEPCTL) */
+		val |= PHEN;
+	else
+		/* Disable the eQEP (Clear PHEN in QEPCTL) */
+		val &= ~PHEN;
+
+	/* Write flags back to control register */
+	writew(val, eqep->mmio_base + QEPCTL);
+
+	/* Return buffer length consumed (all) */
+	return count;
+}
+
+/* Function to read the current position of the eQEP */
+static ssize_t eqep_get_position(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct eqep_chip *eqep = dev_get_drvdata(dev);
+
+	s32 position = 0;
+
+	if (eqep->op_mode == TIEQEP_MODE_ABSOLUTE) {
+		position = readl(eqep->mmio_base + QPOSCNT);
+	} else if (eqep->op_mode == TIEQEP_MODE_RELATIVE) {
+		/* in relative mode, use the last latched value of the eQEP hardware */
+		position = readl(eqep->mmio_base + QPOSLAT);
+		dev_dbg(dev, "get_position:0x%08x\n", position);
+	}
+
+	return sprintf(buf, "%d\n", position);
+}
+
+/* Function to set the position of the eQEP hardware */
+static ssize_t eqep_set_position(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	int rc;
+	s32 position;
+	struct eqep_chip *eqep = dev_get_drvdata(dev);
+
+	if ((rc = kstrtos32(buf, 0, &position)))
+		return rc;
+
+	/*
+	 * If we are in absolute mode, set the position of the encoder,
+	 * discard relative mode because thats pointless
+	 */
+	if (eqep->op_mode == TIEQEP_MODE_ABSOLUTE) {
+		/* If absolute mode, set the current value of the eQEP hardware */
+		writel(position, eqep->mmio_base + QPOSCNT);
+	}
+
+	/* Return buffer length consumed (all) */
+	return count;
+}
+
+/* Function to read the period of the unit time event timer */
+static ssize_t eqep_get_timer_period(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct eqep_chip *eqep = dev_get_drvdata(dev);
+	u64 period;
+
+	/* Convert from counts per interrupt back into period_ns */
+	period = readl(eqep->mmio_base + QUPRD);
+	period = period * NSEC_PER_SEC;
+	do_div(period, eqep->clk_rate);
+
+	/* Otherwise write out the data */
+	return sprintf(buf, "%llu\n", period);
+}
+
+/* Function to set the unit timer period.  0 = off, greater than zero sets the period */
+static ssize_t eqep_set_timer_period(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	int	rc;
+	u16	tmp;
+	u64	period;
+
+	struct eqep_chip *eqep = dev_get_drvdata(dev);
+
+	if ((rc = kstrtou64(buf, 0, &period)))
+		return rc;
+
+	/* Disable the unit timer before modifying its period register */
+	tmp = readw(eqep->mmio_base + QEPCTL);
+	tmp &= ~(UTE | QCLM);
+	writew(tmp, eqep->mmio_base + QEPCTL);
+
+	/* Zero the unit timer counter register */
+	writel(0, eqep->mmio_base + QUTMR);
+
+	/* If the timer is enabled (a non-zero period has been passed) */
+	if (period) {
+		/* update the period */
+		period = period * eqep->clk_rate;
+		do_div(period, NSEC_PER_SEC);
+
+		dev_dbg(dev, "eqep_set_timer_period:%llu\n", period);
+
+		writel(period, eqep->mmio_base + QUPRD);
+
+		/* Enable unit timer, and latch QPOSLAT to QPOSCNT on timer expiration */
+		tmp |= UTE | QCLM;
+		writew(tmp, eqep->mmio_base + QEPCTL);
+	}
+
+	return count;
+}
+
+/* Function to read the mode of the eQEP hardware */
+static ssize_t eqep_get_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct eqep_chip *eqep = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", eqep->op_mode);
+}
+
+/* Function to set the mode of the eQEP hardware */
+static ssize_t eqep_set_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	int 	rc;
+	u16 	val;
+	u8	tmp_mode;
+	struct eqep_chip *eqep = dev_get_drvdata(dev);
+
+	if ((rc = kstrtou8(buf, 0, &tmp_mode)))
+		return rc;
+
+	dev_dbg(dev, "eqep_set_mode:%d\n", tmp_mode);
+
+	val = readw(eqep->mmio_base + QEPCTL);
+
+	if (tmp_mode == TIEQEP_MODE_ABSOLUTE) {
+		/*
+		 * In absolute mode, don't reset the hardware based on time,
+		 * so disable the unit timer position reset (Set PCRM[1:0] = 0)
+		 */
+		val &= ~(PCRM1 | PCRM0);
+
+		eqep->op_mode = TIEQEP_MODE_ABSOLUTE;
+	} else if (tmp_mode == TIEQEP_MODE_RELATIVE) {
+		/*
+		 * In relative mode, latch the value of the eQEP hardware on the
+		 * overflow of the unit timer.	So enable the unit timer position reset
+		 * (Set PCRM[1:0] = 3)
+		 */
+		val |= PCRM1 | PCRM0;
+
+		eqep->op_mode = TIEQEP_MODE_RELATIVE;
+	}
+
+	writew(val, eqep->mmio_base + QEPCTL);
+
+	return count;
+}
+
+/* Bind read/write functions to sysfs entries */
+static DEVICE_ATTR(enabled,	0644, eqep_get_enabled,		eqep_set_enabled);
+static DEVICE_ATTR(position,	0644, eqep_get_position,	eqep_set_position);
+static DEVICE_ATTR(period,	0644, eqep_get_timer_period,	eqep_set_timer_period);
+static DEVICE_ATTR(mode,	0644, eqep_get_mode,		eqep_set_mode);
+
+/* Array holding all of the sysfs entries */
+static const struct attribute *eqep_attrs[] = {
+	&dev_attr_enabled.attr,
+	&dev_attr_position.attr,
+	&dev_attr_period.attr,
+	&dev_attr_mode.attr,
+	NULL,
+};
+
+/* Driver function group */
+static const struct attribute_group eqep_device_attr_group = {
+	.attrs = (struct attribute **) eqep_attrs,
+};
+
+/* Driver compatibility list */
+static struct of_device_id eqep_of_match[] =
+{
+	{ .compatible = "ti,am33xx-eqep" },
+	{ }
+};
+
+/* Register our compatibilities for device trees */
+MODULE_DEVICE_TABLE(of, eqep_of_match);
+
+/* Create an instance of the eQEP driver */
+static int eqep_probe(struct platform_device *pdev)
+{
+	struct resource	 *r;
+	struct clk	 *clk;
+	struct eqep_chip *eqep;
+	struct pinctrl	 *pinctrl;
+
+	int	ret;
+	u64	period;
+	u16	status;
+	u32	value;
+
+	dev_info(&pdev->dev, "ver. 1.0\n");
+
+	/* Select pins provided through the device tree */
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl))
+	{
+		dev_warn(&pdev->dev, "unable to select pin group\n");
+	}
+
+	/* Allocate a eqep_driver object */
+	eqep = devm_kzalloc(&pdev->dev, sizeof(struct eqep_chip), GFP_KERNEL);
+	if (!eqep) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	/* Get a handle to the system clock object */
+	clk = devm_clk_get(&pdev->dev, "fck");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "failed to get clock\n");
+		return PTR_ERR(clk);
+	}
+
+	/* Get the frequency of the system clock */
+	eqep->clk_rate = clk_get_rate(clk);
+	if (!eqep->clk_rate) {
+		dev_err(&pdev->dev, "failed to get clock rate\n");
+		return -EINVAL;
+	}
+
+	/* Get a resource containing the IRQ for this eQEP controller */
+	r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (unlikely(!r)) {
+		dev_err(&pdev->dev, "Invalid IRQ resource\n");
+		return -ENODEV;
+	}
+
+	/* Store the irq */
+	eqep->irq = r->start;
+
+	/* Get a resource containing the requested (from DT) memory address and range of eQEP controller */
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "no memory resource defined\n");
+		return -ENODEV;
+	}
+
+	/* Remap the eQEP controller memory into our own memory space */
+	eqep->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(eqep->mmio_base))
+		return PTR_ERR(eqep->mmio_base);
+
+	/* Store the platform device in our eQEP data structure for later usage */
+	eqep->pdev = pdev;
+
+	/* Subscribe to the eQEP interrupt */
+	if (request_irq(eqep->irq, eqep_irq_handler, IRQF_IRQPOLL, "eqep_interrupt", pdev))
+	{
+		dev_err(&pdev->dev, "unable to request irq for eQEP\n");
+		return -ENODEV;
+	}
+
+	/* Register controls to sysfs */
+	if (sysfs_create_group(&pdev->dev.kobj, &eqep_device_attr_group))
+	{
+		dev_err(&pdev->dev, "sysfs creation failed\n");
+		return -EINVAL;
+	}
+
+	/* set QDECCTL */
+	status = 0;	/* default to Quadrature count mode, QSRC1 & QSRC0 = 0 */
+
+	/* set QSRC1 & QSRC0 bits, one of 4 count_modes. */
+	if (!of_property_read_u32(pdev->dev.of_node, "count_mode", &value) && value <= 3) {
+		status |= value << 14;
+
+		/*
+		 * in count up or count down mode, count on rising edge only
+		 * not on both edges.
+		 */
+		if (value >= 2)
+			status |= XCR;
+	}
+	dev_dbg(&pdev->dev, "count_mode:%d\n", value);
+
+	/* Should we invert the qa input */
+	if (!of_property_read_u32(pdev->dev.of_node, "invert_qa", &value))
+		status = value ? status | QAP : status & ~QAP;
+	dev_dbg(&pdev->dev, "invert_qa:%d\n", value);
+
+	/* Should we invert the qb input */
+	if (!of_property_read_u32(pdev->dev.of_node, "invert_qb", &value))
+		status = value ? status | QBP : status & ~QBP;
+	dev_dbg(&pdev->dev, "invert_qb:%d\n", value);
+
+	/* Should we invert the index input */
+	if (!of_property_read_u32(pdev->dev.of_node, "invert_qi", &value))
+		status = value ? status | QIP : status & ~QIP;
+	dev_dbg(&pdev->dev, "invert_qi:%d\n", value);
+
+	/* Should we invert the strobe input */
+	if (!of_property_read_u32(pdev->dev.of_node, "invert_qs", &value))
+		status = value ? status | QSP : status & ~QSP;
+	dev_dbg(&pdev->dev, "invert_qs:%d\n", value);
+
+	/* Should we swap the cha and chb inputs */
+	if (!of_property_read_u32(pdev->dev.of_node, "swap_inputs", &value))
+		status = value ? status | SWAP : status & ~SWAP;
+	dev_dbg(&pdev->dev, "swap_inputs:%d\n", value);
+
+	dev_dbg(&pdev->dev, "QDECCTL:0x%04x\n", status);
+
+	/* Write the decoder control settings back to the control register */
+	writew(status, eqep->mmio_base + QDECCTL);
+
+	writel( 0, eqep->mmio_base + QPOSINIT);
+	writel(~0, eqep->mmio_base + QPOSMAX);
+	writel( 0, eqep->mmio_base + QPOSCNT);
+
+	dev_dbg(&pdev->dev, "QPOSINIT:0x%08x\n", readl(eqep->mmio_base + QPOSINIT));
+	dev_dbg(&pdev->dev, "QPOSMAX:0x%08x\n", readl(eqep->mmio_base + QPOSMAX));
+	dev_dbg(&pdev->dev, "QPOSCNT:0x%08x\n", readl(eqep->mmio_base + QPOSCNT));
+
+	status = UTOF;		/* Enable Unit Time Period interrupt. */
+	if (!of_property_read_u32(pdev->dev.of_node, "omit_interrupt", &value) && value) {
+		status = 0;	/* no interrupt */
+	}
+	writew(status, eqep->mmio_base + QEINT);
+	dev_dbg(&pdev->dev, "omit_interrupt:%d\n", value);
+	dev_dbg(&pdev->dev, "QEINT:0x%04x\n", status);
+
+	/* Calculate the timer ticks per second */
+	period = 1000000000;
+	period = period * eqep->clk_rate;
+	do_div(period, NSEC_PER_SEC);
+
+	/* Set this period into the unit timer period register */
+	writel(period, eqep->mmio_base + QUPRD);
+	dev_dbg(&pdev->dev, "QUPRD:0x%08x\n", (u32) period);
+
+	/*
+	 * Enable the eQEP with basic position counting turned on
+	 * PHEN - Quadrature position counter enable bit
+	 * UTE	- unit timer enable
+	 * QCLM - latch QPOSLAT to QPOSCNT upon unit timer overflow
+	 * IEL0 - Latch QPOSILAT on index signal.  Rising or falling, IEL[1:0] = 0 is reserved
+	 * SWI	- Software initialization of position count register, i.e. set QPOSCNT <= QPOSINIT,
+	 *  but this bit was not being reset by hardware as advertised in TRM,
+	 *  (so omit & clear QPOSCNT manually elsewhere?)
+	 */
+	status = PHEN | UTE | QCLM | IEL0 | SWI;
+	writew(status, eqep->mmio_base + QEPCTL);
+	dev_dbg(&pdev->dev, "QEPCTL:0x%04x write\n", status);
+	dev_dbg(&pdev->dev, "QEPCTL:0x%04x read\n", readw(eqep->mmio_base + QEPCTL));
+
+	/* We default to absolute mode */
+	eqep->op_mode = TIEQEP_MODE_ABSOLUTE;
+
+	/* Enable the power management runtime */
+	pm_runtime_enable(&pdev->dev);
+
+	/* Increment the device usage count and run pm_runtime_resume() */
+	pm_runtime_get_sync(&pdev->dev);
+
+	/* Enable the clock to the eQEP unit */
+	status = pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EQEPCLK_EN);
+
+	/* If we failed to enable the clocks, fail out */
+	if (!(status & PWMSS_EQEPCLK_EN_ACK)) {
+		dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
+		ret = -EINVAL;
+		goto pwmss_clk_failure;
+	}
+
+	/* Initialize the notify work struture */
+	INIT_WORK(&eqep->notify_work, notify_handler);
+
+	/* Decrement the device usage count (twice) and run pm_runtime_idle() if zero */
+	pm_runtime_put_sync(&pdev->dev);
+
+	/* Set the platform driver data to the data object we've been creating for the eQEP unit */
+	platform_set_drvdata(pdev, eqep);
+
+	/* Success! */
+	dev_dbg(&pdev->dev, "irq:%d, clk_rate:%u\n", eqep->irq, eqep->clk_rate);
+	return 0;
+
+	/* If a failure occurred, stop the runtime power management */
+pwmss_clk_failure:
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	return ret;
+}
+
+/* Remove an instance of the eQEP driver */
+static int eqep_remove(struct platform_device *pdev)
+{
+	/* Get the eQEP driver data from the platform device structure */
+	struct eqep_chip *eqep = platform_get_drvdata(pdev);
+
+	/* Cancel work */
+	cancel_work_sync(&eqep->notify_work);
+
+	/* Unmap from sysfs */
+	sysfs_remove_group(&pdev->dev.kobj, &eqep_device_attr_group);
+
+	/* Release important assets */
+	free_irq(eqep->irq, pdev);
+
+	/* Increment the device usage count and run pm_runtime_resume() */
+	pm_runtime_get_sync(&pdev->dev);
+
+	/* Disable the eQEP clock */
+	pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EQEPCLK_STOP_REQ);
+
+	/* Decrement the device usage count (twice) and run pm_runtime_idle() if zero */
+	pm_runtime_put_sync(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
+
+	/* Disable the runtime power management of this device */
+	pm_runtime_disable(&pdev->dev);
+
+	/* Return success */
+	return 0;
+}
+
+/* Power management suspend device */
+static int eqep_suspend(struct device *dev)
+{
+	/* Get the eqep driver information */
+	struct eqep_chip   *eqep = dev_get_drvdata(dev);
+	u16					tmp;
+
+	/* Shut down interrupts */
+	eqep->prior_qeint = readw(eqep->mmio_base + QEINT);
+	tmp = eqep->prior_qeint & ~UTOF;
+	writew(tmp, eqep->mmio_base + QEINT);
+
+	/* Get the existing state of QEPCTL */
+	eqep->prior_qepctl = readw(eqep->mmio_base + QEPCTL);
+
+	/* Disable eQEP controller */
+	writew(eqep->prior_qepctl & ~PHEN, eqep->mmio_base + QEPCTL);
+
+	/* Decrement the device usage count and run pm_runtime_idle() if zero */
+	pm_runtime_put_sync(dev);
+
+	/* Return success */
+	return 0;
+}
+
+/* Power management wake device back up */
+static int eqep_resume(struct device *dev)
+{
+	/* Get the eqep driver information */
+	struct eqep_chip *eqep = dev_get_drvdata(dev);
+
+	/* Restore interrupt enabled register */
+	writew(eqep->prior_qeint, eqep->mmio_base + QEINT);
+
+	/* Restore prior qep control register */
+	writew(eqep->prior_qepctl, eqep->mmio_base + QEPCTL);
+
+	/* Increment the device usage count and run pm_runtime_resume() */
+	pm_runtime_get_sync(dev);
+
+	/* Success */
+	return 0;
+}
+
+/* create pm functions object */
+static SIMPLE_DEV_PM_OPS(eqep_pm_ops, eqep_suspend, eqep_resume);
+
+/* Platform driver information */
+static struct platform_driver eqep_driver = {
+	.driver = {
+		.name	= "eqep",
+		.owner	= THIS_MODULE,
+		.pm	= &eqep_pm_ops,
+		.of_match_table = eqep_of_match,
+	},
+	.probe = eqep_probe,
+	.remove = eqep_remove,
+};
+
+/* Register this platform driver */
+module_platform_driver(eqep_driver);
+
+/* Module information */
+MODULE_DESCRIPTION("TI eQEP driver");
+MODULE_AUTHOR("Nathaniel R. Lewis");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index 4e7c9b9..c6ac38b 100644
--- a/drivers/net/ethernet/ti/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
@@ -102,6 +102,10 @@ struct davinci_mdio_data {
 	bool		skip_scan;
 };
 
+#if IS_ENABLED(CONFIG_OF)
+static void davinci_mdio_update_dt_from_phymask(u32 phy_mask);
+#endif
+
 static void __davinci_mdio_reset(struct davinci_mdio_data *data)
 {
 	u32 mdio_in, div, mdio_out_khz, access_time;
@@ -158,6 +162,12 @@ static int davinci_mdio_reset(struct mii_bus *bus)
 		/* restrict mdio bus to live phys only */
 		dev_info(data->dev, "detected phy mask %x\n", ~phy_mask);
 		phy_mask = ~phy_mask;
+
+		#if IS_ENABLED(CONFIG_OF)
+		if (of_machine_is_compatible("ti,am335x-bone"))
+			davinci_mdio_update_dt_from_phymask(phy_mask);
+		#endif
+
 	} else {
 		/* desperately scan all phys */
 		dev_warn(data->dev, "no live phy, scanning all\n");
@@ -318,6 +328,93 @@ static int davinci_mdio_probe_dt(struct mdio_platform_data *data,
 
 	return 0;
 }
+static void davinci_mdio_update_dt_from_phymask(u32 phy_mask)
+{
+	int i, len, skip;
+	u32 addr;
+	__be32 *old_phy_p, *phy_id_p;
+	struct property *phy_id_property = NULL;
+	struct device_node *node_p, *slave_p;
+
+	addr = 0;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++) {
+		if ((phy_mask & (1 << i)) == 0) {
+			addr = (u32) i;
+		break;
+		}
+	}
+
+	for_each_compatible_node(node_p, NULL, "ti,cpsw") {
+		for_each_node_by_name(slave_p, "slave") {
+
+#if IS_ENABLED(CONFIG_OF_OVERLAY)
+			skip = 1;
+			// Hack, the overlay fixup "slave" doesn't have phy-mode...
+			old_phy_p = (__be32 *) of_get_property(slave_p, "phy-mode", &len);
+
+			if (len != (sizeof(__be32 *) * 1))
+			{
+				skip = 0;
+			}
+
+			if (skip) {
+#endif
+
+			old_phy_p = (__be32 *) of_get_property(slave_p, "phy_id", &len);
+
+			if (len != (sizeof(__be32 *) * 2))
+				goto err_out;
+
+			if (old_phy_p) {
+
+				phy_id_property = kzalloc(sizeof(*phy_id_property), GFP_KERNEL);
+
+				if (! phy_id_property)
+					goto err_out;
+
+				phy_id_property->length = len;
+				phy_id_property->name = kstrdup("phy_id", GFP_KERNEL);
+				phy_id_property->value = kzalloc(len, GFP_KERNEL);
+
+				if (! phy_id_property->name)
+					goto err_out;
+
+				if (! phy_id_property->value)
+					goto err_out;
+
+				memcpy(phy_id_property->value, old_phy_p, len);
+
+				phy_id_p = (__be32 *) phy_id_property->value + 1;
+
+				*phy_id_p = cpu_to_be32(addr);
+
+				of_update_property(slave_p, phy_id_property);
+				pr_info("davinci_mdio: dt: updated phy_id[%d] from phy_mask[%x]\n", addr, phy_mask);
+
+				++addr;
+			}
+#if IS_ENABLED(CONFIG_OF_OVERLAY)
+		}
+#endif
+		}
+	}
+
+	return;
+
+err_out:
+
+	if (phy_id_property) {
+		if (phy_id_property->name)
+			kfree(phy_id_property->name);
+
+	if (phy_id_property->value)
+		kfree(phy_id_property->value);
+
+	if (phy_id_property)
+		kfree(phy_id_property);
+	}
+}
 #endif
 
 static int davinci_mdio_probe(struct platform_device *pdev)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index e2a4841..59efeda 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -112,4 +112,11 @@ config OF_OVERLAY
 	  While this option is selected automatically when needed, you can
 	  enable it manually to improve device tree unit test coverage.
 
+config OF_CONFIGFS
+	bool "Device Tree Overlay ConfigFS interface"
+	select CONFIGFS_FS
+	depends on OF_OVERLAY
+	help
+	  Enable a simple user-space driven DT overlay interface.
+
 endif # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 156c072..46c8f57 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,4 +1,5 @@
 obj-y = base.o device.o platform.o
+obj-$(CONFIG_OF_CONFIGFS) += configfs.o
 obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
 obj-$(CONFIG_OF_FLATTREE) += fdt.o
 obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
index b299de2..770cb95 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/proc_fs.h>
+#include <linux/rhashtable.h>
 
 #include "of_private.h"
 
@@ -41,6 +42,16 @@ static const char *of_stdout_options;
 
 struct kset *of_kset;
 
+const struct rhashtable_params of_phandle_ht_params = {
+	.key_offset = offsetof(struct device_node, phandle), /* base offset */
+	.key_len = sizeof(phandle),
+	.head_offset = offsetof(struct device_node, ht_node),
+	.automatic_shrinking = true,
+};
+
+struct rhashtable of_phandle_ht;
+bool of_phandle_ht_initialized;
+
 /*
  * Used to protect the of_aliases, to hold off addition of nodes to sysfs.
  * This mutex must be held whenever modifications are being made to the
@@ -156,12 +167,18 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp)
 	return rc;
 }
 
-int __of_attach_node_sysfs(struct device_node *np)
+int __of_attach_node_post(struct device_node *np)
 {
 	const char *name;
 	struct property *pp;
 	int rc;
 
+	if (of_phandle_ht_available()) {
+		rc = of_phandle_ht_insert(np);
+		WARN(rc, "insert to phandle hash fail @%s\n",
+				of_node_full_name(np));
+	}
+
 	if (!IS_ENABLED(CONFIG_SYSFS))
 		return 0;
 
@@ -192,6 +209,14 @@ int __of_attach_node_sysfs(struct device_node *np)
 void __init of_core_init(void)
 {
 	struct device_node *np;
+	int ret;
+
+	ret = rhashtable_init(&of_phandle_ht, &of_phandle_ht_params);
+	if (ret) {
+		pr_warn("devicetree: Failed to initialize hashtable\n");
+		return;
+	}
+	of_phandle_ht_initialized = 1;
 
 	/* Create the kset, and register existing nodes */
 	mutex_lock(&of_mutex);
@@ -202,12 +227,16 @@ void __init of_core_init(void)
 		return;
 	}
 	for_each_of_allnodes(np)
-		__of_attach_node_sysfs(np);
+		__of_attach_node_post(np);
 	mutex_unlock(&of_mutex);
 
 	/* Symlink in /proc as required by userspace ABI */
 	if (of_root)
 		proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
+
+	ret = of_overlay_init();
+	if (ret != 0)
+		pr_warn("of_init: of_overlay_init failed!\n");
 }
 
 static struct property *__of_find_property(const struct device_node *np,
@@ -1068,9 +1097,14 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 		return NULL;
 
 	raw_spin_lock_irqsave(&devtree_lock, flags);
-	for_each_of_allnodes(np)
-		if (np->phandle == handle)
-			break;
+	/* when we're ready use the hash table */
+	if (of_phandle_ht_available() && !in_interrupt())
+		np = of_phandle_ht_lookup(handle);
+	else { /* fallback */
+		for_each_of_allnodes(np)
+			if (np->phandle == handle)
+				break;
+	}
 	of_node_get(np);
 	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 	return np;
diff --git b/drivers/of/configfs.c b/drivers/of/configfs.c
new file mode 100644
index 0000000..fa73b98
--- /dev/null
+++ b/drivers/of/configfs.c
@@ -0,0 +1,307 @@
+/*
+ * Configfs entries for device-tree
+ *
+ * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
+ *
+ * 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.
+ */
+#include <linux/ctype.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/spinlock.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/configfs.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/limits.h>
+#include <linux/file.h>
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+
+#include "of_private.h"
+
+struct cfs_overlay_item {
+	struct config_item	item;
+
+	char			path[PATH_MAX];
+
+	const struct firmware	*fw;
+	struct device_node	*overlay;
+	int			ov_id;
+
+	void			*dtbo;
+	int			dtbo_size;
+};
+
+static int create_overlay(struct cfs_overlay_item *overlay, void *blob)
+{
+	int err;
+
+	/* unflatten the tree */
+	of_fdt_unflatten_tree(blob, &overlay->overlay);
+	if (overlay->overlay == NULL) {
+		pr_err("%s: failed to unflatten tree\n", __func__);
+		err = -EINVAL;
+		goto out_err;
+	}
+	pr_debug("%s: unflattened OK\n", __func__);
+
+	/* mark it as detached */
+	of_node_set_flag(overlay->overlay, OF_DETACHED);
+
+	/* perform resolution */
+	err = of_resolve_phandles(overlay->overlay);
+	if (err != 0) {
+		pr_err("%s: Failed to resolve tree\n", __func__);
+		goto out_err;
+	}
+	pr_debug("%s: resolved OK\n", __func__);
+
+	err = of_overlay_create(overlay->overlay);
+	if (err < 0) {
+		pr_err("%s: Failed to create overlay (err=%d)\n",
+				__func__, err);
+		goto out_err;
+	}
+	overlay->ov_id = err;
+
+out_err:
+	return err;
+}
+
+static inline struct cfs_overlay_item *to_cfs_overlay_item(
+		struct config_item *item)
+{
+	return item ? container_of(item, struct cfs_overlay_item, item) : NULL;
+}
+
+static ssize_t cfs_overlay_item_path_show(struct config_item *item, char *page)
+{
+	return sprintf(page, "%s\n", to_cfs_overlay_item(item)->path);
+}
+
+static ssize_t cfs_overlay_item_path_store(struct config_item *item,
+		const char *page, size_t count)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+	const char *p = page;
+	char *s;
+	int err;
+
+	/* if it's set do not allow changes */
+	if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
+		return -EPERM;
+
+	/* copy to path buffer (and make sure it's always zero terminated */
+	count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p);
+	overlay->path[sizeof(overlay->path) - 1] = '\0';
+
+	/* strip trailing newlines */
+	s = overlay->path + strlen(overlay->path);
+	while (s > overlay->path && *--s == '\n')
+		*s = '\0';
+
+	pr_debug("%s: path is '%s'\n", __func__, overlay->path);
+
+	err = request_firmware(&overlay->fw, overlay->path, NULL);
+	if (err != 0)
+		goto out_err;
+
+	err = create_overlay(overlay, (void *)overlay->fw->data);
+	if (err < 0)
+		goto out_err;
+
+	return count;
+
+out_err:
+
+	release_firmware(overlay->fw);
+	overlay->fw = NULL;
+
+	overlay->path[0] = '\0';
+	return err;
+}
+
+static ssize_t cfs_overlay_item_status_show(struct config_item *item,
+		char *page)
+{
+	return sprintf(page, "%s\n", to_cfs_overlay_item(item)->ov_id >= 0 ?
+					"applied" : "unapplied");
+}
+
+CONFIGFS_ATTR(cfs_overlay_item_, path);
+CONFIGFS_ATTR_RO(cfs_overlay_item_, status);
+
+static struct configfs_attribute *cfs_overlay_attrs[] = {
+	&cfs_overlay_item_attr_path,
+	&cfs_overlay_item_attr_status,
+	NULL,
+};
+
+ssize_t cfs_overlay_item_dtbo_read(struct config_item *item, void *buf,
+		size_t max_count)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+	pr_debug("%s: buf=%p max_count=%u\n", __func__,
+			buf, max_count);
+
+	if (overlay->dtbo == NULL)
+		return 0;
+
+	/* copy if buffer provided */
+	if (buf != NULL) {
+		/* the buffer must be large enough */
+		if (overlay->dtbo_size > max_count)
+			return -ENOSPC;
+
+		memcpy(buf, overlay->dtbo, overlay->dtbo_size);
+	}
+
+	return overlay->dtbo_size;
+}
+
+ssize_t cfs_overlay_item_dtbo_write(struct config_item *item, const void *buf,
+		size_t count)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+	int err;
+
+	/* if it's set do not allow changes */
+	if (overlay->path[0] != '\0' || overlay->dtbo_size > 0)
+		return -EPERM;
+
+	/* copy the contents */
+	overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
+	if (overlay->dtbo == NULL)
+		return -ENOMEM;
+
+	overlay->dtbo_size = count;
+
+	err = create_overlay(overlay, overlay->dtbo);
+	if (err < 0)
+		goto out_err;
+
+	return count;
+
+out_err:
+	kfree(overlay->dtbo);
+	overlay->dtbo = NULL;
+	overlay->dtbo_size = 0;
+
+	return err;
+}
+
+CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M);
+
+static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = {
+	&cfs_overlay_item_attr_dtbo,
+	NULL,
+};
+
+static void cfs_overlay_release(struct config_item *item)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+	if (overlay->ov_id >= 0)
+		of_overlay_destroy(overlay->ov_id);
+	if (overlay->fw)
+		release_firmware(overlay->fw);
+	/* kfree with NULL is safe */
+	kfree(overlay->dtbo);
+	kfree(overlay);
+}
+
+static struct configfs_item_operations cfs_overlay_item_ops = {
+	.release		= cfs_overlay_release,
+};
+
+static struct config_item_type cfs_overlay_type = {
+	.ct_item_ops	= &cfs_overlay_item_ops,
+	.ct_attrs	= cfs_overlay_attrs,
+	.ct_bin_attrs	= cfs_overlay_bin_attrs,
+	.ct_owner	= THIS_MODULE,
+};
+
+static struct config_item *cfs_overlay_group_make_item(
+		struct config_group *group, const char *name)
+{
+	struct cfs_overlay_item *overlay;
+
+	overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
+	if (!overlay)
+		return ERR_PTR(-ENOMEM);
+	overlay->ov_id = -1;
+
+	config_item_init_type_name(&overlay->item, name, &cfs_overlay_type);
+	return &overlay->item;
+}
+
+static void cfs_overlay_group_drop_item(struct config_group *group,
+		struct config_item *item)
+{
+	struct cfs_overlay_item *overlay = to_cfs_overlay_item(item);
+
+	config_item_put(&overlay->item);
+}
+
+static struct configfs_group_operations overlays_ops = {
+	.make_item	= cfs_overlay_group_make_item,
+	.drop_item	= cfs_overlay_group_drop_item,
+};
+
+static struct config_item_type overlays_type = {
+	.ct_group_ops   = &overlays_ops,
+	.ct_owner       = THIS_MODULE,
+};
+
+static struct configfs_group_operations of_cfs_ops = {
+	/* empty - we don't allow anything to be created */
+};
+
+static struct config_item_type of_cfs_type = {
+	.ct_group_ops   = &of_cfs_ops,
+	.ct_owner       = THIS_MODULE,
+};
+
+struct config_group of_cfs_overlay_group;
+
+static struct configfs_subsystem of_cfs_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_namebuf = "device-tree",
+			.ci_type = &of_cfs_type,
+		},
+	},
+	.su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex),
+};
+
+static int __init of_cfs_init(void)
+{
+	int ret;
+
+	pr_info("%s\n", __func__);
+
+	config_group_init(&of_cfs_subsys.su_group);
+	config_group_init_type_name(&of_cfs_overlay_group, "overlays",
+			&overlays_type);
+	configfs_add_default_group(&of_cfs_overlay_group,
+			&of_cfs_subsys.su_group);
+
+	ret = configfs_register_subsystem(&of_cfs_subsys);
+	if (ret != 0) {
+		pr_err("%s: failed to register subsys\n", __func__);
+		goto out;
+	}
+	pr_info("%s: OK\n", __func__);
+out:
+	return ret;
+}
+late_initcall(of_cfs_init);
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index c647bd1..24af842 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/proc_fs.h>
+#include <linux/rhashtable.h>
 
 #include "of_private.h"
 
@@ -41,9 +42,16 @@ void of_node_put(struct device_node *node)
 }
 EXPORT_SYMBOL(of_node_put);
 
-void __of_detach_node_sysfs(struct device_node *np)
+void __of_detach_node_post(struct device_node *np)
 {
 	struct property *pp;
+	int rc;
+
+	if (of_phandle_ht_available()) {
+		rc = of_phandle_ht_remove(np);
+		WARN(rc, "remove from phandle hash fail @%s\n",
+				of_node_full_name(np));
+	}
 
 	if (!IS_ENABLED(CONFIG_SYSFS))
 		return;
@@ -251,7 +259,7 @@ int of_attach_node(struct device_node *np)
 	__of_attach_node(np);
 	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
-	__of_attach_node_sysfs(np);
+	__of_attach_node_post(np);
 	mutex_unlock(&of_mutex);
 
 	of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, &rd);
@@ -304,7 +312,7 @@ int of_detach_node(struct device_node *np)
 	__of_detach_node(np);
 	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
-	__of_detach_node_sysfs(np);
+	__of_detach_node_post(np);
 	mutex_unlock(&of_mutex);
 
 	of_reconfig_notify(OF_RECONFIG_DETACH_NODE, &rd);
@@ -394,8 +402,9 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
 }
 
 /**
- * __of_node_dup() - Duplicate or create an empty device node dynamically.
- * @fmt: Format string (plus vargs) for new full name of the device node
+ * __of_node_dupv() - Duplicate or create an empty device node dynamically.
+ * @fmt: Format string for new full name of the device node
+ * @vargs: va_list containing the arugments for the node full name
  *
  * Create an device tree node, either by duplicating an empty node or by allocating
  * an empty one suitable for further modification.  The node data are
@@ -403,17 +412,15 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
  * OF_DETACHED bits set. Returns the newly allocated node or NULL on out of
  * memory error.
  */
-struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...)
+struct device_node *__of_node_dupv(const struct device_node *np,
+		const char *fmt, va_list vargs)
 {
-	va_list vargs;
 	struct device_node *node;
 
 	node = kzalloc(sizeof(*node), GFP_KERNEL);
 	if (!node)
 		return NULL;
-	va_start(vargs, fmt);
 	node->full_name = kvasprintf(GFP_KERNEL, fmt, vargs);
-	va_end(vargs);
 	if (!node->full_name) {
 		kfree(node);
 		return NULL;
@@ -445,6 +452,24 @@ struct device_node *__of_node_dup(const struct device_node *np, const char *fmt,
 	return NULL;
 }
 
+/**
+ * __of_node_dup() - Duplicate or create an empty device node dynamically.
+ * @fmt: Format string (plus vargs) for new full name of the device node
+ *
+ * See: __of_node_dupv()
+ */
+struct device_node *__of_node_dup(const struct device_node *np,
+		const char *fmt, ...)
+{
+	va_list vargs;
+	struct device_node *node;
+
+	va_start(vargs, fmt);
+	node = __of_node_dupv(np, fmt, vargs);
+	va_end(vargs);
+	return node;
+}
+
 static void __of_changeset_entry_destroy(struct of_changeset_entry *ce)
 {
 	of_node_put(ce->np);
@@ -606,10 +631,10 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
 
 	switch (ce->action) {
 	case OF_RECONFIG_ATTACH_NODE:
-		__of_attach_node_sysfs(ce->np);
+		__of_attach_node_post(ce->np);
 		break;
 	case OF_RECONFIG_DETACH_NODE:
-		__of_detach_node_sysfs(ce->np);
+		__of_detach_node_post(ce->np);
 		break;
 	case OF_RECONFIG_ADD_PROPERTY:
 		/* ignore duplicate names */
@@ -806,3 +831,253 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(of_changeset_action);
+
+/* changeset helpers */
+
+/**
+ * of_changeset_create_device_node - Create an empty device node
+ *
+ * @ocs:	changeset pointer
+ * @parent:	parent device node
+ * @fmt:	format string for the node's full_name
+ * @args:	argument list for the format string
+ *
+ * Create an empty device node, marking it as detached and allocated.
+ *
+ * Returns a device node on success, an error encoded pointer otherwise
+ */
+struct device_node *of_changeset_create_device_nodev(
+	struct of_changeset *ocs, struct device_node *parent,
+	const char *fmt, va_list vargs)
+{
+	struct device_node *node;
+
+	node = __of_node_dupv(NULL, fmt, vargs);
+	if (!node)
+		return ERR_PTR(-ENOMEM);
+
+	node->parent = parent;
+	return node;
+}
+
+/**
+ * of_changeset_create_device_node - Create an empty device node
+ *
+ * @ocs:	changeset pointer
+ * @parent:	parent device node
+ * @fmt:	Format string for the node's full_name
+ * ...		Arguments
+ *
+ * Create an empty device node, marking it as detached and allocated.
+ *
+ * Returns a device node on success, an error encoded pointer otherwise
+ */
+struct device_node *of_changeset_create_device_node(
+	struct of_changeset *ocs, struct device_node *parent,
+	const char *fmt, ...)
+{
+	va_list vargs;
+	struct device_node *node;
+
+	va_start(vargs, fmt);
+	node = of_changeset_create_device_nodev(ocs, parent, fmt, vargs);
+	va_end(vargs);
+	return node;
+}
+
+/**
+ * of_changeset_add_property_copy - Create a new property copying name & value
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @value:	pointer to the value data
+ * @length:	length of the value in bytes
+ *
+ * Adds a property to the changeset by making copies of the name & value
+ * entries.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int of_changeset_add_property_copy(struct of_changeset *ocs,
+		struct device_node *np, const char *name, const void *value,
+		int length)
+{
+	struct property *prop;
+	char *new_name;
+	void *new_value;
+	int ret = -ENOMEM;
+
+	prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+	if (!prop)
+		goto out_no_prop;
+
+	new_name = kstrdup(name, GFP_KERNEL);
+	if (!new_name)
+		goto out_no_name;
+
+	/*
+	 * NOTE: There is no check for zero length value.
+	 * In case of a boolean property, this will allocate a value
+	 * of zero bytes. We do this to work around the use
+	 * of of_get_property() calls on boolean values.
+	 */
+	new_value = kmemdup(value, length, GFP_KERNEL);
+	if (!new_value)
+		goto out_no_value;
+
+	of_property_set_flag(prop, OF_DYNAMIC);
+
+	prop->name = new_name;
+	prop->value = new_value;
+	prop->length = length;
+
+	ret = of_changeset_add_property(ocs, np, prop);
+	if (ret != 0)
+		goto out_no_add;
+
+	return 0;
+
+out_no_add:
+	kfree(prop->value);
+out_no_value:
+	kfree(prop->name);
+out_no_name:
+	kfree(prop);
+out_no_prop:
+	return ret;
+}
+
+/**
+ * of_changeset_add_property_string - Create a new string property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @str:	string property
+ *
+ * Adds a string property to the changeset by making copies of the name
+ * and the string value.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int of_changeset_add_property_string(struct of_changeset *ocs,
+		struct device_node *np, const char *name, const char *str)
+{
+	return of_changeset_add_property_copy(ocs, np, name, str,
+			strlen(str) + 1);
+}
+
+/**
+ * of_changeset_add_property_stringf - Create a new formatted string property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @fmt:	format of string property
+ * ...		arguments of the format string
+ *
+ * Adds a string property to the changeset by making copies of the name
+ * and the formatted value.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int of_changeset_add_property_stringf(struct of_changeset *ocs,
+		struct device_node *np, const char *name, const char *fmt, ...)
+{
+	va_list vargs;
+	char *str;
+	int ret;
+
+	va_start(vargs, fmt);
+	str = kvasprintf(GFP_KERNEL, fmt, vargs);
+	va_end(vargs);
+
+	ret = of_changeset_add_property_string(ocs, np, name, str);
+
+	kfree(str);
+	return ret;
+}
+
+/**
+ * of_changeset_add_property_string_list - Create a new string list property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @strs:	pointer to the string list
+ * @count:	string count
+ *
+ * Adds a string list property to the changeset.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int of_changeset_add_property_string_list(struct of_changeset *ocs,
+		struct device_node *np, const char *name, const char **strs,
+		int count)
+{
+	int total = 0, i, ret;
+	char *value, *s;
+
+	for (i = 0; i < count; i++) {
+		/* check if  it's NULL */
+		if (!strs[i])
+			return -EINVAL;
+		total += strlen(strs[i]) + 1;
+	}
+
+	value = kmalloc(total, GFP_KERNEL);
+	if (!value)
+		return -ENOMEM;
+
+	for (i = 0, s = value; i < count; i++) {
+		/* no need to check for NULL, check above */
+		strcpy(s, strs[i]);
+		s += strlen(strs[i]) + 1;
+	}
+
+	ret = of_changeset_add_property_copy(ocs, np, name, value, total);
+
+	kfree(value);
+
+	return ret;
+}
+
+/**
+ * of_changeset_add_property_u32 - Create a new u32 property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ * @val:	value in host endian format
+ *
+ * Adds a u32 property to the changeset.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int of_changeset_add_property_u32(struct of_changeset *ocs,
+		struct device_node *np, const char *name, u32 val)
+{
+	/* in place */
+	val = cpu_to_be32(val);
+	return of_changeset_add_property_copy(ocs, np, name, &val, sizeof(val));
+}
+
+/**
+ * of_changeset_add_property_bool - Create a new u32 property
+ *
+ * @ocs:	changeset pointer
+ * @np:		device node pointer
+ * @name:	name of the property
+ *
+ * Adds a bool property to the changeset. Note that there is
+ * no option to set the value to false, since the property
+ * existing sets it to true.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int of_changeset_add_property_bool(struct of_changeset *ocs,
+		struct device_node *np, const char *name)
+{
+	return of_changeset_add_property_copy(ocs, np, name, "", 0);
+}
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 829469f..88b3b8f 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -79,9 +79,9 @@ extern void __of_update_property_sysfs(struct device_node *np,
 		struct property *newprop, struct property *oldprop);
 
 extern void __of_attach_node(struct device_node *np);
-extern int __of_attach_node_sysfs(struct device_node *np);
+extern int __of_attach_node_post(struct device_node *np);
 extern void __of_detach_node(struct device_node *np);
-extern void __of_detach_node_sysfs(struct device_node *np);
+extern void __of_detach_node_post(struct device_node *np);
 
 /* iterators for transactions, used for overlays */
 /* forward iterator */
@@ -92,4 +92,44 @@ extern void __of_detach_node_sysfs(struct device_node *np);
 #define for_each_transaction_entry_reverse(_oft, _te) \
 	list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
 
+#if defined(CONFIG_OF_OVERLAY)
+extern int of_overlay_init(void);
+#else
+static inline int of_overlay_init(void)
+{
+	return 0;
+}
+#endif
+
+extern const struct rhashtable_params of_phandle_ht_params;
+extern struct rhashtable of_phandle_ht;
+extern bool of_phandle_ht_initialized;
+
+static inline bool of_phandle_ht_available(void)
+{
+	return of_phandle_ht_initialized;
+}
+
+static inline int of_phandle_ht_insert(struct device_node *np)
+{
+	if (!np || !np->phandle)
+		return 0;
+	return rhashtable_insert_fast(&of_phandle_ht,
+		&np->ht_node, of_phandle_ht_params);
+}
+
+static inline int of_phandle_ht_remove(struct device_node *np)
+{
+	if (!np || !np->phandle)
+		return 0;
+	return rhashtable_remove_fast(&of_phandle_ht,
+		&np->ht_node, of_phandle_ht_params);
+}
+
+static inline struct device_node *of_phandle_ht_lookup(phandle handle)
+{
+	return rhashtable_lookup_fast(&of_phandle_ht,
+			&handle, of_phandle_ht_params);
+}
+
 #endif /* _LINUX_OF_PRIVATE_H */
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 8225081..a7956a2 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -20,11 +20,28 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/idr.h>
+#include <linux/sysfs.h>
+#include <linux/atomic.h>
 
 #include "of_private.h"
 
+/* fwd. decl */
+struct of_overlay;
+struct of_overlay_info;
+
+/* an attribute for each fragment */
+struct fragment_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct kobject *kobj, struct fragment_attribute *fattr,
+			char *buf);
+	ssize_t (*store)(struct kobject *kobj, struct fragment_attribute *fattr,
+			 const char *buf, size_t count);
+	struct of_overlay_info *ovinfo;
+};
+
 /**
  * struct of_overlay_info - Holds a single overlay info
+ * @info:	info node that contains the target and overlay
  * @target:	target of the overlay operation
  * @overlay:	pointer to the overlay contents node
  *
@@ -32,8 +49,13 @@
  * records.
  */
 struct of_overlay_info {
+	struct of_overlay *ov;
+	struct device_node *info;
 	struct device_node *target;
 	struct device_node *overlay;
+	struct attribute_group attr_group;
+	struct attribute *attrs[2];
+	struct fragment_attribute target_attr;
 };
 
 /**
@@ -50,11 +72,26 @@ struct of_overlay {
 	struct list_head node;
 	int count;
 	struct of_overlay_info *ovinfo_tab;
+	const struct attribute_group **attr_groups;
 	struct of_changeset cset;
+	struct kobject kobj;
+	char *indirect_id;
+	struct device_node *target_root;
 };
 
+/* master enable switch; once set to 0 can't be re-enabled */
+static atomic_t ov_enable = ATOMIC_INIT(1);
+
+static int __init of_overlay_disable_setup(char *str __always_unused)
+{
+	atomic_set(&ov_enable, 0);
+	return 1;
+}
+__setup("of_overlay_disable", of_overlay_disable_setup);
+
 static int of_overlay_apply_one(struct of_overlay *ov,
 		struct device_node *target, const struct device_node *overlay);
+static int overlay_removal_is_ok(struct of_overlay *ov);
 
 static int of_overlay_apply_single_property(struct of_overlay *ov,
 		struct device_node *target, struct property *prop)
@@ -185,35 +222,141 @@ static int of_overlay_apply(struct of_overlay *ov)
 	return 0;
 }
 
-/*
- * Find the target node using a number of different strategies
- * in order of preference
- *
- * "target" property containing the phandle of the target
- * "target-path" property containing the path of the target
- */
-static struct device_node *find_target_node(struct device_node *info_node)
+static struct device_node *find_target_node_direct(struct of_overlay *ov,
+		struct device_node *info_node)
 {
+	struct device_node *target = NULL, *np;
 	const char *path;
+	char *newpath;
 	u32 val;
 	int ret;
 
 	/* first try to go by using the target as a phandle */
 	ret = of_property_read_u32(info_node, "target", &val);
-	if (ret == 0)
-		return of_find_node_by_phandle(val);
+	if (ret == 0) {
+		target = of_find_node_by_phandle(val);
+		if (!target) {
+			pr_err("%s: Could not find target phandle 0x%x\n",
+					__func__, val);
+			return NULL;
+		}
+		goto check_root;
+	}
 
-	/* now try to locate by path */
+	/* failed, try to locate by path */
 	ret = of_property_read_string(info_node, "target-path", &path);
-	if (ret == 0)
-		return of_find_node_by_path(path);
+	if (ret == 0) {
+
+		if (!ov->target_root) {
+			target = of_find_node_by_path(path);
+			if (!target)
+				pr_err("%s: Could not find target path \"%s\"\n",
+						__func__, path);
+			return target;
+		}
+
+		/* remove preceding '/' from path; relative path */
+		if (*path == '/') {
+			while (*path == '/')
+				path++;
+
+			newpath = kasprintf(GFP_KERNEL, "%s%s%s",
+					of_node_full_name(ov->target_root),
+					*path ? "/" : "", path);
+			if (!newpath) {
+				pr_err("%s: Could not allocate \"%s%s%s\"\n",
+					__func__,
+					of_node_full_name(ov->target_root),
+					*path ? "/" : "", path);
+				return NULL;
+			}
+			target = of_find_node_by_path(newpath);
+			kfree(newpath);
+
+			return target;
+
+		}
+		/* target is an alias, need to check */
+		target = of_find_node_by_path(path);
+		if (!target) {
+			pr_err("%s: Could not find alias \"%s\"\n",
+					__func__, path);
+			return NULL;
+		}
+		goto check_root;
+	}
 
-	pr_err("%s: Failed to find target for node %p (%s)\n", __func__,
-		info_node, info_node->name);
+	return NULL;
+
+check_root:
+	if (!ov->target_root)
+		return target;
 
+	/* got a target, but we have to check it's under target root */
+	for (np = target; np; np = np->parent) {
+		if (np == ov->target_root)
+			return target;
+	}
+	pr_err("%s: target \"%s\" not under target_root \"%s\"\n",
+			__func__, of_node_full_name(target),
+			of_node_full_name(ov->target_root));
+	/* target is not under target_root */
+	of_node_put(target);
 	return NULL;
 }
 
+/*
+ * Find the target node using a number of different strategies
+ * in order of preference. Respects the indirect id if available.
+ *
+ * "target" property containing the phandle of the target
+ * "target-path" property containing the path of the target
+ */
+static struct device_node *find_target_node(struct of_overlay *ov,
+		struct device_node *info_node)
+{
+	struct device_node *target;
+	struct device_node *target_indirect;
+	struct device_node *indirect;
+
+	/* try direct target */
+	target = find_target_node_direct(ov, info_node);
+	if (target)
+		return target;
+
+	/* try indirect if there */
+	if (!ov->indirect_id)
+		return NULL;
+
+	target_indirect = of_get_child_by_name(info_node, "target-indirect");
+	if (!target_indirect) {
+		pr_err("%s: Failed to find target-indirect node at %s\n",
+				__func__,
+				of_node_full_name(info_node));
+		return NULL;
+	}
+
+	indirect = of_get_child_by_name(target_indirect, ov->indirect_id);
+	of_node_put(target_indirect);
+	if (!indirect) {
+		pr_err("%s: Failed to find indirect child node \"%s\" at %s\n",
+				__func__, ov->indirect_id,
+				of_node_full_name(info_node));
+		return NULL;
+	}
+
+	target = find_target_node_direct(ov, indirect);
+
+	if (!target) {
+		pr_err("%s: Failed to find target for \"%s\" at %s\n",
+				__func__, ov->indirect_id,
+				of_node_full_name(indirect));
+	}
+	of_node_put(indirect);
+
+	return target;
+}
+
 /**
  * of_fill_overlay_info() - Fill an overlay info structure
  * @ov		Overlay to fill
@@ -235,10 +378,12 @@ static int of_fill_overlay_info(struct of_overlay *ov,
 	if (ovinfo->overlay == NULL)
 		goto err_fail;
 
-	ovinfo->target = find_target_node(info_node);
+	ovinfo->target = find_target_node(ov, info_node);
 	if (ovinfo->target == NULL)
 		goto err_fail;
 
+	ovinfo->info = of_node_get(info_node);
+
 	return 0;
 
 err_fail:
@@ -249,6 +394,17 @@ err_fail:
 	return -EINVAL;
 }
 
+static ssize_t target_show(struct kobject *kobj,
+		struct fragment_attribute *fattr, char *buf)
+{
+	struct of_overlay_info *ovinfo = fattr->ovinfo;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			of_node_full_name(ovinfo->target));
+}
+
+static const struct fragment_attribute target_template_attr = __ATTR_RO(target);
+
 /**
  * of_build_overlay_info() - Build an overlay info array
  * @ov		Overlay to build
@@ -266,7 +422,7 @@ static int of_build_overlay_info(struct of_overlay *ov,
 {
 	struct device_node *node;
 	struct of_overlay_info *ovinfo;
-	int cnt, err;
+	int i, cnt, err;
 
 	/* worst case; every child is a node */
 	cnt = 0;
@@ -287,14 +443,45 @@ static int of_build_overlay_info(struct of_overlay *ov,
 
 	/* if nothing filled, return error */
 	if (cnt == 0) {
-		kfree(ovinfo);
-		return -ENODEV;
+		err = -ENODEV;
+		goto err_free_ovinfo;
 	}
 
 	ov->count = cnt;
 	ov->ovinfo_tab = ovinfo;
 
+	ov->attr_groups = kcalloc(cnt + 1,
+			sizeof(struct attribute_group *), GFP_KERNEL);
+	if (ov->attr_groups == NULL) {
+		err = -ENOMEM;
+		goto err_free_ovinfo;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		ovinfo = &ov->ovinfo_tab[i];
+
+		ov->attr_groups[i] = &ovinfo->attr_group;
+
+		ovinfo->target_attr = target_template_attr;
+		/* make lockdep happy */
+		sysfs_attr_init(&ovinfo->target_attr.attr);
+		ovinfo->target_attr.ovinfo = ovinfo;
+
+		ovinfo->attrs[0] = &ovinfo->target_attr.attr;
+		ovinfo->attrs[1] = NULL;
+
+		/* NOTE: direct reference to the full_name */
+		ovinfo->attr_group.name = kbasename(ovinfo->info->full_name);
+		ovinfo->attr_group.attrs = ovinfo->attrs;
+
+	}
+	ov->attr_groups[i] = NULL;
+
 	return 0;
+
+err_free_ovinfo:
+	kfree(ovinfo);
+	return err;
 }
 
 /**
@@ -311,46 +498,218 @@ static int of_free_overlay_info(struct of_overlay *ov)
 	struct of_overlay_info *ovinfo;
 	int i;
 
+	/* free attribute groups space */
+	kfree(ov->attr_groups);
+
 	/* do it in reverse */
 	for (i = ov->count - 1; i >= 0; i--) {
 		ovinfo = &ov->ovinfo_tab[i];
 
 		of_node_put(ovinfo->target);
 		of_node_put(ovinfo->overlay);
+		of_node_put(ovinfo->info);
 	}
 	kfree(ov->ovinfo_tab);
 
 	return 0;
 }
 
+static int of_overlay_add_symbols(
+		struct device_node *tree,
+		struct of_overlay *ov)
+{
+	struct of_overlay_info *ovinfo;
+	struct device_node *root_sym = NULL;
+	struct device_node *child = NULL;
+	struct property *prop;
+	const char *path, *s;
+	char *new_path;
+	int i, len, err;
+
+	/* this may fail (if no fixups are required) */
+	root_sym = of_find_node_by_path("/__symbols__");
+
+	/* do nothing if no root symbols */
+	if (!root_sym)
+		return 0;
+
+	/* locate the symbols & fixups nodes on resolve */
+	for_each_child_of_node(tree, child) {
+		if (of_node_cmp(child->name, "__symbols__") == 0)
+			goto found;
+	}
+	/* no symbols, no problem */
+	of_node_put(root_sym);
+	return 0;
+
+found:
+	err = -EINVAL;
+	for_each_property_of_node(child, prop) {
+
+		/* skip properties added automatically */
+		if (of_prop_cmp(prop->name, "name") == 0)
+			continue;
+
+		err = of_property_read_string(child,
+				prop->name, &path);
+		if (err != 0) {
+			pr_err("%s: Could not find symbol '%s'\n",
+					__func__, prop->name);
+			continue;
+		}
+
+
+		/* now find fragment index */
+		s = path;
+
+		/* compare paths to find fragment index */
+		ovinfo = NULL;
+		len = -1;
+		for (i = 0; i < ov->count; i++) {
+			ovinfo = &ov->ovinfo_tab[i];
+
+			pr_debug("%s: #%d: overlay->name=%s target->name=%s\n",
+					__func__, i, ovinfo->overlay->full_name,
+					ovinfo->target->full_name);
+
+			len = strlen(ovinfo->overlay->full_name);
+			if (strncasecmp(path, ovinfo->overlay->full_name,
+						len) == 0 && path[len] == '/')
+				break;
+		}
+
+		if (i >= ov->count)
+			continue;
+
+		pr_debug("%s: found target at #%d\n", __func__, i);
+		new_path = kasprintf(GFP_KERNEL, "%s%s",
+				ovinfo->target->full_name,
+				path + len);
+		if (!new_path) {
+			pr_err("%s: Failed to allocate propname for \"%s\"\n",
+					__func__, prop->name);
+			continue;
+		}
+
+		err = of_changeset_add_property_string(&ov->cset, root_sym,
+				prop->name, new_path);
+
+		/* free always */
+		kfree(new_path);
+
+		if (err) {
+			pr_err("%s: Failed to add property for \"%s\"\n",
+					__func__, prop->name);
+		}
+	}
+
+	of_node_put(child);
+	of_node_put(root_sym);
+
+	return 0;
+}
+
 static LIST_HEAD(ov_list);
 static DEFINE_IDR(ov_idr);
 
-/**
- * of_overlay_create() - Create and apply an overlay
- * @tree:	Device node containing all the overlays
- *
- * Creates and applies an overlay while also keeping track
- * of the overlay in a list. This list can be used to prevent
- * illegal overlay removals.
- *
- * Returns the id of the created overlay, or a negative error number
- */
-int of_overlay_create(struct device_node *tree)
+static inline struct of_overlay *kobj_to_overlay(struct kobject *kobj)
+{
+	return container_of(kobj, struct of_overlay, kobj);
+}
+
+void of_overlay_release(struct kobject *kobj)
+{
+	struct of_overlay *ov = kobj_to_overlay(kobj);
+
+	of_node_put(ov->target_root);
+	kfree(ov->indirect_id);
+	kfree(ov);
+}
+
+static ssize_t enable_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&ov_enable));
+}
+
+static ssize_t enable_store(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret;
+	bool new_enable;
+
+	ret = strtobool(buf, &new_enable);
+	if (ret != 0)
+		return ret;
+	/* if we've disabled it, no going back */
+	if (atomic_read(&ov_enable) == 0)
+		return -EPERM;
+	atomic_set(&ov_enable, (int)new_enable);
+	return count;
+}
+
+static struct kobj_attribute enable_attr = __ATTR_RW(enable);
+
+static const struct attribute *overlay_global_attrs[] = {
+	&enable_attr.attr,
+	NULL
+};
+
+static ssize_t can_remove_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	struct of_overlay *ov = kobj_to_overlay(kobj);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", overlay_removal_is_ok(ov));
+}
+
+static struct kobj_attribute can_remove_attr = __ATTR_RO(can_remove);
+
+static struct attribute *overlay_attrs[] = {
+	&can_remove_attr.attr,
+	NULL
+};
+
+static struct kobj_type of_overlay_ktype = {
+	.release = of_overlay_release,
+	.sysfs_ops = &kobj_sysfs_ops,	/* default kobj sysfs ops */
+	.default_attrs = overlay_attrs,
+};
+
+static struct kset *ov_kset;
+
+static int __of_overlay_create(struct device_node *tree,
+		const char *indirect_id, struct device_node *target_root)
 {
 	struct of_overlay *ov;
 	int err, id;
 
+	/* administratively disabled */
+	if (!atomic_read(&ov_enable))
+		return -EPERM;
+
 	/* allocate the overlay structure */
 	ov = kzalloc(sizeof(*ov), GFP_KERNEL);
 	if (ov == NULL)
 		return -ENOMEM;
 	ov->id = -1;
 
+	if (indirect_id) {
+		ov->indirect_id = kstrdup(indirect_id, GFP_KERNEL);
+		if (!ov->indirect_id) {
+			err = -ENOMEM;
+			goto err_no_mem;
+		}
+	}
+	ov->target_root = of_node_get(target_root);
+
 	INIT_LIST_HEAD(&ov->node);
 
 	of_changeset_init(&ov->cset);
 
+	/* initialize kobject */
+	kobject_init(&ov->kobj, &of_overlay_ktype);
+
 	mutex_lock(&of_mutex);
 
 	id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL);
@@ -378,6 +737,13 @@ int of_overlay_create(struct device_node *tree)
 		goto err_abort_trans;
 	}
 
+	err = of_overlay_add_symbols(tree, ov);
+	if (err) {
+		pr_err("%s: of_overlay_add_symbols() failed for tree@%s\n",
+				__func__, tree->full_name);
+		goto err_abort_trans;
+	}
+
 	/* apply the changeset */
 	err = __of_changeset_apply(&ov->cset);
 	if (err) {
@@ -386,13 +752,31 @@ int of_overlay_create(struct device_node *tree)
 		goto err_revert_overlay;
 	}
 
+	ov->kobj.kset = ov_kset;
+	err = kobject_add(&ov->kobj, NULL, "%d", id);
+	if (err != 0) {
+		pr_err("%s: kobject_add() failed for tree@%s\n",
+				__func__, tree->full_name);
+		goto err_cancel_overlay;
+	}
+
+	err = sysfs_create_groups(&ov->kobj, ov->attr_groups);
+	if (err != 0) {
+		pr_err("%s: sysfs_create_groups() failed for tree@%s\n",
+				__func__, tree->full_name);
+		goto err_remove_kobj;
+	}
+
 	/* add to the tail of the overlay list */
 	list_add_tail(&ov->node, &ov_list);
 
 	mutex_unlock(&of_mutex);
 
 	return id;
-
+err_remove_kobj:
+	kobject_put(&ov->kobj);
+err_cancel_overlay:
+	of_changeset_revert(&ov->cset);
 err_revert_overlay:
 err_abort_trans:
 	of_free_overlay_info(ov);
@@ -400,13 +784,68 @@ err_free_idr:
 	idr_remove(&ov_idr, ov->id);
 err_destroy_trans:
 	of_changeset_destroy(&ov->cset);
+err_no_mem:
+	of_node_put(ov->target_root);
+	kfree(ov->indirect_id);
 	kfree(ov);
 	mutex_unlock(&of_mutex);
 
 	return err;
 }
+
+/**
+ * of_overlay_create() - Create and apply an overlay
+ * @tree:	Device node containing all the overlays
+ *
+ * Creates and applies an overlay while also keeping track
+ * of the overlay in a list. This list can be used to prevent
+ * illegal overlay removals.
+ *
+ * Returns the id of the created overlay, or a negative error number
+ */
+int of_overlay_create(struct device_node *tree)
+{
+	return __of_overlay_create(tree, NULL, NULL);
+}
 EXPORT_SYMBOL_GPL(of_overlay_create);
 
+/**
+ * of_overlay_create_indirect() - Create and apply an overlay
+ * @tree:	Device node containing all the overlays
+ * @id:		Indirect property phandle
+ *
+ * Creates and applies an overlay while also keeping track
+ * of the overlay in a list. This list can be used to prevent
+ * illegal overlay removals.
+ *
+ * Returns the id of the created overlay, or a negative error number
+ */
+int of_overlay_create_indirect(struct device_node *tree, const char *id)
+{
+	return __of_overlay_create(tree, id, NULL);
+}
+EXPORT_SYMBOL_GPL(of_overlay_create_indirect);
+
+/**
+ * of_overlay_create_target_root() - Create and apply an overlay
+ *			under which will be limited to target_root
+ * @tree:		Device node containing all the overlays
+ * @target_root:	Target root for the overlay.
+ *
+ * Creates and applies an overlay while also keeping track
+ * of the overlay in a list. This list can be used to prevent
+ * illegal overlay removals. The overlay is only allowed to
+ * target nodes under the target_root node.
+ *
+ * Returns the id of the created overlay, or an negative error number
+ */
+int of_overlay_create_target_root(struct device_node *tree,
+		struct device_node *target_root)
+{
+	return __of_overlay_create(tree, NULL, target_root);
+}
+EXPORT_SYMBOL_GPL(of_overlay_create_target_root);
+
 /* check whether the given node, lies under the given tree */
 static int overlay_subtree_check(struct device_node *tree,
 		struct device_node *dn)
@@ -511,11 +950,13 @@ int of_overlay_destroy(int id)
 
 
 	list_del(&ov->node);
+	sysfs_remove_groups(&ov->kobj, ov->attr_groups);
 	__of_changeset_revert(&ov->cset);
 	of_free_overlay_info(ov);
 	idr_remove(&ov_idr, id);
 	of_changeset_destroy(&ov->cset);
-	kfree(ov);
+
+	kobject_put(&ov->kobj);
 
 	err = 0;
 
@@ -545,7 +986,7 @@ int of_overlay_destroy_all(void)
 		__of_changeset_revert(&ov->cset);
 		of_free_overlay_info(ov);
 		idr_remove(&ov_idr, ov->id);
-		kfree(ov);
+		kobject_put(&ov->kobj);
 	}
 
 	mutex_unlock(&of_mutex);
@@ -553,3 +994,18 @@ int of_overlay_destroy_all(void)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(of_overlay_destroy_all);
+
+/* called from of_init() */
+int of_overlay_init(void)
+{
+	int rc;
+
+	ov_kset = kset_create_and_add("overlays", NULL, &of_kset->kobj);
+	if (!ov_kset)
+		return -ENOMEM;
+
+	rc = sysfs_create_files(&ov_kset->kobj, overlay_global_attrs);
+	WARN(rc, "%s: error adding global attributes\n", __func__);
+
+	return rc;
+}
diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dts
index 12f7c3d..8052b96 100644
--- a/drivers/of/unittest-data/testcases.dts
+++ b/drivers/of/unittest-data/testcases.dts
@@ -75,5 +75,19 @@
 				target = <0x00000000>;
 			};
 		};
+		overlay16 {
+			fragment@0 {
+				target-indirect {
+					unittest16 {
+						target = <0x00000000>;
+					};
+				};
+			};
+		};
+		overlay18 {
+			fragment@0 {
+				target = <0x00000000>;
+			};
+		};
 	};
 }; };
diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi
index 02ba56c..e10ff5a 100644
--- a/drivers/of/unittest-data/tests-overlay.dtsi
+++ b/drivers/of/unittest-data/tests-overlay.dtsi
@@ -110,6 +110,30 @@
 						};
 					};
 				};
+
+				unittest16: test-unittest16 {
+					compatible = "unittest";
+					status = "disabled";
+					reg = <16>;
+				};
+
+				unittest17: test-unittest17 {
+					compatible = "unittest";
+					status = "disabled";
+					reg = <17>;
+				};
+
+				unittest18: test-unittest18 {
+					compatible = "unittest";
+					status = "disabled";
+					reg = <18>;
+				};
+
+				unittest19: test-unittest19 {
+					compatible = "unittest";
+					status = "disabled";
+					reg = <19>;
+				};
 			};
 		};
 
@@ -325,5 +349,48 @@
 			};
 		};
 
+		/* test enable using indirect functionality */
+		overlay16 {
+			fragment@0 {
+				target-indirect {
+					unittest16 {
+						target = <&unittest16>;
+					};
+				};
+				__overlay__ {
+					status = "okay";
+				};
+			};
+		};
+
+		/* test enable using target root (relative path) */
+		overlay17 {
+			fragment@0 {
+				target-path = "/";
+				__overlay__ {
+					status = "okay";
+				};
+			};
+		};
+
+		/* test enable using target phandle */
+		overlay18 {
+			fragment@0 {
+				target = <&unittest18>;
+				__overlay__ {
+					status = "okay";
+				};
+			};
+		};
+
+		/* test trying to enable out of root (should fail) */
+		overlay19 {
+			fragment@0 {
+				target = <&unittest19>;
+				__overlay__ {
+					status = "okay";
+				};
+			};
+		};
 	};
 };
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index e986e6e..0c5994f 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -543,6 +543,45 @@ static void __init of_unittest_changeset(void)
 #endif
 }
 
+static void __init of_unittest_changeset_helper(void)
+{
+#ifdef CONFIG_OF_DYNAMIC
+	struct device_node *n1, *n2, *n21, *parent, *np;
+	struct of_changeset chgset;
+
+	of_changeset_init(&chgset);
+
+	parent = of_find_node_by_path("/testcase-data/changeset");
+
+	unittest(parent, "testcase setup failure\n");
+	n1 = of_changeset_create_device_node(&chgset,
+			parent, "/testcase-data/changeset/n1");
+	unittest(n1, "testcase setup failure\n");
+	n2 = of_changeset_create_device_node(&chgset,
+			parent, "/testcase-data/changeset/n2");
+	unittest(n2, "testcase setup failure\n");
+	n21 = of_changeset_create_device_node(&chgset, n2, "%s/%s",
+			"/testcase-data/changeset/n2", "n21");
+
+	of_changeset_init(&chgset);
+	unittest(!of_changeset_add_property_string(&chgset, parent,
+				"prop-add", "foo"), "fail add prop\n");
+	unittest(!of_changeset_apply(&chgset), "apply failed\n");
+
+	/* Make sure node names are constructed correctly */
+	unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
+		 "'%s' not added\n", n21->full_name);
+	of_node_put(np);
+
+	unittest(!of_changeset_revert(&chgset), "revert failed\n");
+
+	of_changeset_destroy(&chgset);
+
+	of_node_put(parent);
+#endif
+}
+
+
 static void __init of_unittest_parse_interrupts(void)
 {
 	struct device_node *np;
@@ -878,7 +917,7 @@ static int attach_node_and_children(struct device_node *np)
 	of_node_clear_flag(np, OF_DETACHED);
 	raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
-	__of_attach_node_sysfs(np);
+	__of_attach_node_post(np);
 	mutex_unlock(&of_mutex);
 
 	while (child) {
@@ -936,7 +975,7 @@ static int __init unittest_data_add(void)
 	if (!of_root) {
 		of_root = unittest_data_node;
 		for_each_of_allnodes(np)
-			__of_attach_node_sysfs(np);
+			__of_attach_node_post(np);
 		of_aliases = of_find_node_by_path("/aliases");
 		of_chosen = of_find_node_by_path("/chosen");
 		return 0;
@@ -1868,6 +1907,272 @@ static inline void of_unittest_overlay_i2c_15(void) { }
 
 #endif
 
+static void of_unittest_overlay_16(void)
+{
+	int ret;
+	int overlay_nr = 16;
+	int unittest_nr = 16;
+	enum overlay_type ovtype = PDEV_OVERLAY;
+	int before = 0;
+	int after = 1;
+	struct device_node *np = NULL;
+	int id = -1;
+
+	/* unittest device must not be in before state */
+	if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
+		unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+				overlay_path(overlay_nr),
+				unittest_path(unittest_nr, ovtype),
+				!before ? "enabled" : "disabled");
+		return;
+	}
+
+	np = of_find_node_by_path(overlay_path(overlay_nr));
+	if (np == NULL) {
+		unittest(0, "could not find overlay node @\"%s\"\n",
+				overlay_path(overlay_nr));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = of_overlay_create_indirect(np, "unittest16");
+	if (ret < 0) {
+		unittest(0, "could not create overlay from \"%s\"\n",
+				overlay_path(overlay_nr));
+		goto out;
+	}
+	id = ret;
+	of_unittest_track_overlay(id);
+
+	ret = 0;
+
+out:
+	of_node_put(np);
+
+	if (ret)
+		return;
+
+	/* unittest device must be to set to after state */
+	if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
+		unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+				overlay_path(overlay_nr),
+				unittest_path(unittest_nr, ovtype),
+				!after ? "enabled" : "disabled");
+		return;
+	}
+
+	unittest(1, "overlay test %d passed\n", 16);
+}
+
+static void of_unittest_overlay_17(void)
+{
+	int ret;
+	int overlay_nr = 17;
+	int unittest_nr = 17;
+	enum overlay_type ovtype = PDEV_OVERLAY;
+	int before = 0;
+	int after = 1;
+	const char *root_path;
+	struct device_node *np = NULL, *target_root = NULL;
+	int id = -1;
+
+	/* unittest device must not be in before state */
+	if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
+		unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+				overlay_path(overlay_nr),
+				unittest_path(unittest_nr, ovtype),
+				!before ? "enabled" : "disabled");
+		return;
+	}
+
+	np = of_find_node_by_path(overlay_path(overlay_nr));
+	if (np == NULL) {
+		unittest(0, "could not find overlay node @\"%s\"\n",
+				overlay_path(overlay_nr));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	root_path = "/testcase-data/overlay-node/test-bus/test-unittest17";
+	target_root = of_find_node_by_path(root_path);
+	if (!target_root) {
+		unittest(0, "could not find target_root node @\"%s\"\n",
+				root_path);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = of_overlay_create_target_root(np, target_root);
+	of_node_put(target_root);
+
+	if (ret < 0) {
+		unittest(0, "could not create overlay from \"%s\"\n",
+				overlay_path(overlay_nr));
+		goto out;
+	}
+	id = ret;
+	of_unittest_track_overlay(id);
+
+	ret = 0;
+
+out:
+	of_node_put(np);
+
+	if (ret)
+		return;
+
+	/* unittest device must be to set to after state */
+	if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
+		unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+				overlay_path(overlay_nr),
+				unittest_path(unittest_nr, ovtype),
+				!after ? "enabled" : "disabled");
+		return;
+	}
+
+	unittest(1, "overlay test %d passed\n", 17);
+}
+
+static void of_unittest_overlay_18(void)
+{
+	int ret;
+	int overlay_nr = 18;
+	int unittest_nr = 18;
+	enum overlay_type ovtype = PDEV_OVERLAY;
+	int before = 0;
+	int after = 1;
+	const char *root_path;
+	struct device_node *np = NULL, *target_root = NULL;
+	int id = -1;
+
+	/* unittest device must not be in before state */
+	if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
+		unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+				overlay_path(overlay_nr),
+				unittest_path(unittest_nr, ovtype),
+				!before ? "enabled" : "disabled");
+		return;
+	}
+
+	np = of_find_node_by_path(overlay_path(overlay_nr));
+	if (np == NULL) {
+		unittest(0, "could not find overlay node @\"%s\"\n",
+				overlay_path(overlay_nr));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	root_path = "/testcase-data/overlay-node/test-bus/test-unittest18";
+	target_root = of_find_node_by_path(root_path);
+	if (!target_root) {
+		unittest(0, "could not find target_root node @\"%s\"\n",
+				root_path);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = of_overlay_create_target_root(np, target_root);
+	of_node_put(target_root);
+
+	if (ret < 0) {
+		unittest(0, "could not create overlay from \"%s\"\n",
+				overlay_path(overlay_nr));
+		goto out;
+	}
+	id = ret;
+	of_unittest_track_overlay(id);
+
+	ret = 0;
+
+out:
+	of_node_put(np);
+
+	if (ret)
+		return;
+
+	/* unittest device must be to set to after state */
+	if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
+		unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+				overlay_path(overlay_nr),
+				unittest_path(unittest_nr, ovtype),
+				!after ? "enabled" : "disabled");
+		return;
+	}
+
+	unittest(1, "overlay test %d passed\n", 18);
+}
+
+static void of_unittest_overlay_19(void)
+{
+	int ret;
+	int overlay_nr = 19;
+	int unittest_nr = 19;
+	enum overlay_type ovtype = PDEV_OVERLAY;
+	int before = 0;
+	int after = 0;
+	const char *root_path;
+	struct device_node *np = NULL, *target_root = NULL;
+	int id = -1;
+
+	/* unittest device must not be in before state */
+	if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
+		unittest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+				overlay_path(overlay_nr),
+				unittest_path(unittest_nr, ovtype),
+				!before ? "enabled" : "disabled");
+		return;
+	}
+
+	np = of_find_node_by_path(overlay_path(overlay_nr));
+	if (np == NULL) {
+		unittest(0, "could not find overlay node @\"%s\"\n",
+				overlay_path(overlay_nr));
+		ret = -EINVAL;
+		goto out;
+	}
+
+	root_path = "/testcase-data/overlay-node/test-bus/test-unittest19";
+	target_root = of_find_node_by_path(root_path);
+	if (!target_root) {
+		unittest(0, "could not find target_root node @\"%s\"\n",
+				root_path);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = of_overlay_create_target_root(np, target_root);
+	of_node_put(target_root);
+
+	if (ret >= 0) {
+		unittest(0, "created overlay from \"%s\" while we shouldn't\n",
+				overlay_path(overlay_nr));
+		id = ret;
+		of_unittest_track_overlay(id);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = 0;
+
+out:
+	of_node_put(np);
+
+	if (ret)
+		return;
+
+	/* unittest device must be to set to after state */
+	if (of_unittest_device_exists(unittest_nr, ovtype) != after) {
+		unittest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+				overlay_path(overlay_nr),
+				unittest_path(unittest_nr, ovtype),
+				!after ? "enabled" : "disabled");
+		return;
+	}
+
+	unittest(1, "overlay test %d passed\n", 16);
+}
+
+
 static void __init of_unittest_overlay(void)
 {
 	struct device_node *bus_np = NULL;
@@ -1919,6 +2224,12 @@ static void __init of_unittest_overlay(void)
 	of_unittest_overlay_10();
 	of_unittest_overlay_11();
 
+	of_unittest_overlay_16();
+
+	of_unittest_overlay_17();
+	of_unittest_overlay_18();
+	of_unittest_overlay_19();
+
 #if IS_BUILTIN(CONFIG_I2C)
 	if (unittest(of_unittest_overlay_i2c_init() == 0, "i2c init failed\n"))
 		goto out;
@@ -1969,6 +2280,7 @@ static int __init of_unittest(void)
 	of_unittest_property_string();
 	of_unittest_property_copy();
 	of_unittest_changeset();
+	of_unittest_changeset_helper();
 	of_unittest_parse_interrupts();
 	of_unittest_parse_interrupts_extended();
 	of_unittest_match_node();
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index fb8200b..afdf551 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -168,6 +168,18 @@ config PINCTRL_ST
 	select PINCONF
 	select GPIOLIB_IRQCHIP
 
+config PINCTRL_TI_IODELAY
+	bool "TI IODelay Module pinconf driver"
+	depends on OF
+	select PINCONF
+	select GENERIC_PINCONF
+	select REGMAP_MMIO
+	help
+	  Say Y here to support Texas Instruments' IODelay pinconf driver.
+	  IODelay module is used for the DRA7 SoC family. This driver is in
+	  addition to PINCTRL_SINGLE which controls the mux.
+
+
 config PINCTRL_TZ1090
 	bool "Toumaz Xenif TZ1090 pin control driver"
 	depends on SOC_TZ1090
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index e4bc115..8ffdf30 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_PINCTRL_ROCKCHIP)	+= pinctrl-rockchip.o
 obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o
 obj-$(CONFIG_PINCTRL_SIRF)	+= sirf/
 obj-$(CONFIG_PINCTRL_TEGRA)	+= tegra/
+obj-$(CONFIG_PINCTRL_TI_IODELAY)+= pinctrl-ti-iodelay.o
 obj-$(CONFIG_PINCTRL_TZ1090)	+= pinctrl-tz1090.o
 obj-$(CONFIG_PINCTRL_TZ1090_PDC)	+= pinctrl-tz1090-pdc.o
 obj-$(CONFIG_PINCTRL_U300)	+= pinctrl-u300.o
diff --git b/drivers/pinctrl/pinctrl-ti-iodelay.c b/drivers/pinctrl/pinctrl-ti-iodelay.c
new file mode 100644
index 0000000..8d33414
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ti-iodelay.c
@@ -0,0 +1,968 @@
+/*
+ * Support for configuration of IO Delay module found on Texas Instruments SoCs
+ * such as DRA7
+ *
+ * Copyright (C) 2015 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define IODELAY_REG_NAME_LEN		((sizeof(u32) * 2) + 3)
+#define DRIVER_NAME			"ti-io-delay"
+/* Should I change this? Abuse? */
+#define IODELAY_MUX_PINS_NAME		"pinctrl-single,pins"
+
+/* Device tree match, populated later */
+static const struct of_device_id ti_iodelay_of_match[];
+
+/**
+ * struct ti_iodelay_conf_vals - Description of each configuration parameters.
+ * @offset:	Configuration register offset
+ * @a_delay:	Agnostic Delay (in ps)
+ * @g_delay:	Gnostic Delay (in ps)
+ */
+struct ti_iodelay_conf_vals {
+	u16 offset;
+	u16 a_delay;
+	u16 g_delay;
+};
+
+/**
+ * struct ti_iodelay_reg_data - Describes the registers for the IOdelay instance
+ * @signature_mask:	Conf reg- mask for the signature bits
+ * @signature_value:	Conf reg- signature value to be written (see TRM)
+ * @lock_mask:		Conf reg- mask for the lock bits
+ * @lock_val:		Conf reg- lock value for the lock bits (see TRM)
+ * @unlock_val:		Conf reg- unlock value for the lock bits (see TRM)
+ * @binary_data_coarse_mask: Conf reg- coarse mask (see TRM)
+ * @binary_data_fine_mask: Conf reg- fine mask (see TRM)
+ * @reg_refclk_offset:	Refclk register offset
+ * @refclk_period_mask:	Refclk mask
+ * @reg_coarse_offset:	Coarse register configuration offset
+ * @coarse_delay_count_mask: Coarse delay count mask
+ * @coarse_ref_count_mask: Coarse ref count mask
+ * @reg_fine_offset:	Fine register configuration offset
+ * @fine_delay_count_mask: Fine delay count mask
+ * @fine_ref_count_mask: Fine  ref count mask
+ * @reg_global_lock_offset: Global(for the IOdelay module) lock register offset
+ * @global_lock_mask:	Lock mask
+ * @global_unlock_val:	unlock value
+ * @global_lock_val:	lock value
+ * @reg_start_offset:	Where does the configuration registers start?
+ * @regmap_config:	Regmap configuration for the IODelay region
+ */
+struct ti_iodelay_reg_data {
+	u32 signature_mask;
+	u32 signature_value;
+	u32 lock_mask;
+	u32 lock_val;
+	u32 unlock_val;
+	u32 binary_data_coarse_mask;
+	u32 binary_data_fine_mask;
+
+	u32 reg_refclk_offset;
+	u32 refclk_period_mask;
+
+	u32 reg_coarse_offset;
+	u32 coarse_delay_count_mask;
+	u32 coarse_ref_count_mask;
+
+	u32 reg_fine_offset;
+	u32 fine_delay_count_mask;
+	u32 fine_ref_count_mask;
+
+	u32 reg_global_lock_offset;
+	u32 global_lock_mask;
+	u32 global_unlock_val;
+	u32 global_lock_val;
+
+	u32 reg_start_offset;
+
+	struct regmap_config *regmap_config;
+};
+
+/**
+ * struct ti_iodelay_reg_values - Computed io_reg configuration values (see TRM)
+ * @coarse_ref_count:	Coarse reference count
+ * @coarse_delay_count:	Coarse delay count
+ * @fine_ref_count:	Fine reference count
+ * @fine_delay_count:	Fine Delay count
+ * @ref_clk_period:	Reference Clock period
+ * @cdpe:		Coarse delay parameter
+ * @fdpe:		Fine delay parameter
+ */
+struct ti_iodelay_reg_values {
+	u16 coarse_ref_count;
+	u16 coarse_delay_count;
+
+	u16 fine_ref_count;
+	u16 fine_delay_count;
+
+	u16 ref_clk_period;
+
+	u32 cdpe;
+	u32 fdpe;
+};
+
+/**
+ * struct ti_iodelay_pin_name - name of the pins
+ * @name: name
+ */
+struct ti_iodelay_pin_name {
+	char name[IODELAY_REG_NAME_LEN];
+};
+
+/**
+ * struct ti_iodelay_pingroup - Structure that describes one group
+ * @np:		Node pointer (device tree)
+ * @name:	Name of the group
+ * @map:	pinctrl map allocated for the group
+ * @vals:	configuration values allocated for the group (from dt)
+ * @nvals:	number of configuration values allocated
+ * @config:	pinconf "Config" - currently a dummy value
+ * @node:	list node to next group
+ */
+struct ti_iodelay_pingroup {
+	struct device_node *np;
+	const char *name;
+	struct pinctrl_map *map;
+	struct ti_iodelay_conf_vals *vals;
+	int nvals;
+	unsigned long config;
+	struct list_head node;
+};
+
+/**
+ * struct ti_iodelay_device - Represents information for a IOdelay instance
+ * @dev: device pointer
+ * @reg_base: Remapped virtual address
+ * @regmap: Regmap for this IOdelay instance
+ * @pctl: Pinctrl device
+ * @desc: pinctrl descriptor for pctl
+ * @pa: pinctrl pin wise description
+ * @names: names of the pins
+ * @groups: list of pinconf groups for iodelay instance
+ * @ngroups: number of groups in the list
+ * @mutex: mutex to protect group list modification
+ * @reg_data: Register definition data for the IODelay instance
+ * @reg_init_conf_values: Initial configuration values.
+ */
+struct ti_iodelay_device {
+	struct device *dev;
+	void __iomem *reg_base;
+	struct regmap *regmap;
+
+	struct pinctrl_dev *pctl;
+	struct pinctrl_desc desc;
+	struct pinctrl_pin_desc *pa;
+	struct ti_iodelay_pin_name *names;
+
+	struct list_head groups;
+	int ngroups;
+	struct mutex mutex; /* list protection */
+
+	const struct ti_iodelay_reg_data *reg_data;
+	struct ti_iodelay_reg_values reg_init_conf_values;
+};
+
+/*--- IOdelay configuration stuff ----*/
+
+/**
+ * ti_iodelay_extract() - extract bits for a field
+ * @val:	register value
+ * @mask:	Mask
+ *
+ * Return: extracted value which is appropriately shifted
+ */
+static inline u32 ti_iodelay_extract(u32 val, u32 mask)
+{
+	return (val & mask) >> __ffs(mask);
+}
+
+/**
+ * ti_iodelay_compute_dpe() - Compute equation for delay parameter
+ * @period:	Period to use
+ * @ref:	Reference Count
+ * @delay:	Delay count
+ * @delay_m:	Delay multiplier
+ *
+ * Return: Computed delay parameter
+ */
+static inline u32 ti_iodelay_compute_dpe(u16 period, u16 ref, u16 delay,
+					 u16 delay_m)
+{
+	u64 m, d;
+
+	/* Handle overflow conditions */
+	m = 10 * (u64)period * (u64)ref;
+	d = 2 * (u64)delay * (u64)delay_m;
+
+	/* Truncate result back to 32 bits */
+	return div64_u64(m, d);
+}
+
+/**
+ * ti_iodelay_pinconf_set() - Configure the pin configuration
+ * @iod:	IODelay device
+ * @val:	Configuration value
+ *
+ * Update the configuration register as per TRM and lockup once done.
+ * *IMPORTANT NOTE* SoC TRM does recommend doing iodelay programmation only
+ * while in Isolation. But, then, isolation also implies that every pin
+ * on the SoC(including DDR) will be isolated out. The only benefit being
+ * a glitchless configuration, However, the intent of this driver is purely
+ * to support a "glitchy" configuration where applicable.
+ *
+ * Return: 0 in case of success, else appropriate error value
+ */
+static int ti_iodelay_pinconf_set(struct ti_iodelay_device *iod,
+				  struct ti_iodelay_conf_vals *val)
+{
+	const struct ti_iodelay_reg_data *reg = iod->reg_data;
+	struct ti_iodelay_reg_values *ival = &iod->reg_init_conf_values;
+	struct device *dev = iod->dev;
+	u32 g_delay_coarse, g_delay_fine;
+	u32 a_delay_coarse, a_delay_fine;
+	u32 c_elements, f_elements;
+	u32 total_delay;
+	u32 reg_mask, reg_val, tmp_val;
+	int r;
+
+	/* NOTE: Truncation is expected in all division below */
+	g_delay_coarse = val->g_delay / 920;
+	g_delay_fine = ((val->g_delay % 920) * 10) / 60;
+
+	a_delay_coarse = val->a_delay / ival->cdpe;
+	a_delay_fine = ((val->a_delay % ival->cdpe) * 10) / ival->fdpe;
+
+	c_elements = g_delay_coarse + a_delay_coarse;
+	f_elements = (g_delay_fine + a_delay_fine) / 10;
+
+	if (f_elements > 22) {
+		total_delay = c_elements * ival->cdpe + f_elements * ival->fdpe;
+		c_elements = total_delay / ival->cdpe;
+		f_elements = (total_delay % ival->cdpe) / ival->fdpe;
+	}
+
+	reg_mask = reg->signature_mask;
+	reg_val = reg->signature_value << __ffs(reg->signature_mask);
+
+	reg_mask |= reg->binary_data_coarse_mask;
+	tmp_val = c_elements << __ffs(reg->binary_data_coarse_mask);
+	if (tmp_val & ~reg->binary_data_coarse_mask) {
+		dev_err(dev, "Masking overflow of coarse elements %08x\n",
+			tmp_val);
+		tmp_val &= reg->binary_data_coarse_mask;
+	}
+	reg_val |= tmp_val;
+
+	reg_mask |= reg->binary_data_fine_mask;
+	tmp_val = f_elements << __ffs(reg->binary_data_fine_mask);
+	if (tmp_val & ~reg->binary_data_fine_mask) {
+		dev_err(dev, "Masking overflow of fine elements %08x\n",
+			tmp_val);
+		tmp_val &= reg->binary_data_fine_mask;
+	}
+	reg_val |= tmp_val;
+
+	/*
+	 * NOTE: we leave the iodelay values unlocked - this is to work around
+	 * situations such as those found with mmc mode change.
+	 * However, this leaves open any unwarranted changes to padconf register
+	 * impacting iodelay configuration. Use with care!
+	 */
+	reg_mask |= reg->lock_mask;
+	reg_val |= reg->unlock_val << __ffs(reg->lock_mask);
+	r = regmap_update_bits(iod->regmap, val->offset, reg_mask, reg_val);
+
+	dev_dbg(dev, "Set reg 0x%x Delay(a=%d g=%d), Elements(C=%d F=%d)0x%x\n",
+		val->offset, val->a_delay, val->g_delay, c_elements,
+		f_elements, reg_val);
+
+	return r;
+}
+
+/**
+ * ti_iodelay_pinconf_init_dev() - Initialize IODelay device
+ * @iod:	IODelay device
+ *
+ * Unlocks the IODelay region, computes the common parameters
+ *
+ * Return: 0 in case of success, else appropriate error value
+ */
+static int ti_iodelay_pinconf_init_dev(struct ti_iodelay_device *iod)
+{
+	const struct ti_iodelay_reg_data *reg = iod->reg_data;
+	struct device *dev = iod->dev;
+	struct ti_iodelay_reg_values *ival = &iod->reg_init_conf_values;
+	u32 val;
+	int r;
+
+	/* unlock the IOdelay region */
+	r = regmap_update_bits(iod->regmap, reg->reg_global_lock_offset,
+			       reg->global_lock_mask, reg->global_unlock_val);
+	if (r)
+		return r;
+
+	/* Read up Recalibration sequence done by bootloader */
+	r = regmap_read(iod->regmap, reg->reg_refclk_offset, &val);
+	if (r)
+		return r;
+	ival->ref_clk_period = ti_iodelay_extract(val, reg->refclk_period_mask);
+	dev_dbg(dev, "refclk_period=0x%04x\n", ival->ref_clk_period);
+
+	r = regmap_read(iod->regmap, reg->reg_coarse_offset, &val);
+	if (r)
+		return r;
+	ival->coarse_ref_count =
+	    ti_iodelay_extract(val, reg->coarse_ref_count_mask);
+	ival->coarse_delay_count =
+	    ti_iodelay_extract(val, reg->coarse_delay_count_mask);
+	if (!ival->coarse_delay_count) {
+		dev_err(dev, "Invalid Coarse delay count (0) (reg=0x%08x)\n",
+			val);
+		return -EINVAL;
+	}
+	ival->cdpe = ti_iodelay_compute_dpe(ival->ref_clk_period,
+					    ival->coarse_ref_count,
+					    ival->coarse_delay_count, 88);
+	if (!ival->cdpe) {
+		dev_err(dev, "Invalid cdpe computed params = %d %d %d\n",
+			ival->ref_clk_period, ival->coarse_ref_count,
+			ival->coarse_delay_count);
+		return -EINVAL;
+	}
+	dev_dbg(iod->dev, "coarse: ref=0x%04x delay=0x%04x cdpe=0x%08x\n",
+		ival->coarse_ref_count, ival->coarse_delay_count, ival->cdpe);
+
+	r = regmap_read(iod->regmap, reg->reg_fine_offset, &val);
+	if (r)
+		return r;
+	ival->fine_ref_count =
+	    ti_iodelay_extract(val, reg->fine_ref_count_mask);
+	ival->fine_delay_count =
+	    ti_iodelay_extract(val, reg->fine_delay_count_mask);
+	if (!ival->fine_delay_count) {
+		dev_err(dev, "Invalid Fine delay count (0) (reg=0x%08x)\n",
+			val);
+		return -EINVAL;
+	}
+	ival->fdpe = ti_iodelay_compute_dpe(ival->ref_clk_period,
+					    ival->fine_ref_count,
+					    ival->fine_delay_count, 264);
+	if (!ival->fdpe) {
+		dev_err(dev, "Invalid fdpe(0) computed params = %d %d %d\n",
+			ival->ref_clk_period, ival->fine_ref_count,
+			ival->fine_delay_count);
+		return -EINVAL;
+	}
+	dev_dbg(iod->dev, "fine: ref=0x%04x delay=0x%04x fdpe=0x%08x\n",
+		ival->fine_ref_count, ival->fine_delay_count, ival->fdpe);
+
+	return 0;
+}
+
+/**
+ * ti_iodelay_pinconf_deinit_dev() - deinit the IOdelay device
+ * @iod:	IODelay device
+ *
+ * Deinitialize the IODelay device (basically just lock the region back up.
+ */
+static void ti_iodelay_pinconf_deinit_dev(struct ti_iodelay_device *iod)
+{
+	const struct ti_iodelay_reg_data *reg = iod->reg_data;
+
+	/* lock the IOdelay region back again */
+	regmap_update_bits(iod->regmap, reg->reg_global_lock_offset,
+			   reg->global_lock_mask, reg->global_lock_val);
+}
+
+/*--- Pinctrl/pinconf framework stuff ----*/
+
+/**
+ * ti_iodelay_get_group() - Find the group mapped by a group selector
+ * @iod:	IODelay device
+ * @gselector:	Group Selector
+ *
+ * Return: Corresponding group representing group selector in list of groups
+ * managed in IOdelay device OR NULL if not found.
+ */
+static struct ti_iodelay_pingroup *ti_iodelay_get_group(struct ti_iodelay_device
+							*iod,
+							unsigned gselector)
+{
+	struct ti_iodelay_pingroup *group;
+	int gid = 0;
+
+	list_for_each_entry(group, &iod->groups, node) {
+		if (gid == gselector)
+			return group;
+		gid++;
+	}
+
+	dev_err(iod->dev, "%s could not find pingroup %i\n", __func__,
+		gselector);
+	return NULL;
+}
+
+/**
+ * ti_iodelay_dt_node_to_map() - Map a device tree node to appropriate group
+ * @pctldev:	pinctrl device representing IODelay device
+ * @np:		Node Pointer (device tree)
+ * @map:	Pinctrl Map returned back to pinctrl framework
+ * @num_maps:	Number of maps (1)
+ *
+ * Maps the device tree description into a group of configuration parameters
+ * for IOdelay block entry.
+ *
+ * Return: 0 in case of success, else appropriate error value
+ */
+static int ti_iodelay_dt_node_to_map(struct pinctrl_dev *pctldev,
+				     struct device_node *np,
+				     struct pinctrl_map **map,
+				     unsigned *num_maps)
+{
+	struct ti_iodelay_device *iod;
+	struct device *dev;
+	/* const char **pgnames; */
+	int ret = 0;
+	const __be32 *mux;
+	struct ti_iodelay_conf_vals *vals;
+	struct ti_iodelay_pingroup *group;
+	int size, index, idx, rows;
+	u32 offset, val;
+
+	iod = pinctrl_dev_get_drvdata(pctldev);
+	if (!iod)
+		return -EINVAL;
+	dev = iod->dev;
+
+	*map = devm_kzalloc(dev, sizeof(**map), GFP_KERNEL);
+	if (!*map)
+		return -ENOMEM;
+	*num_maps = 0;
+
+	group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
+	if (!group) {
+		ret = -ENOMEM;
+		goto free_map;
+	}
+
+	mux = of_get_property(np, IODELAY_MUX_PINS_NAME, &size);
+	if ((!mux) || (size < sizeof(*mux) * 2)) {
+		dev_err(dev, "bad data for mux %s\n", np->name);
+		ret = -EINVAL;
+		goto free_group;
+	}
+
+	size /= sizeof(*mux);	/* Number of elements in array */
+	rows = size / 2;
+
+	vals = devm_kzalloc(dev, sizeof(*vals) * rows, GFP_KERNEL);
+	if (!vals) {
+		ret = -ENOMEM;
+		goto free_group;
+	}
+
+	index = 0;
+	idx = 0;
+	while (index < size) {
+		offset = be32_to_cpup(mux + index++);
+		val = be32_to_cpup(mux + index++);
+		vals[idx].offset = offset;
+		vals[idx].a_delay = val & 0xFFFF;
+		vals[idx].g_delay = (val & 0xFFFF0000) >> 16;
+		if (offset > iod->reg_data->regmap_config->max_register) {
+			dev_err(dev, "Invalid offset for %s 0x%x\n",
+				np->name, offset);
+			break;
+		}
+		dev_dbg(dev, "%s offset=%x a_delay = %d g_delay = %d\n",
+			np->name, vals[idx].offset, vals[idx].a_delay,
+			vals[idx].g_delay);
+		idx++;
+	}
+
+	group->name = np->name;
+	group->np = np;
+	group->vals = vals;
+	group->nvals = idx;
+	group->config = PIN_CONFIG_END;
+	group->map = *map;
+
+	/* Add to group list */
+	mutex_lock(&iod->mutex);
+	list_add_tail(&group->node, &iod->groups);
+	iod->ngroups++;
+	mutex_unlock(&iod->mutex);
+
+	(*map)->type = PIN_MAP_TYPE_CONFIGS_GROUP;
+	(*map)->data.configs.group_or_pin = np->name;
+	(*map)->data.configs.configs = &group->config;
+	(*map)->data.configs.num_configs = 1;
+	*num_maps = 1;
+
+	return 0;
+
+free_group:
+	devm_kfree(dev, group);
+free_map:
+	devm_kfree(dev, *map);
+	return ret;
+}
+
+/**
+ * ti_iodelay_dt_free_map() - Free map and resource alloted as per the map
+ * @pctldev:	pinctrl device representing IODelay device
+ * @map:	Map allocated by ti_iodelay_dt_node_to_map
+ * @num_maps:	Num maps (1)
+ *
+ * Removes the group associated with the map and frees all resources allocated
+ * for the group.
+ */
+static void ti_iodelay_dt_free_map(struct pinctrl_dev *pctldev,
+				   struct pinctrl_map *map, unsigned num_maps)
+{
+	struct ti_iodelay_device *iod;
+	struct device *dev;
+	struct ti_iodelay_pingroup *group;
+	bool found = false;
+
+	if (!map)
+		return;
+
+	iod = pinctrl_dev_get_drvdata(pctldev);
+	if (!iod)
+		return;
+	dev = iod->dev;
+
+	mutex_lock(&iod->mutex);
+	list_for_each_entry(group, &iod->groups, node) {
+		if (group->map == map) {
+			found = true;
+			list_del(&group->node);
+			iod->ngroups--;
+			break;
+		}
+	}
+	mutex_unlock(&iod->mutex);
+
+	/* If some freaky pinconf framework bug... */
+	if (!found)
+		return;
+
+	devm_kfree(dev, group->vals);
+	devm_kfree(dev, group);
+	devm_kfree(dev, map);
+}
+
+/**
+ * ti_iodelay_pinctrl_get_groups_count() - Get number of groups registered
+ * @pctldev:	pinctrl device representing IODelay device
+ *
+ * Return: number of groups mapped on the IODelay
+ */
+static int ti_iodelay_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct ti_iodelay_device *iod;
+	struct device *dev;
+
+	iod = pinctrl_dev_get_drvdata(pctldev);
+	dev = iod->dev;
+
+	return iod->ngroups;
+}
+
+/**
+ * ti_iodelay_pinctrl_get_group_name() - Get the group name
+ * @pctldev:	pinctrl device representing IODelay device
+ * @gselector:	group selector
+ *
+ * Return: name of the Group given a valid gselector, else NULL.
+ */
+static const char *ti_iodelay_pinctrl_get_group_name(struct pinctrl_dev
+						     *pctldev,
+						     unsigned gselector)
+{
+	struct ti_iodelay_device *iod;
+	struct device *dev;
+	struct ti_iodelay_pingroup *group;
+
+	iod = pinctrl_dev_get_drvdata(pctldev);
+	dev = iod->dev;
+
+	group = ti_iodelay_get_group(iod, gselector);
+	if (!group)
+		return NULL;
+
+	return group->name;
+}
+
+/**
+ * ti_iodelay_pinctrl_get_group_pins() - get group pins
+ * @pctldev:	pinctrl device representing IODelay device
+ * @gselector: Group selector
+ * @pins:	pointer to the pins
+ * @npins:	number of pins
+ *
+ * Dummy implementation since we do not track pins, we track configurations
+ * Forced by pinctrl's pinctrl_check_ops()
+ *
+ * Return: -EINVAL
+ */
+static int ti_iodelay_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+					     unsigned gselector,
+					     const unsigned **pins,
+					     unsigned *npins)
+{
+	/* Dummy implementation - we dont do pin mux */
+	return -EINVAL;
+}
+
+/**
+ * ti_iodelay_pinconf_group_get() - Get the group configuration
+ * @pctldev:	pinctrl device representing IODelay device
+ * @gselector:	Group selector
+ * @config:	configuration returned
+ *
+ * Return: The configuration if the group is valid, else returns -EINVAL
+ */
+static int ti_iodelay_pinconf_group_get(struct pinctrl_dev *pctldev,
+					unsigned gselector,
+					unsigned long *config)
+{
+	struct ti_iodelay_device *iod;
+	struct device *dev;
+	struct ti_iodelay_pingroup *group;
+
+	iod = pinctrl_dev_get_drvdata(pctldev);
+	dev = iod->dev;
+	group = ti_iodelay_get_group(iod, gselector);
+
+	if (!group)
+		return -EINVAL;
+
+	*config = group->config;
+	return 0;
+}
+
+/**
+ * ti_iodelay_pinconf_group_set() - Configure the groups of pins
+ * @pctldev:	pinctrl device representing IODelay device
+ * @gselector:	Group selector
+ * @configs:	Configurations
+ * @num_configs: Number of configurations
+ *
+ * Return: 0 if all went fine, else appropriate error value.
+ */
+static int ti_iodelay_pinconf_group_set(struct pinctrl_dev *pctldev,
+					unsigned gselector,
+					unsigned long *configs,
+					unsigned num_configs)
+{
+	struct ti_iodelay_device *iod;
+	struct device *dev;
+	struct ti_iodelay_pingroup *group;
+	int i;
+
+	iod = pinctrl_dev_get_drvdata(pctldev);
+	dev = iod->dev;
+	group = ti_iodelay_get_group(iod, gselector);
+
+	if (num_configs != 1) {
+		dev_err(dev, "Unsupported number of configurations %d\n",
+			num_configs);
+		return -EINVAL;
+	}
+
+	if (*configs != PIN_CONFIG_END) {
+		dev_err(dev, "Unsupported configuration\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < group->nvals; i++) {
+		if (ti_iodelay_pinconf_set(iod, &group->vals[i]))
+			return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+/**
+ * ti_iodelay_pinconf_group_dbg_show() - show the group information
+ * @pctldev:	Show the group information
+ * @s:	Sequence file
+ * @gselector:	group selector
+ *
+ * Provide the configuration information of the selected group
+ */
+static void ti_iodelay_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+					      struct seq_file *s,
+					      unsigned gselector)
+{
+	struct ti_iodelay_device *iod;
+	struct device *dev;
+	struct ti_iodelay_pingroup *group;
+	int i;
+
+	iod = pinctrl_dev_get_drvdata(pctldev);
+	dev = iod->dev;
+	group = ti_iodelay_get_group(iod, gselector);
+	if (!group)
+		return;
+
+	for (i = 0; i < group->nvals; i++) {
+		struct ti_iodelay_conf_vals *val;
+		u32 reg = 0;
+
+		val = &group->vals[i];
+		regmap_read(iod->regmap, val->offset, &reg),
+		    seq_printf(s, "\n\t0x%08x = 0x%08x (%3d, %3d)",
+			       val->offset, reg, val->a_delay, val->g_delay);
+	}
+}
+#endif
+
+static struct pinctrl_ops ti_iodelay_pinctrl_ops = {
+	.dt_node_to_map = ti_iodelay_dt_node_to_map,
+	.dt_free_map = ti_iodelay_dt_free_map,
+	.get_groups_count = ti_iodelay_pinctrl_get_groups_count,
+	.get_group_name = ti_iodelay_pinctrl_get_group_name,
+	.get_group_pins = ti_iodelay_pinctrl_get_group_pins,
+};
+
+static struct pinconf_ops ti_iodelay_pinctrl_pinconf_ops = {
+	.pin_config_group_get = ti_iodelay_pinconf_group_get,
+	.pin_config_group_set = ti_iodelay_pinconf_group_set,
+#ifdef CONFIG_DEBUG_FS
+	.pin_config_group_dbg_show = ti_iodelay_pinconf_group_dbg_show,
+#endif
+};
+
+/**
+ * ti_iodelay_alloc_pins() - Allocate structures needed for pins for IOdelay
+ * @dev:	device pointer
+ * @iod:	IODelay device
+ * @base_phy:	Base Physical Address
+ *
+ * Return: 0 if all went fine, else appropriate error value.
+ */
+static int ti_iodelay_alloc_pins(struct device *dev,
+				 struct ti_iodelay_device *iod, u32 base_phy)
+{
+	const struct ti_iodelay_reg_data *r = iod->reg_data;
+	struct pinctrl_pin_desc *pin;
+	struct ti_iodelay_pin_name *pn;
+	u32 phy_reg;
+	int nr_pins, i;
+
+	nr_pins = (r->regmap_config->max_register - r->reg_start_offset) / 4;
+
+	dev_dbg(dev, "Allocating %i pins\n", nr_pins);
+
+	iod->pa = devm_kzalloc(dev, sizeof(*iod->pa) * nr_pins, GFP_KERNEL);
+	if (!iod->pa)
+		return -ENOMEM;
+
+	iod->names =
+	    devm_kzalloc(dev, sizeof(struct ti_iodelay_pin_name) * nr_pins,
+			 GFP_KERNEL);
+	if (!iod->names)
+		return -ENOMEM;
+
+	iod->desc.pins = iod->pa;
+	iod->desc.npins = nr_pins;
+
+	phy_reg = r->reg_start_offset + base_phy;
+	pn = iod->names;
+	for (i = 0; i < nr_pins; i++, pn++, phy_reg += 4) {
+		pin = &iod->pa[i];
+		sprintf(pn->name, "%x.%d", phy_reg, i);
+		pin->number = i;
+		pin->name = pn->name;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_iodelay_probe() - Standard probe
+ * @pdev:	platform device
+ *
+ * Return: 0 if all went fine, else appropriate error value.
+ */
+static int ti_iodelay_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = of_node_get(dev->of_node);
+	const struct of_device_id *match;
+	struct resource *res;
+	struct ti_iodelay_device *iod;
+	int ret = 0;
+
+	if (!np) {
+		ret = -EINVAL;
+		dev_err(dev, "No OF node\n");
+		goto exit_out;
+	}
+
+	match = of_match_device(ti_iodelay_of_match, dev);
+	if (!match) {
+		ret = -EINVAL;
+		dev_err(dev, "No DATA match\n");
+		goto exit_out;
+	}
+
+	iod = devm_kzalloc(dev, sizeof(*iod), GFP_KERNEL);
+	if (!iod) {
+		ret = -ENOMEM;
+		goto exit_out;
+	}
+	iod->dev = dev;
+	iod->reg_data = match->data;
+
+	/* So far We can assume there is only 1 bank of registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "Missing MEM resource\n");
+		ret = -ENODEV;
+		goto exit_out;
+	}
+
+	iod->reg_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(iod->reg_base)) {
+		ret = PTR_ERR(iod->reg_base);
+		goto exit_out;
+	}
+
+	iod->regmap = devm_regmap_init_mmio(dev, iod->reg_base,
+					    iod->reg_data->regmap_config);
+	if (IS_ERR(iod->regmap)) {
+		dev_err(dev, "Regmap MMIO init failed.\n");
+		ret = PTR_ERR(iod->regmap);
+		goto exit_out;
+	}
+
+	if (ti_iodelay_pinconf_init_dev(iod))
+		goto exit_out;
+
+	ret = ti_iodelay_alloc_pins(dev, iod, res->start);
+	if (ret)
+		goto exit_out;
+
+	INIT_LIST_HEAD(&iod->groups);
+	mutex_init(&iod->mutex);
+
+	iod->desc.pctlops = &ti_iodelay_pinctrl_ops;
+	/* no pinmux ops - we are pinconf */
+	iod->desc.confops = &ti_iodelay_pinctrl_pinconf_ops;
+	iod->desc.name = dev_name(dev);
+	iod->desc.owner = THIS_MODULE;
+
+	iod->pctl = pinctrl_register(&iod->desc, dev, iod);
+	if (!iod->pctl) {
+		dev_err(dev, "Failed to register pinctrl\n");
+		ret = -ENODEV;
+		goto exit_out;
+	}
+
+	platform_set_drvdata(pdev, iod);
+
+exit_out:
+	of_node_put(np);
+	return ret;
+}
+
+/**
+ * ti_iodelay_remove() - standard remove
+ * @pdev:	platform device
+ *
+ * Return: 0 if all went fine, else appropriate error value.
+ */
+static int ti_iodelay_remove(struct platform_device *pdev)
+{
+	struct ti_iodelay_device *iod = platform_get_drvdata(pdev);
+
+	if (!iod)
+		return 0;
+	if (iod->pctl)
+		pinctrl_unregister(iod->pctl);
+
+	ti_iodelay_pinconf_deinit_dev(iod);
+
+	/* Expect other allocations to be freed by devm */
+
+	return 0;
+}
+
+static struct regmap_config dra7_iodelay_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = 0xD1C,
+};
+
+static struct ti_iodelay_reg_data dra7_iodelay_data = {
+	.signature_mask = 0x0003F000,
+	.signature_value = 0x29,
+	.lock_mask = 0x00000400,
+	.lock_val = 1,
+	.unlock_val = 0,
+	.binary_data_coarse_mask = 0x000003E0,
+	.binary_data_fine_mask = 0x0000001F,
+
+	.reg_refclk_offset = 0x14,
+	.refclk_period_mask = 0xFFFF,
+
+	.reg_coarse_offset = 0x18,
+	.coarse_delay_count_mask = 0xFFFF0000,
+	.coarse_ref_count_mask = 0x0000FFFF,
+
+	.reg_fine_offset = 0x1C,
+	.fine_delay_count_mask = 0xFFFF0000,
+	.fine_ref_count_mask = 0x0000FFFF,
+
+	.reg_global_lock_offset = 0x2C,
+	.global_lock_mask = 0x0000FFFF,
+	.global_unlock_val = 0x0000AAAA,
+	.global_lock_val = 0x0000AAAB,
+
+	.reg_start_offset = 0x30,
+	.regmap_config = &dra7_iodelay_regmap_config,
+};
+
+static const struct of_device_id ti_iodelay_of_match[] = {
+	{.compatible = "ti,dra7-iodelay", .data = &dra7_iodelay_data},
+	{ /* Hopefully no more.. */ },
+};
+MODULE_DEVICE_TABLE(of, ti_iodelay_of_match);
+
+static struct platform_driver ti_iodelay_driver = {
+	.probe = ti_iodelay_probe,
+	.remove = ti_iodelay_remove,
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = DRIVER_NAME,
+		   .of_match_table = ti_iodelay_of_match,
+		   },
+};
+module_platform_driver(ti_iodelay_driver);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("Pinconf driver for TI's IO Delay module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index e3c19f3..f9c5fa5 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -713,11 +713,11 @@ static int spidev_probe(struct spi_device *spi)
 	 * compatible string, it is a Linux implementation thing
 	 * rather than a description of the hardware.
 	 */
-	if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
-		dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
-		WARN_ON(spi->dev.of_node &&
-			!of_match_device(spidev_dt_ids, &spi->dev));
-	}
+//	if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
+//		dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
+//		WARN_ON(spi->dev.of_node &&
+//			!of_match_device(spidev_dt_ids, &spi->dev));
+//	}
 
 	/* Allocate driver data */
 	spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c
index ba9fc44..82b46cd 100644
--- a/drivers/staging/fbtft/fb_agm1264k-fl.c
+++ b/drivers/staging/fbtft/fb_agm1264k-fl.c
@@ -414,7 +414,7 @@ static int write(struct fbtft_par *par, void *buf, size_t len)
 	while (len--) {
 		u8 i, data;
 
-		data = *(u8 *) buf++;
+		data = *(u8 *)buf++;
 
 		/* set data bus */
 		for (i = 0; i < 8; ++i)
diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c
index a6f091f..4dcea2e 100644
--- a/drivers/staging/fbtft/fbtft-io.c
+++ b/drivers/staging/fbtft/fbtft-io.c
@@ -141,7 +141,7 @@ int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
 		"%s(len=%d): ", __func__, len);
 
 	while (len--) {
-		data = *(u8 *) buf;
+		data = *(u8 *)buf;
 
 		/* Start writing by pulling down /WR */
 		gpio_set_value(par->gpio.wr, 0);
@@ -170,7 +170,7 @@ int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
 		gpio_set_value(par->gpio.wr, 1);
 
 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
-		prev_data = *(u8 *) buf;
+		prev_data = *(u8 *)buf;
 #endif
 		buf++;
 	}
@@ -191,7 +191,7 @@ int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
 		"%s(len=%d): ", __func__, len);
 
 	while (len) {
-		data = *(u16 *) buf;
+		data = *(u16 *)buf;
 
 		/* Start writing by pulling down /WR */
 		gpio_set_value(par->gpio.wr, 0);
@@ -220,7 +220,7 @@ int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
 		gpio_set_value(par->gpio.wr, 1);
 
 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
-		prev_data = *(u16 *) buf;
+		prev_data = *(u16 *)buf;
 #endif
 		buf += 2;
 		len -= 2;
diff --git a/drivers/staging/fbtft/fbtft_device.c b/drivers/staging/fbtft/fbtft_device.c
index 241d7c6..e4a355a 100644
--- a/drivers/staging/fbtft/fbtft_device.c
+++ b/drivers/staging/fbtft/fbtft_device.c
@@ -1254,7 +1254,7 @@ static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len)
 		"%s(len=%d): ", __func__, len);
 
 	while (len) {
-		data = *(u16 *) buf;
+		data = *(u16 *)buf;
 
 		/* Start writing by pulling down /WR */
 		gpio_set_value(par->gpio.wr, 0);
@@ -1283,7 +1283,7 @@ static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len)
 		gpio_set_value(par->gpio.wr, 1);
 
 #ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
-		prev_data = *(u16 *) buf;
+		prev_data = *(u16 *)buf;
 #endif
 		buf += 2;
 		len -= 2;
@@ -1436,7 +1436,7 @@ static int __init fbtft_device_init(void)
 		}
 		strncpy(fbtft_device_param_gpios[i].name, p_name,
 			FBTFT_GPIO_NAME_SIZE - 1);
-		fbtft_device_param_gpios[i++].gpio = (int) val;
+		fbtft_device_param_gpios[i++].gpio = (int)val;
 		if (i == MAX_GPIOS) {
 			pr_err("gpios parameter: exceeded max array size: %d\n",
 			       MAX_GPIOS);
diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
index fa67da9..1c994b5 100644
--- a/drivers/staging/iio/accel/Kconfig
+++ b/drivers/staging/iio/accel/Kconfig
@@ -27,18 +27,6 @@ config ADIS16203
 	  To compile this driver as a module, say M here: the module will be
 	  called adis16203.
 
-config ADIS16204
-	tristate "Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder"
-	depends on SPI
-	select IIO_ADIS_LIB
-	select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
-	help
-	  Say Y here to build support for Analog Devices adis16204 Programmable
-	  High-g Digital Impact Sensor and Recorder.
-
-	  To compile this driver as a module, say M here: the module will be
-	  called adis16204.
-
 config ADIS16209
 	tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
 	depends on SPI
@@ -51,17 +39,6 @@ config ADIS16209
 	  To compile this driver as a module, say M here: the module will be
 	  called adis16209.
 
-config ADIS16220
-	tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor"
-	depends on SPI
-	select IIO_ADIS_LIB
-	help
-	  Say Y here to build support for Analog Devices adis16220 programmable
-	  digital vibration sensor.
-
-	  To compile this driver as a module, say M here: the module will be
-	  called adis16220.
-
 config ADIS16240
 	tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder"
 	depends on SPI
@@ -74,20 +51,6 @@ config ADIS16240
 	  To compile this driver as a module, say M here: the module will be
 	  called adis16240.
 
-config LIS3L02DQ
-	tristate "ST Microelectronics LIS3L02DQ Accelerometer Driver"
-	depends on SPI
-	select IIO_TRIGGER if IIO_BUFFER
-	depends on !IIO_BUFFER || IIO_KFIFO_BUF
-	depends on GPIOLIB || COMPILE_TEST
-	help
-	  Say Y here to build SPI support for the ST microelectronics
-	  accelerometer. The driver supplies direct access via sysfs files
-	  and an event interface via a character device.
-
-	  To compile this driver as a module, say M here: the module will be
-	  called lis3l02dq.
-
 config SCA3000
 	depends on IIO_BUFFER
 	depends on SPI
diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
index 1ed137f..1810a43 100644
--- a/drivers/staging/iio/accel/Makefile
+++ b/drivers/staging/iio/accel/Makefile
@@ -8,21 +8,11 @@ obj-$(CONFIG_ADIS16201) += adis16201.o
 adis16203-y             := adis16203_core.o
 obj-$(CONFIG_ADIS16203) += adis16203.o
 
-adis16204-y             := adis16204_core.o
-obj-$(CONFIG_ADIS16204) += adis16204.o
-
 adis16209-y             := adis16209_core.o
 obj-$(CONFIG_ADIS16209) += adis16209.o
 
-adis16220-y             := adis16220_core.o
-obj-$(CONFIG_ADIS16220) += adis16220.o
-
 adis16240-y             := adis16240_core.o
 obj-$(CONFIG_ADIS16240) += adis16240.o
 
-lis3l02dq-y		:= lis3l02dq_core.o
-lis3l02dq-$(CONFIG_IIO_BUFFER) += lis3l02dq_ring.o
-obj-$(CONFIG_LIS3L02DQ)	+= lis3l02dq.o
-
 sca3000-y		:= sca3000_core.o sca3000_ring.o
 obj-$(CONFIG_SCA3000)	+= sca3000.o
diff --git a/drivers/staging/iio/accel/adis16201.h b/drivers/staging/iio/accel/adis16201.h
index e6b8c9a..64844ad 100644
--- a/drivers/staging/iio/accel/adis16201.h
+++ b/drivers/staging/iio/accel/adis16201.h
@@ -3,51 +3,129 @@
 
 #define ADIS16201_STARTUP_DELAY	220 /* ms */
 
-#define ADIS16201_FLASH_CNT      0x00 /* Flash memory write count */
-#define ADIS16201_SUPPLY_OUT     0x02 /* Output, power supply */
-#define ADIS16201_XACCL_OUT      0x04 /* Output, x-axis accelerometer */
-#define ADIS16201_YACCL_OUT      0x06 /* Output, y-axis accelerometer */
-#define ADIS16201_AUX_ADC        0x08 /* Output, auxiliary ADC input */
-#define ADIS16201_TEMP_OUT       0x0A /* Output, temperature */
-#define ADIS16201_XINCL_OUT      0x0C /* Output, x-axis inclination */
-#define ADIS16201_YINCL_OUT      0x0E /* Output, y-axis inclination */
-#define ADIS16201_XACCL_OFFS     0x10 /* Calibration, x-axis acceleration offset */
-#define ADIS16201_YACCL_OFFS     0x12 /* Calibration, y-axis acceleration offset */
-#define ADIS16201_XACCL_SCALE    0x14 /* x-axis acceleration scale factor */
-#define ADIS16201_YACCL_SCALE    0x16 /* y-axis acceleration scale factor */
-#define ADIS16201_XINCL_OFFS     0x18 /* Calibration, x-axis inclination offset */
-#define ADIS16201_YINCL_OFFS     0x1A /* Calibration, y-axis inclination offset */
-#define ADIS16201_XINCL_SCALE    0x1C /* x-axis inclination scale factor */
-#define ADIS16201_YINCL_SCALE    0x1E /* y-axis inclination scale factor */
-#define ADIS16201_ALM_MAG1       0x20 /* Alarm 1 amplitude threshold */
-#define ADIS16201_ALM_MAG2       0x22 /* Alarm 2 amplitude threshold */
-#define ADIS16201_ALM_SMPL1      0x24 /* Alarm 1, sample period */
-#define ADIS16201_ALM_SMPL2      0x26 /* Alarm 2, sample period */
-#define ADIS16201_ALM_CTRL       0x28 /* Alarm control */
-#define ADIS16201_AUX_DAC        0x30 /* Auxiliary DAC data */
-#define ADIS16201_GPIO_CTRL      0x32 /* General-purpose digital input/output control */
-#define ADIS16201_MSC_CTRL       0x34 /* Miscellaneous control */
-#define ADIS16201_SMPL_PRD       0x36 /* Internal sample period (rate) control */
-#define ADIS16201_AVG_CNT        0x38 /* Operation, filter configuration */
-#define ADIS16201_SLP_CNT        0x3A /* Operation, sleep mode control */
-#define ADIS16201_DIAG_STAT      0x3C /* Diagnostics, system status register */
-#define ADIS16201_GLOB_CMD       0x3E /* Operation, system command register */
+/* Flash memory write count */
+#define ADIS16201_FLASH_CNT      0x00
+
+/* Output, power supply */
+#define ADIS16201_SUPPLY_OUT     0x02
+
+/* Output, x-axis accelerometer */
+#define ADIS16201_XACCL_OUT      0x04
+
+/* Output, y-axis accelerometer */
+#define ADIS16201_YACCL_OUT      0x06
+
+/* Output, auxiliary ADC input */
+#define ADIS16201_AUX_ADC        0x08
+
+/* Output, temperature */
+#define ADIS16201_TEMP_OUT       0x0A
+
+/* Output, x-axis inclination */
+#define ADIS16201_XINCL_OUT      0x0C
+
+/* Output, y-axis inclination */
+#define ADIS16201_YINCL_OUT      0x0E
+
+/* Calibration, x-axis acceleration offset */
+#define ADIS16201_XACCL_OFFS     0x10
+
+/* Calibration, y-axis acceleration offset */
+#define ADIS16201_YACCL_OFFS     0x12
+
+/* x-axis acceleration scale factor */
+#define ADIS16201_XACCL_SCALE    0x14
+
+/* y-axis acceleration scale factor */
+#define ADIS16201_YACCL_SCALE    0x16
+
+/* Calibration, x-axis inclination offset */
+#define ADIS16201_XINCL_OFFS     0x18
+
+/* Calibration, y-axis inclination offset */
+#define ADIS16201_YINCL_OFFS     0x1A
+
+/* x-axis inclination scale factor */
+#define ADIS16201_XINCL_SCALE    0x1C
+
+/* y-axis inclination scale factor */
+#define ADIS16201_YINCL_SCALE    0x1E
+
+/* Alarm 1 amplitude threshold */
+#define ADIS16201_ALM_MAG1       0x20
+
+/* Alarm 2 amplitude threshold */
+#define ADIS16201_ALM_MAG2       0x22
+
+/* Alarm 1, sample period */
+#define ADIS16201_ALM_SMPL1      0x24
+
+/* Alarm 2, sample period */
+#define ADIS16201_ALM_SMPL2      0x26
+
+/* Alarm control */
+#define ADIS16201_ALM_CTRL       0x28
+
+/* Auxiliary DAC data */
+#define ADIS16201_AUX_DAC        0x30
+
+/* General-purpose digital input/output control */
+#define ADIS16201_GPIO_CTRL      0x32
+
+/* Miscellaneous control */
+#define ADIS16201_MSC_CTRL       0x34
+
+/* Internal sample period (rate) control */
+#define ADIS16201_SMPL_PRD       0x36
+
+/* Operation, filter configuration */
+#define ADIS16201_AVG_CNT        0x38
+
+/* Operation, sleep mode control */
+#define ADIS16201_SLP_CNT        0x3A
+
+/* Diagnostics, system status register */
+#define ADIS16201_DIAG_STAT      0x3C
+
+/* Operation, system command register */
+#define ADIS16201_GLOB_CMD       0x3E
 
 /* MSC_CTRL */
-#define ADIS16201_MSC_CTRL_SELF_TEST_EN	        BIT(8)  /* Self-test enable */
-#define ADIS16201_MSC_CTRL_DATA_RDY_EN	        BIT(2)  /* Data-ready enable: 1 = enabled, 0 = disabled */
-#define ADIS16201_MSC_CTRL_ACTIVE_HIGH	        BIT(1)  /* Data-ready polarity: 1 = active high, 0 = active low */
-#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1	BIT(0)  /* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
+
+/* Self-test enable */
+#define ADIS16201_MSC_CTRL_SELF_TEST_EN	        BIT(8)
+
+/* Data-ready enable: 1 = enabled, 0 = disabled */
+#define ADIS16201_MSC_CTRL_DATA_RDY_EN	        BIT(2)
+
+/* Data-ready polarity: 1 = active high, 0 = active low */
+#define ADIS16201_MSC_CTRL_ACTIVE_HIGH	        BIT(1)
+
+/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
+#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1	BIT(0)
 
 /* DIAG_STAT */
-#define ADIS16201_DIAG_STAT_ALARM2        BIT(9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
-#define ADIS16201_DIAG_STAT_ALARM1        BIT(8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
-#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT   3 /* SPI communications failure */
-#define ADIS16201_DIAG_STAT_FLASH_UPT_BIT  2 /* Flash update failure */
-#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1 /* Power supply above 3.625 V */
-#define ADIS16201_DIAG_STAT_POWER_LOW_BIT  0 /* Power supply below 3.15 V */
+
+/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16201_DIAG_STAT_ALARM2        BIT(9)
+
+/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16201_DIAG_STAT_ALARM1        BIT(8)
+
+/* SPI communications failure */
+#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT   3
+
+/* Flash update failure */
+#define ADIS16201_DIAG_STAT_FLASH_UPT_BIT  2
+
+/* Power supply above 3.625 V */
+#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1
+
+/* Power supply below 3.15 V */
+#define ADIS16201_DIAG_STAT_POWER_LOW_BIT  0
 
 /* GLOB_CMD */
+
 #define ADIS16201_GLOB_CMD_SW_RESET	BIT(7)
 #define ADIS16201_GLOB_CMD_FACTORY_CAL	BIT(1)
 
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
index 06c0b75..6f3f8ff 100644
--- a/drivers/staging/iio/accel/adis16201_core.c
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -167,6 +167,7 @@ static const struct adis_data adis16201_data = {
 	.diag_stat_reg = ADIS16201_DIAG_STAT,
 
 	.self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN,
+	.self_test_no_autoclear = true,
 	.startup_delay = ADIS16201_STARTUP_DELAY,
 
 	.status_error_msgs = adis16201_status_error_msgs,
diff --git a/drivers/staging/iio/accel/adis16203.h b/drivers/staging/iio/accel/adis16203.h
index 6426e38..b483e4e 100644
--- a/drivers/staging/iio/accel/adis16203.h
+++ b/drivers/staging/iio/accel/adis16203.h
@@ -3,45 +3,111 @@
 
 #define ADIS16203_STARTUP_DELAY	220 /* ms */
 
-#define ADIS16203_FLASH_CNT      0x00 /* Flash memory write count */
-#define ADIS16203_SUPPLY_OUT     0x02 /* Output, power supply */
-#define ADIS16203_AUX_ADC        0x08 /* Output, auxiliary ADC input */
-#define ADIS16203_TEMP_OUT       0x0A /* Output, temperature */
-#define ADIS16203_XINCL_OUT      0x0C /* Output, x-axis inclination */
-#define ADIS16203_YINCL_OUT      0x0E /* Output, y-axis inclination */
-#define ADIS16203_INCL_NULL      0x18 /* Incline null calibration */
-#define ADIS16203_ALM_MAG1       0x20 /* Alarm 1 amplitude threshold */
-#define ADIS16203_ALM_MAG2       0x22 /* Alarm 2 amplitude threshold */
-#define ADIS16203_ALM_SMPL1      0x24 /* Alarm 1, sample period */
-#define ADIS16203_ALM_SMPL2      0x26 /* Alarm 2, sample period */
-#define ADIS16203_ALM_CTRL       0x28 /* Alarm control */
-#define ADIS16203_AUX_DAC        0x30 /* Auxiliary DAC data */
-#define ADIS16203_GPIO_CTRL      0x32 /* General-purpose digital input/output control */
-#define ADIS16203_MSC_CTRL       0x34 /* Miscellaneous control */
-#define ADIS16203_SMPL_PRD       0x36 /* Internal sample period (rate) control */
-#define ADIS16203_AVG_CNT        0x38 /* Operation, filter configuration */
-#define ADIS16203_SLP_CNT        0x3A /* Operation, sleep mode control */
-#define ADIS16203_DIAG_STAT      0x3C /* Diagnostics, system status register */
-#define ADIS16203_GLOB_CMD       0x3E /* Operation, system command register */
+/* Flash memory write count */
+#define ADIS16203_FLASH_CNT      0x00
+
+/* Output, power supply */
+#define ADIS16203_SUPPLY_OUT     0x02
+
+/* Output, auxiliary ADC input */
+#define ADIS16203_AUX_ADC        0x08
+
+/* Output, temperature */
+#define ADIS16203_TEMP_OUT       0x0A
+
+/* Output, x-axis inclination */
+#define ADIS16203_XINCL_OUT      0x0C
+
+/* Output, y-axis inclination */
+#define ADIS16203_YINCL_OUT      0x0E
+
+/* Incline null calibration */
+#define ADIS16203_INCL_NULL      0x18
+
+/* Alarm 1 amplitude threshold */
+#define ADIS16203_ALM_MAG1       0x20
+
+/* Alarm 2 amplitude threshold */
+#define ADIS16203_ALM_MAG2       0x22
+
+/* Alarm 1, sample period */
+#define ADIS16203_ALM_SMPL1      0x24
+
+/* Alarm 2, sample period */
+#define ADIS16203_ALM_SMPL2      0x26
+
+/* Alarm control */
+#define ADIS16203_ALM_CTRL       0x28
+
+/* Auxiliary DAC data */
+#define ADIS16203_AUX_DAC        0x30
+
+/* General-purpose digital input/output control */
+#define ADIS16203_GPIO_CTRL      0x32
+
+/* Miscellaneous control */
+#define ADIS16203_MSC_CTRL       0x34
+
+/* Internal sample period (rate) control */
+#define ADIS16203_SMPL_PRD       0x36
+
+/* Operation, filter configuration */
+#define ADIS16203_AVG_CNT        0x38
+
+/* Operation, sleep mode control */
+#define ADIS16203_SLP_CNT        0x3A
+
+/* Diagnostics, system status register */
+#define ADIS16203_DIAG_STAT      0x3C
+
+/* Operation, system command register */
+#define ADIS16203_GLOB_CMD       0x3E
 
 /* MSC_CTRL */
-#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST	BIT(10) /* Self-test at power-on: 1 = disabled, 0 = enabled */
-#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN	BIT(9)  /* Reverses rotation of both inclination outputs */
-#define ADIS16203_MSC_CTRL_SELF_TEST_EN	        BIT(8)  /* Self-test enable */
-#define ADIS16203_MSC_CTRL_DATA_RDY_EN	        BIT(2)  /* Data-ready enable: 1 = enabled, 0 = disabled */
-#define ADIS16203_MSC_CTRL_ACTIVE_HIGH	        BIT(1)  /* Data-ready polarity: 1 = active high, 0 = active low */
-#define ADIS16203_MSC_CTRL_DATA_RDY_DIO1	BIT(0)  /* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
+
+/* Self-test at power-on: 1 = disabled, 0 = enabled */
+#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST	BIT(10)
+
+/* Reverses rotation of both inclination outputs */
+#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN	BIT(9)
+
+/* Self-test enable */
+#define ADIS16203_MSC_CTRL_SELF_TEST_EN	        BIT(8)
+
+/* Data-ready enable: 1 = enabled, 0 = disabled */
+#define ADIS16203_MSC_CTRL_DATA_RDY_EN	        BIT(2)
+
+/* Data-ready polarity: 1 = active high, 0 = active low */
+#define ADIS16203_MSC_CTRL_ACTIVE_HIGH	        BIT(1)
+
+/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
+#define ADIS16203_MSC_CTRL_DATA_RDY_DIO1	BIT(0)
 
 /* DIAG_STAT */
-#define ADIS16203_DIAG_STAT_ALARM2        BIT(9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
-#define ADIS16203_DIAG_STAT_ALARM1        BIT(8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
-#define ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT 5 /* Self-test diagnostic error flag */
-#define ADIS16203_DIAG_STAT_SPI_FAIL_BIT      3 /* SPI communications failure */
-#define ADIS16203_DIAG_STAT_FLASH_UPT_BIT     2 /* Flash update failure */
-#define ADIS16203_DIAG_STAT_POWER_HIGH_BIT    1 /* Power supply above 3.625 V */
-#define ADIS16203_DIAG_STAT_POWER_LOW_BIT     0 /* Power supply below 3.15 V */
+
+/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16203_DIAG_STAT_ALARM2        BIT(9)
+
+/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16203_DIAG_STAT_ALARM1        BIT(8)
+
+/* Self-test diagnostic error flag */
+#define ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT 5
+
+/* SPI communications failure */
+#define ADIS16203_DIAG_STAT_SPI_FAIL_BIT      3
+
+/* Flash update failure */
+#define ADIS16203_DIAG_STAT_FLASH_UPT_BIT     2
+
+/* Power supply above 3.625 V */
+#define ADIS16203_DIAG_STAT_POWER_HIGH_BIT    1
+
+/* Power supply below 3.15 V */
+#define ADIS16203_DIAG_STAT_POWER_LOW_BIT     0
 
 /* GLOB_CMD */
+
 #define ADIS16203_GLOB_CMD_SW_RESET	BIT(7)
 #define ADIS16203_GLOB_CMD_CLEAR_STAT	BIT(4)
 #define ADIS16203_GLOB_CMD_FACTORY_CAL	BIT(1)
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
index de5b84a..c706717 100644
--- a/drivers/staging/iio/accel/adis16203_core.c
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -134,6 +134,7 @@ static const struct adis_data adis16203_data = {
 	.diag_stat_reg = ADIS16203_DIAG_STAT,
 
 	.self_test_mask = ADIS16203_MSC_CTRL_SELF_TEST_EN,
+	.self_test_no_autoclear = true,
 	.startup_delay = ADIS16203_STARTUP_DELAY,
 
 	.status_error_msgs = adis16203_status_error_msgs,
diff --git a/drivers/staging/iio/accel/adis16209.h b/drivers/staging/iio/accel/adis16209.h
index 813698d..315f1c0 100644
--- a/drivers/staging/iio/accel/adis16209.h
+++ b/drivers/staging/iio/accel/adis16209.h
@@ -5,88 +5,127 @@
 
 /* Flash memory write count */
 #define ADIS16209_FLASH_CNT      0x00
+
 /* Output, power supply */
 #define ADIS16209_SUPPLY_OUT     0x02
+
 /* Output, x-axis accelerometer */
 #define ADIS16209_XACCL_OUT      0x04
+
 /* Output, y-axis accelerometer */
 #define ADIS16209_YACCL_OUT      0x06
+
 /* Output, auxiliary ADC input */
 #define ADIS16209_AUX_ADC        0x08
+
 /* Output, temperature */
 #define ADIS16209_TEMP_OUT       0x0A
+
 /* Output, x-axis inclination */
 #define ADIS16209_XINCL_OUT      0x0C
+
 /* Output, y-axis inclination */
 #define ADIS16209_YINCL_OUT      0x0E
+
 /* Output, +/-180 vertical rotational position */
 #define ADIS16209_ROT_OUT        0x10
+
 /* Calibration, x-axis acceleration offset null */
 #define ADIS16209_XACCL_NULL     0x12
+
 /* Calibration, y-axis acceleration offset null */
 #define ADIS16209_YACCL_NULL     0x14
+
 /* Calibration, x-axis inclination offset null */
 #define ADIS16209_XINCL_NULL     0x16
+
 /* Calibration, y-axis inclination offset null */
 #define ADIS16209_YINCL_NULL     0x18
+
 /* Calibration, vertical rotation offset null */
 #define ADIS16209_ROT_NULL       0x1A
+
 /* Alarm 1 amplitude threshold */
 #define ADIS16209_ALM_MAG1       0x20
+
 /* Alarm 2 amplitude threshold */
 #define ADIS16209_ALM_MAG2       0x22
+
 /* Alarm 1, sample period */
 #define ADIS16209_ALM_SMPL1      0x24
+
 /* Alarm 2, sample period */
 #define ADIS16209_ALM_SMPL2      0x26
+
 /* Alarm control */
 #define ADIS16209_ALM_CTRL       0x28
+
 /* Auxiliary DAC data */
 #define ADIS16209_AUX_DAC        0x30
+
 /* General-purpose digital input/output control */
 #define ADIS16209_GPIO_CTRL      0x32
+
 /* Miscellaneous control */
 #define ADIS16209_MSC_CTRL       0x34
+
 /* Internal sample period (rate) control */
 #define ADIS16209_SMPL_PRD       0x36
+
 /* Operation, filter configuration */
 #define ADIS16209_AVG_CNT        0x38
+
 /* Operation, sleep mode control */
 #define ADIS16209_SLP_CNT        0x3A
+
 /* Diagnostics, system status register */
 #define ADIS16209_DIAG_STAT      0x3C
+
 /* Operation, system command register */
 #define ADIS16209_GLOB_CMD       0x3E
 
 /* MSC_CTRL */
+
 /* Self-test at power-on: 1 = disabled, 0 = enabled */
 #define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST	BIT(10)
+
 /* Self-test enable */
 #define ADIS16209_MSC_CTRL_SELF_TEST_EN	        BIT(8)
+
 /* Data-ready enable: 1 = enabled, 0 = disabled */
 #define ADIS16209_MSC_CTRL_DATA_RDY_EN	        BIT(2)
+
 /* Data-ready polarity: 1 = active high, 0 = active low */
 #define ADIS16209_MSC_CTRL_ACTIVE_HIGH	        BIT(1)
+
 /* Data-ready line selection: 1 = DIO2, 0 = DIO1 */
 #define ADIS16209_MSC_CTRL_DATA_RDY_DIO2	BIT(0)
 
 /* DIAG_STAT */
+
 /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
 #define ADIS16209_DIAG_STAT_ALARM2        BIT(9)
+
 /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
 #define ADIS16209_DIAG_STAT_ALARM1        BIT(8)
+
 /* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */
 #define ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT	5
+
 /* SPI communications failure */
 #define ADIS16209_DIAG_STAT_SPI_FAIL_BIT	3
+
 /* Flash update failure */
 #define ADIS16209_DIAG_STAT_FLASH_UPT_BIT	2
+
 /* Power supply above 3.625 V */
 #define ADIS16209_DIAG_STAT_POWER_HIGH_BIT	1
+
 /* Power supply below 3.15 V */
 #define ADIS16209_DIAG_STAT_POWER_LOW_BIT	0
 
 /* GLOB_CMD */
+
 #define ADIS16209_GLOB_CMD_SW_RESET	BIT(7)
 #define ADIS16209_GLOB_CMD_CLEAR_STAT	BIT(4)
 #define ADIS16209_GLOB_CMD_FACTORY_CAL	BIT(1)
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index 8b42bf8..8dbad58 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -168,6 +168,7 @@ static const struct adis_data adis16209_data = {
 	.diag_stat_reg = ADIS16209_DIAG_STAT,
 
 	.self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN,
+	.self_test_no_autoclear = true,
 	.startup_delay = ADIS16209_STARTUP_DELAY,
 
 	.status_error_msgs = adis16209_status_error_msgs,
diff --git a/drivers/staging/iio/accel/adis16240.h b/drivers/staging/iio/accel/adis16240.h
index 66b5ad2..b2cb37b 100644
--- a/drivers/staging/iio/accel/adis16240.h
+++ b/drivers/staging/iio/accel/adis16240.h
@@ -5,110 +5,160 @@
 
 /* Flash memory write count */
 #define ADIS16240_FLASH_CNT      0x00
+
 /* Output, power supply */
 #define ADIS16240_SUPPLY_OUT     0x02
+
 /* Output, x-axis accelerometer */
 #define ADIS16240_XACCL_OUT      0x04
+
 /* Output, y-axis accelerometer */
 #define ADIS16240_YACCL_OUT      0x06
+
 /* Output, z-axis accelerometer */
 #define ADIS16240_ZACCL_OUT      0x08
+
 /* Output, auxiliary ADC input */
 #define ADIS16240_AUX_ADC        0x0A
+
 /* Output, temperature */
 #define ADIS16240_TEMP_OUT       0x0C
+
 /* Output, x-axis acceleration peak */
 #define ADIS16240_XPEAK_OUT      0x0E
+
 /* Output, y-axis acceleration peak */
 #define ADIS16240_YPEAK_OUT      0x10
+
 /* Output, z-axis acceleration peak */
 #define ADIS16240_ZPEAK_OUT      0x12
+
 /* Output, sum-of-squares acceleration peak */
 #define ADIS16240_XYZPEAK_OUT    0x14
+
 /* Output, Capture Buffer 1, X and Y acceleration */
 #define ADIS16240_CAPT_BUF1      0x16
+
 /* Output, Capture Buffer 2, Z acceleration */
 #define ADIS16240_CAPT_BUF2      0x18
+
 /* Diagnostic, error flags */
 #define ADIS16240_DIAG_STAT      0x1A
+
 /* Diagnostic, event counter */
 #define ADIS16240_EVNT_CNTR      0x1C
+
 /* Diagnostic, check sum value from firmware test */
 #define ADIS16240_CHK_SUM        0x1E
+
 /* Calibration, x-axis acceleration offset adjustment */
 #define ADIS16240_XACCL_OFF      0x20
+
 /* Calibration, y-axis acceleration offset adjustment */
 #define ADIS16240_YACCL_OFF      0x22
+
 /* Calibration, z-axis acceleration offset adjustment */
 #define ADIS16240_ZACCL_OFF      0x24
+
 /* Clock, hour and minute */
 #define ADIS16240_CLK_TIME       0x2E
+
 /* Clock, month and day */
 #define ADIS16240_CLK_DATE       0x30
+
 /* Clock, year */
 #define ADIS16240_CLK_YEAR       0x32
+
 /* Wake-up setting, hour and minute */
 #define ADIS16240_WAKE_TIME      0x34
+
 /* Wake-up setting, month and day */
 #define ADIS16240_WAKE_DATE      0x36
+
 /* Alarm 1 amplitude threshold */
 #define ADIS16240_ALM_MAG1       0x38
+
 /* Alarm 2 amplitude threshold */
 #define ADIS16240_ALM_MAG2       0x3A
+
 /* Alarm control */
 #define ADIS16240_ALM_CTRL       0x3C
+
 /* Capture, external trigger control */
 #define ADIS16240_XTRIG_CTRL     0x3E
+
 /* Capture, address pointer */
 #define ADIS16240_CAPT_PNTR      0x40
+
 /* Capture, configuration and control */
 #define ADIS16240_CAPT_CTRL      0x42
+
 /* General-purpose digital input/output control */
 #define ADIS16240_GPIO_CTRL      0x44
+
 /* Miscellaneous control */
 #define ADIS16240_MSC_CTRL       0x46
+
 /* Internal sample period (rate) control */
 #define ADIS16240_SMPL_PRD       0x48
+
 /* System command */
 #define ADIS16240_GLOB_CMD       0x4A
 
 /* MSC_CTRL */
+
 /* Enables sum-of-squares output (XYZPEAK_OUT) */
 #define ADIS16240_MSC_CTRL_XYZPEAK_OUT_EN	BIT(15)
+
 /* Enables peak tracking output (XPEAK_OUT, YPEAK_OUT, and ZPEAK_OUT) */
 #define ADIS16240_MSC_CTRL_X_Y_ZPEAK_OUT_EN	BIT(14)
+
 /* Self-test enable: 1 = apply electrostatic force, 0 = disabled */
 #define ADIS16240_MSC_CTRL_SELF_TEST_EN	        BIT(8)
+
 /* Data-ready enable: 1 = enabled, 0 = disabled */
 #define ADIS16240_MSC_CTRL_DATA_RDY_EN	        BIT(2)
+
 /* Data-ready polarity: 1 = active high, 0 = active low */
 #define ADIS16240_MSC_CTRL_ACTIVE_HIGH	        BIT(1)
+
 /* Data-ready line selection: 1 = DIO2, 0 = DIO1 */
 #define ADIS16240_MSC_CTRL_DATA_RDY_DIO2	BIT(0)
 
 /* DIAG_STAT */
+
 /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
 #define ADIS16240_DIAG_STAT_ALARM2      BIT(9)
+
 /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
 #define ADIS16240_DIAG_STAT_ALARM1      BIT(8)
+
 /* Capture buffer full: 1 = capture buffer is full */
 #define ADIS16240_DIAG_STAT_CPT_BUF_FUL BIT(7)
+
 /* Flash test, checksum flag: 1 = mismatch, 0 = match */
 #define ADIS16240_DIAG_STAT_CHKSUM      BIT(6)
+
 /* Power-on, self-test flag: 1 = failure, 0 = pass */
 #define ADIS16240_DIAG_STAT_PWRON_FAIL_BIT  5
+
 /* Power-on self-test: 1 = in-progress, 0 = complete */
 #define ADIS16240_DIAG_STAT_PWRON_BUSY  BIT(4)
+
 /* SPI communications failure */
 #define ADIS16240_DIAG_STAT_SPI_FAIL_BIT	3
+
 /* Flash update failure */
 #define ADIS16240_DIAG_STAT_FLASH_UPT_BIT	2
+
 /* Power supply above 3.625 V */
 #define ADIS16240_DIAG_STAT_POWER_HIGH_BIT	1
+
  /* Power supply below 3.15 V */
 #define ADIS16240_DIAG_STAT_POWER_LOW_BIT	0
 
 /* GLOB_CMD */
+
 #define ADIS16240_GLOB_CMD_RESUME	BIT(8)
 #define ADIS16240_GLOB_CMD_SW_RESET	BIT(7)
 #define ADIS16240_GLOB_CMD_STANDBY	BIT(2)
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index 1b5b685..d5b99e6 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -29,13 +29,13 @@
 static ssize_t adis16240_spi_read_signed(struct device *dev,
 					 struct device_attribute *attr,
 					 char *buf,
-					 unsigned bits)
+					 unsigned int bits)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct adis *st = iio_priv(indio_dev);
 	int ret;
 	s16 val = 0;
-	unsigned shift = 16 - bits;
+	unsigned int shift = 16 - bits;
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
 	ret = adis_read_reg_16(st,
@@ -222,6 +222,7 @@ static const struct adis_data adis16240_data = {
 	.diag_stat_reg = ADIS16240_DIAG_STAT,
 
 	.self_test_mask = ADIS16240_MSC_CTRL_SELF_TEST_EN,
+	.self_test_no_autoclear = true,
 	.startup_delay = ADIS16240_STARTUP_DELAY,
 
 	.status_error_msgs = adis16240_status_error_msgs,
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index ec12181..b5625f5 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -774,7 +774,7 @@ static irqreturn_t sca3000_event_handler(int irq, void *private)
 	struct iio_dev *indio_dev = private;
 	struct sca3000_state *st = iio_priv(indio_dev);
 	int ret, val;
-	s64 last_timestamp = iio_get_time_ns();
+	s64 last_timestamp = iio_get_time_ns(indio_dev);
 
 	/*
 	 * Could lead if badly timed to an extra read of status reg,
@@ -1046,6 +1046,8 @@ static int sca3000_clean_setup(struct sca3000_state *st)
 
 	/* Disable ring buffer */
 	ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL);
+	if (ret < 0)
+		goto error_ret;
 	ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL,
 				     (ret & SCA3000_OUT_CTRL_PROT_MASK)
 				     | SCA3000_OUT_CTRL_BUF_X_EN
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index f843f19..1cf6b79 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -35,10 +35,10 @@
 #define AD7192_REG_DATA		3 /* Data Register	     (RO, 24/32-bit) */
 #define AD7192_REG_ID		4 /* ID Register	     (RO, 8-bit) */
 #define AD7192_REG_GPOCON	5 /* GPOCON Register	     (RO, 8-bit) */
-#define AD7192_REG_OFFSET	6 /* Offset Register	     (RW, 16-bit
-				   * (AD7792)/24-bit (AD7192)) */
-#define AD7192_REG_FULLSALE	7 /* Full-Scale Register
-				   * (RW, 16-bit (AD7792)/24-bit (AD7192)) */
+#define AD7192_REG_OFFSET	6 /* Offset Register	     (RW, 16-bit */
+				  /* (AD7792)/24-bit (AD7192)) */
+#define AD7192_REG_FULLSALE	7 /* Full-Scale Register */
+				  /* (RW, 16-bit (AD7792)/24-bit (AD7192)) */
 
 /* Communications Register Bit Designations (AD7192_REG_COMM) */
 #define AD7192_COMM_WEN		BIT(7) /* Write Enable */
@@ -80,13 +80,13 @@
 #define AD7192_MODE_CAL_SYS_FULL	7 /* System Full-Scale Calibration */
 
 /* Mode Register: AD7192_MODE_CLKSRC options */
-#define AD7192_CLK_EXT_MCLK1_2		0 /* External 4.92 MHz Clock connected
-					   * from MCLK1 to MCLK2 */
+#define AD7192_CLK_EXT_MCLK1_2		0 /* External 4.92 MHz Clock connected*/
+					  /* from MCLK1 to MCLK2 */
 #define AD7192_CLK_EXT_MCLK2		1 /* External Clock applied to MCLK2 */
-#define AD7192_CLK_INT			2 /* Internal 4.92 MHz Clock not
-					   * available at the MCLK2 pin */
-#define AD7192_CLK_INT_CO		3 /* Internal 4.92 MHz Clock available
-					   * at the MCLK2 pin */
+#define AD7192_CLK_INT			2 /* Internal 4.92 MHz Clock not */
+					  /* available at the MCLK2 pin */
+#define AD7192_CLK_INT_CO		3 /* Internal 4.92 MHz Clock available*/
+					  /* at the MCLK2 pin */
 
 /* Configuration Register Bit Designations (AD7192_REG_CONF) */
 
@@ -349,11 +349,9 @@ static ssize_t ad7192_write_frequency(struct device *dev,
 	if (lval == 0)
 		return -EINVAL;
 
-	mutex_lock(&indio_dev->mlock);
-	if (iio_buffer_enabled(indio_dev)) {
-		mutex_unlock(&indio_dev->mlock);
-		return -EBUSY;
-	}
+	ret = iio_device_claim_direct_mode(indio_dev);
+	if (ret)
+		return ret;
 
 	div = st->mclk / (lval * st->f_order * 1024);
 	if (div < 1 || div > 1023) {
@@ -366,7 +364,7 @@ static ssize_t ad7192_write_frequency(struct device *dev,
 	ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
 
 out:
-	mutex_unlock(&indio_dev->mlock);
+	iio_device_release_direct_mode(indio_dev);
 
 	return ret ? ret : len;
 }
@@ -434,11 +432,9 @@ static ssize_t ad7192_set(struct device *dev,
 	if (ret < 0)
 		return ret;
 
-	mutex_lock(&indio_dev->mlock);
-	if (iio_buffer_enabled(indio_dev)) {
-		mutex_unlock(&indio_dev->mlock);
-		return -EBUSY;
-	}
+	ret = iio_device_claim_direct_mode(indio_dev);
+	if (ret)
+		return ret;
 
 	switch ((u32)this_attr->address) {
 	case AD7192_REG_GPOCON:
@@ -461,7 +457,7 @@ static ssize_t ad7192_set(struct device *dev,
 		ret = -EINVAL;
 	}
 
-	mutex_unlock(&indio_dev->mlock);
+	iio_device_release_direct_mode(indio_dev);
 
 	return ret ? ret : len;
 }
@@ -555,11 +551,9 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
 	int ret, i;
 	unsigned int tmp;
 
-	mutex_lock(&indio_dev->mlock);
-	if (iio_buffer_enabled(indio_dev)) {
-		mutex_unlock(&indio_dev->mlock);
-		return -EBUSY;
-	}
+	ret = iio_device_claim_direct_mode(indio_dev);
+	if (ret)
+		return ret;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_SCALE:
@@ -582,7 +576,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
 		ret = -EINVAL;
 	}
 
-	mutex_unlock(&indio_dev->mlock);
+	iio_device_release_direct_mode(indio_dev);
 
 	return ret;
 }
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
index 62e5eca..2177f1d 100644
--- a/drivers/staging/iio/adc/ad7280a.c
+++ b/drivers/staging/iio/adc/ad7280a.c
@@ -155,7 +155,7 @@ static void ad7280_crc8_build_table(unsigned char *crc_tab)
 	}
 }
 
-static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned val)
+static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val)
 {
 	unsigned char crc;
 
@@ -165,7 +165,7 @@ static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned val)
 	return  crc ^ (val & 0xFF);
 }
 
-static int ad7280_check_crc(struct ad7280_state *st, unsigned val)
+static int ad7280_check_crc(struct ad7280_state *st, unsigned int val)
 {
 	unsigned char crc = ad7280_calc_crc8(st->crc_tab, val >> 10);
 
@@ -191,7 +191,7 @@ static void ad7280_delay(struct ad7280_state *st)
 		usleep_range(250, 500);
 }
 
-static int __ad7280_read32(struct ad7280_state *st, unsigned *val)
+static int __ad7280_read32(struct ad7280_state *st, unsigned int *val)
 {
 	int ret;
 	struct spi_transfer t = {
@@ -211,10 +211,10 @@ static int __ad7280_read32(struct ad7280_state *st, unsigned *val)
 	return 0;
 }
 
-static int ad7280_write(struct ad7280_state *st, unsigned devaddr,
-			unsigned addr, bool all, unsigned val)
+static int ad7280_write(struct ad7280_state *st, unsigned int devaddr,
+			unsigned int addr, bool all, unsigned int val)
 {
-	unsigned reg = devaddr << 27 | addr << 21 |
+	unsigned int reg = devaddr << 27 | addr << 21 |
 			(val & 0xFF) << 13 | all << 12;
 
 	reg |= ad7280_calc_crc8(st->crc_tab, reg >> 11) << 3 | 0x2;
@@ -223,11 +223,11 @@ static int ad7280_write(struct ad7280_state *st, unsigned devaddr,
 	return spi_write(st->spi, &st->buf[0], 4);
 }
 
-static int ad7280_read(struct ad7280_state *st, unsigned devaddr,
-		       unsigned addr)
+static int ad7280_read(struct ad7280_state *st, unsigned int devaddr,
+		       unsigned int addr)
 {
 	int ret;
-	unsigned tmp;
+	unsigned int tmp;
 
 	/* turns off the read operation on all parts */
 	ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
@@ -261,11 +261,11 @@ static int ad7280_read(struct ad7280_state *st, unsigned devaddr,
 	return (tmp >> 13) & 0xFF;
 }
 
-static int ad7280_read_channel(struct ad7280_state *st, unsigned devaddr,
-			       unsigned addr)
+static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr,
+			       unsigned int addr)
 {
 	int ret;
-	unsigned tmp;
+	unsigned int tmp;
 
 	ret = ad7280_write(st, devaddr, AD7280A_READ, 0, addr << 2);
 	if (ret)
@@ -299,11 +299,11 @@ static int ad7280_read_channel(struct ad7280_state *st, unsigned devaddr,
 	return (tmp >> 11) & 0xFFF;
 }
 
-static int ad7280_read_all_channels(struct ad7280_state *st, unsigned cnt,
-				    unsigned *array)
+static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt,
+				    unsigned int *array)
 {
 	int i, ret;
-	unsigned tmp, sum = 0;
+	unsigned int tmp, sum = 0;
 
 	ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ, 1,
 			   AD7280A_CELL_VOLTAGE_1 << 2);
@@ -338,7 +338,7 @@ static int ad7280_read_all_channels(struct ad7280_state *st, unsigned cnt,
 
 static int ad7280_chain_setup(struct ad7280_state *st)
 {
-	unsigned val, n;
+	unsigned int val, n;
 	int ret;
 
 	ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_LB, 1,
@@ -401,7 +401,7 @@ static ssize_t ad7280_store_balance_sw(struct device *dev,
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	bool readin;
 	int ret;
-	unsigned devaddr, ch;
+	unsigned int devaddr, ch;
 
 	ret = strtobool(buf, &readin);
 	if (ret)
@@ -431,7 +431,7 @@ static ssize_t ad7280_show_balance_timer(struct device *dev,
 	struct ad7280_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int ret;
-	unsigned msecs;
+	unsigned int msecs;
 
 	mutex_lock(&indio_dev->mlock);
 	ret = ad7280_read(st, this_attr->address >> 8,
@@ -602,7 +602,7 @@ static ssize_t ad7280_read_channel_config(struct device *dev,
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ad7280_state *st = iio_priv(indio_dev);
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-	unsigned val;
+	unsigned int val;
 
 	switch ((u32)this_attr->address) {
 	case AD7280A_CELL_OVERVOLTAGE:
@@ -683,7 +683,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
 {
 	struct iio_dev *indio_dev = private;
 	struct ad7280_state *st = iio_priv(indio_dev);
-	unsigned *channels;
+	unsigned int *channels;
 	int i, ret;
 
 	channels = kcalloc(st->scan_cnt, sizeof(*channels), GFP_KERNEL);
@@ -705,7 +705,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
 							IIO_EV_DIR_RISING,
 							IIO_EV_TYPE_THRESH,
 							0, 0, 0),
-					       iio_get_time_ns());
+					       iio_get_time_ns(indio_dev));
 			else if (((channels[i] >> 11) & 0xFFF) <=
 				st->cell_threshlow)
 				iio_push_event(indio_dev,
@@ -715,7 +715,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
 							IIO_EV_DIR_FALLING,
 							IIO_EV_TYPE_THRESH,
 							0, 0, 0),
-					       iio_get_time_ns());
+					       iio_get_time_ns(indio_dev));
 		} else {
 			if (((channels[i] >> 11) & 0xFFF) >= st->aux_threshhigh)
 				iio_push_event(indio_dev,
@@ -724,7 +724,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
 							0,
 							IIO_EV_TYPE_THRESH,
 							IIO_EV_DIR_RISING),
-					       iio_get_time_ns());
+					       iio_get_time_ns(indio_dev));
 			else if (((channels[i] >> 11) & 0xFFF) <=
 				st->aux_threshlow)
 				iio_push_event(indio_dev,
@@ -733,7 +733,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
 							0,
 							IIO_EV_TYPE_THRESH,
 							IIO_EV_DIR_FALLING),
-					       iio_get_time_ns());
+					       iio_get_time_ns(indio_dev));
 		}
 	}
 
diff --git a/drivers/staging/iio/adc/ad7280a.h b/drivers/staging/iio/adc/ad7280a.h
index 732347a..ccfb90d 100644
--- a/drivers/staging/iio/adc/ad7280a.h
+++ b/drivers/staging/iio/adc/ad7280a.h
@@ -29,10 +29,10 @@
 #define AD7280A_ALERT_REMOVE_AUX4_AUX5		BIT(1)
 
 struct ad7280_platform_data {
-	unsigned acquisition_time;
-	unsigned conversion_averaging;
-	unsigned chain_last_alert_ignore;
-	bool thermistor_term_en;
+	unsigned int		acquisition_time;
+	unsigned int		conversion_averaging;
+	unsigned int		chain_last_alert_ignore;
+	bool			thermistor_term_en;
 };
 
 #endif /* IIO_ADC_AD7280_H_ */
diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h
index cca9469..39f5044 100644
--- a/drivers/staging/iio/adc/ad7606.h
+++ b/drivers/staging/iio/adc/ad7606.h
@@ -28,16 +28,16 @@
  */
 
 struct ad7606_platform_data {
-	unsigned			default_os;
-	unsigned			default_range;
-	unsigned			gpio_convst;
-	unsigned			gpio_reset;
-	unsigned			gpio_range;
-	unsigned			gpio_os0;
-	unsigned			gpio_os1;
-	unsigned			gpio_os2;
-	unsigned			gpio_frstdata;
-	unsigned			gpio_stby;
+	unsigned int			default_os;
+	unsigned int			default_range;
+	unsigned int			gpio_convst;
+	unsigned int			gpio_reset;
+	unsigned int			gpio_range;
+	unsigned int			gpio_os0;
+	unsigned int			gpio_os1;
+	unsigned int			gpio_os2;
+	unsigned int			gpio_frstdata;
+	unsigned int			gpio_stby;
 };
 
 /**
@@ -52,7 +52,7 @@ struct ad7606_chip_info {
 	const char			*name;
 	u16				int_vref_mv;
 	const struct iio_chan_spec	*channels;
-	unsigned			num_channels;
+	unsigned int			num_channels;
 };
 
 /**
@@ -67,8 +67,8 @@ struct ad7606_state {
 	struct work_struct		poll_work;
 	wait_queue_head_t		wq_data_avail;
 	const struct ad7606_bus_ops	*bops;
-	unsigned			range;
-	unsigned			oversampling;
+	unsigned int			range;
+	unsigned int			oversampling;
 	bool				done;
 	void __iomem			*base_address;
 
@@ -86,7 +86,7 @@ struct ad7606_bus_ops {
 };
 
 struct iio_dev *ad7606_probe(struct device *dev, int irq,
-			      void __iomem *base_address, unsigned id,
+			      void __iomem *base_address, unsigned int id,
 			      const struct ad7606_bus_ops *bops);
 int ad7606_remove(struct iio_dev *indio_dev, int irq);
 int ad7606_reset(struct ad7606_state *st);
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
index fe6caee..f79ee61 100644
--- a/drivers/staging/iio/adc/ad7606_core.c
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -36,7 +36,7 @@ int ad7606_reset(struct ad7606_state *st)
 	return -ENODEV;
 }
 
-static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned ch)
+static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
 {
 	struct ad7606_state *st = iio_priv(indio_dev);
 	int ret;
@@ -88,12 +88,12 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		mutex_lock(&indio_dev->mlock);
-		if (iio_buffer_enabled(indio_dev))
-			ret = -EBUSY;
-		else
-			ret = ad7606_scan_direct(indio_dev, chan->address);
-		mutex_unlock(&indio_dev->mlock);
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret)
+			return ret;
+
+		ret = ad7606_scan_direct(indio_dev, chan->address);
+		iio_device_release_direct_mode(indio_dev);
 
 		if (ret < 0)
 			return ret;
@@ -155,7 +155,7 @@ static ssize_t ad7606_show_oversampling_ratio(struct device *dev,
 	return sprintf(buf, "%u\n", st->oversampling);
 }
 
-static int ad7606_oversampling_get_index(unsigned val)
+static int ad7606_oversampling_get_index(unsigned int val)
 {
 	unsigned char supported[] = {0, 2, 4, 8, 16, 32, 64};
 	int i;
@@ -446,7 +446,7 @@ static const struct iio_info ad7606_info_range = {
 
 struct iio_dev *ad7606_probe(struct device *dev, int irq,
 			     void __iomem *base_address,
-			     unsigned id,
+			     unsigned int id,
 			     const struct ad7606_bus_ops *bops)
 {
 	struct ad7606_platform_data *pdata = dev->platform_data;
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index a6f8eb1..0572df9 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -77,7 +77,8 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
 			goto done;
 	}
 
-	iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
+	iio_push_to_buffers_with_timestamp(indio_dev, buf,
+					   iio_get_time_ns(indio_dev));
 done:
 	gpio_set_value(st->pdata->gpio_convst, 0);
 	iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c
index d873a51..9587fa8 100644
--- a/drivers/staging/iio/adc/ad7606_spi.c
+++ b/drivers/staging/iio/adc/ad7606_spi.c
@@ -22,6 +22,7 @@ static int ad7606_spi_read_block(struct device *dev,
 	struct spi_device *spi = to_spi_device(dev);
 	int i, ret;
 	unsigned short *data = buf;
+	__be16 *bdata = buf;
 
 	ret = spi_read(spi, buf, count * 2);
 	if (ret < 0) {
@@ -30,7 +31,7 @@ static int ad7606_spi_read_block(struct device *dev,
 	}
 
 	for (i = 0; i < count; i++)
-		data[i] = be16_to_cpu(data[i]);
+		data[i] = be16_to_cpu(bdata[i]);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c
index 1439cfd..c9a0c2a 100644
--- a/drivers/staging/iio/adc/ad7780.c
+++ b/drivers/staging/iio/adc/ad7780.c
@@ -63,7 +63,7 @@ static int ad7780_set_mode(struct ad_sigma_delta *sigma_delta,
 			   enum ad_sigma_delta_mode mode)
 {
 	struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta);
-	unsigned val;
+	unsigned int val;
 
 	switch (mode) {
 	case AD_SD_MODE_SINGLE:
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
index ac3735c..5e8115b 100644
--- a/drivers/staging/iio/adc/ad7816.c
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -253,7 +253,8 @@ static const struct attribute_group ad7816_attribute_group = {
 
 static irqreturn_t ad7816_event_handler(int irq, void *private)
 {
-	iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI, iio_get_time_ns());
+	iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI,
+		       iio_get_time_ns((struct iio_dev *)private));
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index a10e7d8..3faffe5 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -1752,7 +1752,7 @@ static irqreturn_t adt7316_event_handler(int irq, void *private)
 		if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
 			stat1 &= 0x1F;
 
-		time = iio_get_time_ns();
+		time = iio_get_time_ns(indio_dev);
 		if (stat1 & BIT(0))
 			iio_push_event(indio_dev,
 				       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
@@ -1804,7 +1804,7 @@ static irqreturn_t adt7316_event_handler(int irq, void *private)
 							    0,
 							    IIO_EV_TYPE_THRESH,
 							    IIO_EV_DIR_RISING),
-				       iio_get_time_ns());
+				       iio_get_time_ns(indio_dev));
 	}
 
 	return IRQ_HANDLED;
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index f6b9a10..5578a07 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -493,7 +493,7 @@ static irqreturn_t ad7150_event_handler(int irq, void *private)
 	struct iio_dev *indio_dev = private;
 	struct ad7150_chip_info *chip = iio_priv(indio_dev);
 	u8 int_status;
-	s64 timestamp = iio_get_time_ns();
+	s64 timestamp = iio_get_time_ns(indio_dev);
 	int ret;
 
 	ret = i2c_smbus_read_byte_data(chip->client, AD7150_STATUS);
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index 18b27a1..358400b 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -31,7 +31,7 @@ static unsigned long ad9832_calc_freqreg(unsigned long mclk, unsigned long fout)
 }
 
 static int ad9832_write_frequency(struct ad9832_state *st,
-				  unsigned addr, unsigned long fout)
+				  unsigned int addr, unsigned long fout)
 {
 	unsigned long regval;
 
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index d1218d8..170ac98 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -12,20 +12,16 @@
 #include <linux/sysfs.h>
 #include <linux/i2c.h>
 #include <linux/regulator/consumer.h>
-#include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/module.h>
-#include <asm/div64.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/buffer.h>
 #include <linux/iio/kfifo_buf.h>
 
-#include "ad5933.h"
-
 /* AD5933/AD5934 Registers */
 #define AD5933_REG_CONTROL_HB		0x80	/* R/W, 2 bytes */
 #define AD5933_REG_CONTROL_LB		0x81	/* R/W, 2 bytes */
@@ -86,6 +82,18 @@
 #define AD5933_POLL_TIME_ms		10
 #define AD5933_INIT_EXCITATION_TIME_ms	100
 
+/**
+ * struct ad5933_platform_data - platform specific data
+ * @ext_clk_Hz:		the external clock frequency in Hz, if not set
+ *			the driver uses the internal clock (16.776 MHz)
+ * @vref_mv:		the external reference voltage in millivolt
+ */
+
+struct ad5933_platform_data {
+	unsigned long			ext_clk_Hz;
+	unsigned short			vref_mv;
+};
+
 struct ad5933_state {
 	struct i2c_client		*client;
 	struct regulator		*reg;
@@ -93,14 +101,14 @@ struct ad5933_state {
 	unsigned long			mclk_hz;
 	unsigned char			ctrl_hb;
 	unsigned char			ctrl_lb;
-	unsigned			range_avail[4];
+	unsigned int			range_avail[4];
 	unsigned short			vref_mv;
 	unsigned short			settling_cycles;
 	unsigned short			freq_points;
-	unsigned			freq_start;
-	unsigned			freq_inc;
-	unsigned			state;
-	unsigned			poll_time_jiffies;
+	unsigned int			freq_start;
+	unsigned int			freq_inc;
+	unsigned int			state;
+	unsigned int			poll_time_jiffies;
 };
 
 static struct ad5933_platform_data ad5933_default_pdata  = {
@@ -214,7 +222,7 @@ static int ad5933_wait_busy(struct ad5933_state *st, unsigned char event)
 }
 
 static int ad5933_set_freq(struct ad5933_state *st,
-			   unsigned reg, unsigned long freq)
+			   unsigned int reg, unsigned long freq)
 {
 	unsigned long long freqreg;
 	union {
@@ -274,7 +282,7 @@ static int ad5933_setup(struct ad5933_state *st)
 static void ad5933_calc_out_ranges(struct ad5933_state *st)
 {
 	int i;
-	unsigned normalized_3v3[4] = {1980, 198, 383, 970};
+	unsigned int normalized_3v3[4] = {1980, 198, 383, 970};
 
 	for (i = 0; i < 4; i++)
 		st->range_avail[i] = normalized_3v3[i] * st->vref_mv / 3300;
@@ -307,10 +315,10 @@ static ssize_t ad5933_show_frequency(struct device *dev,
 
 	freqreg = be32_to_cpu(dat.d32) & 0xFFFFFF;
 
-	freqreg = (u64) freqreg * (u64) (st->mclk_hz / 4);
+	freqreg = (u64)freqreg * (u64)(st->mclk_hz / 4);
 	do_div(freqreg, 1 << 27);
 
-	return sprintf(buf, "%d\n", (int) freqreg);
+	return sprintf(buf, "%d\n", (int)freqreg);
 }
 
 static ssize_t ad5933_store_frequency(struct device *dev,
@@ -358,7 +366,7 @@ static ssize_t ad5933_show(struct device *dev,
 	int ret = 0, len = 0;
 
 	mutex_lock(&indio_dev->mlock);
-	switch ((u32) this_attr->address) {
+	switch ((u32)this_attr->address) {
 	case AD5933_OUT_RANGE:
 		len = sprintf(buf, "%u\n",
 			      st->range_avail[(st->ctrl_hb >> 1) & 0x3]);
@@ -409,7 +417,7 @@ static ssize_t ad5933_store(struct device *dev,
 	}
 
 	mutex_lock(&indio_dev->mlock);
-	switch ((u32) this_attr->address) {
+	switch ((u32)this_attr->address) {
 	case AD5933_OUT_RANGE:
 		for (i = 0; i < 4; i++)
 			if (val == st->range_avail[i]) {
@@ -436,10 +444,10 @@ static ssize_t ad5933_store(struct device *dev,
 		st->settling_cycles = val;
 
 		/* 2x, 4x handling, see datasheet */
-		if (val > 511)
-			val = (val >> 1) | (1 << 9);
-		else if (val > 1022)
+		if (val > 1022)
 			val = (val >> 2) | (3 << 9);
+		else if (val > 511)
+			val = (val >> 1) | (1 << 9);
 
 		dat = cpu_to_be16(val);
 		ret = ad5933_i2c_write(st->client,
@@ -683,8 +691,9 @@ static void ad5933_work(struct work_struct *work)
 	}
 
 	if (status & AD5933_STAT_SWEEP_DONE) {
-		/* last sample received - power down do nothing until
-		 * the ring enable is toggled */
+		/* last sample received - power down do
+		 * nothing until the ring enable is toggled
+		 */
 		ad5933_cmd(st, AD5933_CTRL_POWER_DOWN);
 	} else {
 		/* we just received a valid datum, move on to the next */
@@ -699,7 +708,7 @@ static int ad5933_probe(struct i2c_client *client,
 				   const struct i2c_device_id *id)
 {
 	int ret, voltage_uv = 0;
-	struct ad5933_platform_data *pdata = client->dev.platform_data;
+	struct ad5933_platform_data *pdata = dev_get_platdata(&client->dev);
 	struct ad5933_state *st;
 	struct iio_dev *indio_dev;
 
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
index 6e2ba45..2e3b1d6 100644
--- a/drivers/staging/iio/light/isl29028.c
+++ b/drivers/staging/iio/light/isl29028.c
@@ -69,7 +69,6 @@ enum als_ir_mode {
 };
 
 struct isl29028_chip {
-	struct device		*dev;
 	struct mutex		lock;
 	struct regmap		*regmap;
 
@@ -166,20 +165,21 @@ static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
 
 static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
 {
+	struct device *dev = regmap_get_device(chip->regmap);
 	unsigned int lsb;
 	unsigned int msb;
 	int ret;
 
 	ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);
 	if (ret < 0) {
-		dev_err(chip->dev,
+		dev_err(dev,
 			"Error in reading register ALSIR_L err %d\n", ret);
 		return ret;
 	}
 
 	ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);
 	if (ret < 0) {
-		dev_err(chip->dev,
+		dev_err(dev,
 			"Error in reading register ALSIR_U err %d\n", ret);
 		return ret;
 	}
@@ -190,12 +190,13 @@ static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
 
 static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox)
 {
+	struct device *dev = regmap_get_device(chip->regmap);
 	unsigned int data;
 	int ret;
 
 	ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);
 	if (ret < 0) {
-		dev_err(chip->dev, "Error in reading register %d, error %d\n",
+		dev_err(dev, "Error in reading register %d, error %d\n",
 			ISL29028_REG_PROX_DATA, ret);
 		return ret;
 	}
@@ -218,13 +219,14 @@ static int isl29028_proxim_get(struct isl29028_chip *chip, int *prox_data)
 
 static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
 {
+	struct device *dev = regmap_get_device(chip->regmap);
 	int ret;
 	int als_ir_data;
 
 	if (chip->als_ir_mode != MODE_ALS) {
 		ret = isl29028_set_als_ir_mode(chip, MODE_ALS);
 		if (ret < 0) {
-			dev_err(chip->dev,
+			dev_err(dev,
 				"Error in enabling ALS mode err %d\n", ret);
 			return ret;
 		}
@@ -251,12 +253,13 @@ static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
 
 static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
 {
+	struct device *dev = regmap_get_device(chip->regmap);
 	int ret;
 
 	if (chip->als_ir_mode != MODE_IR) {
 		ret = isl29028_set_als_ir_mode(chip, MODE_IR);
 		if (ret < 0) {
-			dev_err(chip->dev,
+			dev_err(dev,
 				"Error in enabling IR mode err %d\n", ret);
 			return ret;
 		}
@@ -271,25 +274,26 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
 			      int val, int val2, long mask)
 {
 	struct isl29028_chip *chip = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(chip->regmap);
 	int ret = -EINVAL;
 
 	mutex_lock(&chip->lock);
 	switch (chan->type) {
 	case IIO_PROXIMITY:
 		if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
-			dev_err(chip->dev,
+			dev_err(dev,
 				"proximity: mask value 0x%08lx not supported\n",
 				mask);
 			break;
 		}
 		if (val < 1 || val > 100) {
-			dev_err(chip->dev,
+			dev_err(dev,
 				"Samp_freq %d is not in range[1:100]\n", val);
 			break;
 		}
 		ret = isl29028_set_proxim_sampling(chip, val);
 		if (ret < 0) {
-			dev_err(chip->dev,
+			dev_err(dev,
 				"Setting proximity samp_freq fail, err %d\n",
 				ret);
 			break;
@@ -299,19 +303,19 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
 
 	case IIO_LIGHT:
 		if (mask != IIO_CHAN_INFO_SCALE) {
-			dev_err(chip->dev,
+			dev_err(dev,
 				"light: mask value 0x%08lx not supported\n",
 				mask);
 			break;
 		}
 		if ((val != 125) && (val != 2000)) {
-			dev_err(chip->dev,
+			dev_err(dev,
 				"lux scale %d is invalid [125, 2000]\n", val);
 			break;
 		}
 		ret = isl29028_set_als_scale(chip, val);
 		if (ret < 0) {
-			dev_err(chip->dev,
+			dev_err(dev,
 				"Setting lux scale fail with error %d\n", ret);
 			break;
 		}
@@ -319,7 +323,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
 		break;
 
 	default:
-		dev_err(chip->dev, "Unsupported channel type\n");
+		dev_err(dev, "Unsupported channel type\n");
 		break;
 	}
 	mutex_unlock(&chip->lock);
@@ -331,6 +335,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
 			     int *val, int *val2, long mask)
 {
 	struct isl29028_chip *chip = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(chip->regmap);
 	int ret = -EINVAL;
 
 	mutex_lock(&chip->lock);
@@ -370,7 +375,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
 		break;
 
 	default:
-		dev_err(chip->dev, "mask value 0x%08lx not supported\n", mask);
+		dev_err(dev, "mask value 0x%08lx not supported\n", mask);
 		break;
 	}
 	mutex_unlock(&chip->lock);
@@ -417,6 +422,7 @@ static const struct iio_info isl29028_info = {
 
 static int isl29028_chip_init(struct isl29028_chip *chip)
 {
+	struct device *dev = regmap_get_device(chip->regmap);
 	int ret;
 
 	chip->enable_prox  = false;
@@ -426,35 +432,33 @@ static int isl29028_chip_init(struct isl29028_chip *chip)
 
 	ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+		dev_err(dev, "%s(): write to reg %d failed, err = %d\n",
 			__func__, ISL29028_REG_TEST1_MODE, ret);
 		return ret;
 	}
 	ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+		dev_err(dev, "%s(): write to reg %d failed, err = %d\n",
 			__func__, ISL29028_REG_TEST2_MODE, ret);
 		return ret;
 	}
 
 	ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+		dev_err(dev, "%s(): write to reg %d failed, err = %d\n",
 			__func__, ISL29028_REG_CONFIGURE, ret);
 		return ret;
 	}
 
 	ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling);
 	if (ret < 0) {
-		dev_err(chip->dev, "setting the proximity, err = %d\n",
-			ret);
+		dev_err(dev, "setting the proximity, err = %d\n", ret);
 		return ret;
 	}
 
 	ret = isl29028_set_als_scale(chip, chip->lux_scale);
 	if (ret < 0)
-		dev_err(chip->dev,
-			"setting als scale failed, err = %d\n", ret);
+		dev_err(dev, "setting als scale failed, err = %d\n", ret);
 	return ret;
 }
 
@@ -496,19 +500,19 @@ static int isl29028_probe(struct i2c_client *client,
 	chip = iio_priv(indio_dev);
 
 	i2c_set_clientdata(client, indio_dev);
-	chip->dev = &client->dev;
 	mutex_init(&chip->lock);
 
 	chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);
 	if (IS_ERR(chip->regmap)) {
 		ret = PTR_ERR(chip->regmap);
-		dev_err(chip->dev, "regmap initialization failed: %d\n", ret);
+		dev_err(&client->dev, "regmap initialization failed: %d\n",
+			ret);
 		return ret;
 	}
 
 	ret = isl29028_chip_init(chip);
 	if (ret < 0) {
-		dev_err(chip->dev, "chip initialization failed: %d\n", ret);
+		dev_err(&client->dev, "chip initialization failed: %d\n", ret);
 		return ret;
 	}
 
@@ -520,7 +524,8 @@ static int isl29028_probe(struct i2c_client *client,
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
 	if (ret < 0) {
-		dev_err(chip->dev, "iio registration fails with error %d\n",
+		dev_err(&client->dev,
+			"iio registration fails with error %d\n",
 			ret);
 		return ret;
 	}
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
index 5f308ba..ea15bc1 100644
--- a/drivers/staging/iio/light/tsl2x7x_core.c
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -187,9 +187,11 @@ struct tsl2X7X_chip {
 	const struct tsl2x7x_chip_info	*chip_info;
 	const struct iio_info *info;
 	s64 event_timestamp;
-	/* This structure is intentionally large to accommodate
-	 * updates via sysfs. */
-	/* Sized to 9 = max 8 segments + 1 termination segment */
+	/*
+	 * This structure is intentionally large to accommodate
+	 * updates via sysfs.
+	 * Sized to 9 = max 8 segments + 1 termination segment
+	 */
 	struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
 };
 
@@ -349,13 +351,13 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
 	if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) {
 		/* device is not enabled */
 		dev_err(&chip->client->dev, "%s: device is not enabled\n",
-				__func__);
+			__func__);
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 
 	ret = tsl2x7x_i2c_read(chip->client,
-		(TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]);
+			       (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]);
 	if (ret < 0) {
 		dev_err(&chip->client->dev,
 			"%s: Failed to read STATUS Reg\n", __func__);
@@ -371,8 +373,8 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
 
 	for (i = 0; i < 4; i++) {
 		ret = tsl2x7x_i2c_read(chip->client,
-			(TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i)),
-			&buf[i]);
+				       (TSL2X7X_CMD_REG |
+				       (TSL2X7X_ALS_CHAN0LO + i)), &buf[i]);
 		if (ret < 0) {
 			dev_err(&chip->client->dev,
 				"failed to read. err=%x\n", ret);
@@ -382,9 +384,9 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
 
 	/* clear any existing interrupt status */
 	ret = i2c_smbus_write_byte(chip->client,
-		(TSL2X7X_CMD_REG |
-				TSL2X7X_CMD_SPL_FN |
-				TSL2X7X_CMD_ALS_INT_CLR));
+				   (TSL2X7X_CMD_REG |
+				   TSL2X7X_CMD_SPL_FN |
+				   TSL2X7X_CMD_ALS_INT_CLR));
 	if (ret < 0) {
 		dev_err(&chip->client->dev,
 			"i2c_write_command failed - err = %d\n", ret);
@@ -411,7 +413,7 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
 	/* calculate ratio */
 	ratio = (ch1 << 15) / ch0;
 	/* convert to unscaled lux using the pointer to the table */
-	p = (struct tsl2x7x_lux *) chip->tsl2x7x_device_lux;
+	p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux;
 	while (p->ratio != 0 && p->ratio < ratio)
 		p++;
 
@@ -488,7 +490,7 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
 	}
 
 	ret = tsl2x7x_i2c_read(chip->client,
-		(TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status);
+			       (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status);
 	if (ret < 0) {
 		dev_err(&chip->client->dev, "i2c err=%d\n", ret);
 		goto prox_poll_err;
@@ -515,8 +517,8 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
 
 	for (i = 0; i < 2; i++) {
 		ret = tsl2x7x_i2c_read(chip->client,
-			(TSL2X7X_CMD_REG |
-					(TSL2X7X_PRX_LO + i)), &chdata[i]);
+				       (TSL2X7X_CMD_REG |
+				       (TSL2X7X_PRX_LO + i)), &chdata[i]);
 		if (ret < 0)
 			goto prox_poll_err;
 	}
@@ -542,19 +544,19 @@ static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
 {
 	/* If Operational settings defined elsewhere.. */
 	if (chip->pdata && chip->pdata->platform_default_settings)
-		memcpy(&(chip->tsl2x7x_settings),
-			chip->pdata->platform_default_settings,
-			sizeof(tsl2x7x_default_settings));
+		memcpy(&chip->tsl2x7x_settings,
+		       chip->pdata->platform_default_settings,
+		       sizeof(tsl2x7x_default_settings));
 	else
-		memcpy(&(chip->tsl2x7x_settings),
-			&tsl2x7x_default_settings,
-			sizeof(tsl2x7x_default_settings));
+		memcpy(&chip->tsl2x7x_settings,
+		       &tsl2x7x_default_settings,
+		       sizeof(tsl2x7x_default_settings));
 
 	/* Load up the proper lux table. */
 	if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
 		memcpy(chip->tsl2x7x_device_lux,
-			chip->pdata->platform_lux_table,
-			sizeof(chip->pdata->platform_lux_table));
+		       chip->pdata->platform_lux_table,
+		       sizeof(chip->pdata->platform_lux_table));
 	else
 		memcpy(chip->tsl2x7x_device_lux,
 		(struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id],
@@ -576,7 +578,7 @@ static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
 	int lux_val;
 
 	ret = i2c_smbus_write_byte(chip->client,
-			(TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+				   (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
 	if (ret < 0) {
 		dev_err(&chip->client->dev,
 			"failed to write CNTRL register, ret=%d\n", ret);
@@ -592,7 +594,7 @@ static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
 	}
 
 	ret = i2c_smbus_write_byte(chip->client,
-			(TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+				   (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
 	if (ret < 0) {
 		dev_err(&chip->client->dev,
 			"failed to write ctrl reg: ret=%d\n", ret);
@@ -609,7 +611,7 @@ static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
 	lux_val = tsl2x7x_get_lux(indio_dev);
 	if (lux_val < 0) {
 		dev_err(&chip->client->dev,
-		"%s: failed to get lux\n", __func__);
+			"%s: failed to get lux\n", __func__);
 		return lux_val;
 	}
 
@@ -620,9 +622,9 @@ static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
 
 	chip->tsl2x7x_settings.als_gain_trim = gain_trim_val;
 	dev_info(&chip->client->dev,
-		"%s als_calibrate completed\n", chip->client->name);
+		 "%s als_calibrate completed\n", chip->client->name);
 
-	return (int) gain_trim_val;
+	return (int)gain_trim_val;
 }
 
 static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
@@ -695,23 +697,28 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
 	chip->als_saturation = als_count * 922; /* 90% of full scale */
 	chip->als_time_scale = (als_time + 25) / 50;
 
-	/* TSL2X7X Specific power-on / adc enable sequence
-	 * Power on the device 1st. */
+	/*
+	 * TSL2X7X Specific power-on / adc enable sequence
+	 * Power on the device 1st.
+	 */
 	utmp = TSL2X7X_CNTL_PWR_ON;
 	ret = i2c_smbus_write_byte_data(chip->client,
-		TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+					TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
 	if (ret < 0) {
 		dev_err(&chip->client->dev,
 			"%s: failed on CNTRL reg.\n", __func__);
 		return ret;
 	}
 
-	/* Use the following shadow copy for our delay before enabling ADC.
-	 * Write all the registers. */
+	/*
+	 * Use the following shadow copy for our delay before enabling ADC.
+	 * Write all the registers.
+	 */
 	for (i = 0, dev_reg = chip->tsl2x7x_config;
 			i < TSL2X7X_MAX_CONFIG_REG; i++) {
 		ret = i2c_smbus_write_byte_data(chip->client,
-				TSL2X7X_CMD_REG + i, *dev_reg++);
+						TSL2X7X_CMD_REG + i,
+						*dev_reg++);
 		if (ret < 0) {
 			dev_err(&chip->client->dev,
 				"failed on write to reg %d.\n", i);
@@ -721,13 +728,15 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
 
 	mdelay(3);	/* Power-on settling time */
 
-	/* NOW enable the ADC
-	 * initialize the desired mode of operation */
+	/*
+	 * NOW enable the ADC
+	 * initialize the desired mode of operation
+	 */
 	utmp = TSL2X7X_CNTL_PWR_ON |
 			TSL2X7X_CNTL_ADC_ENBL |
 			TSL2X7X_CNTL_PROX_DET_ENBL;
 	ret = i2c_smbus_write_byte_data(chip->client,
-			TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+					TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
 	if (ret < 0) {
 		dev_err(&chip->client->dev,
 			"%s: failed on 2nd CTRL reg.\n", __func__);
@@ -741,12 +750,13 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
 
 		reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL;
 		if ((chip->tsl2x7x_settings.interrupts_en == 0x20) ||
-			(chip->tsl2x7x_settings.interrupts_en == 0x30))
+		    (chip->tsl2x7x_settings.interrupts_en == 0x30))
 			reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
 
 		reg_val |= chip->tsl2x7x_settings.interrupts_en;
 		ret = i2c_smbus_write_byte_data(chip->client,
-			(TSL2X7X_CMD_REG | TSL2X7X_CNTRL), reg_val);
+						(TSL2X7X_CMD_REG |
+						TSL2X7X_CNTRL), reg_val);
 		if (ret < 0)
 			dev_err(&chip->client->dev,
 				"%s: failed in tsl2x7x_IOCTL_INT_SET.\n",
@@ -754,8 +764,9 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
 
 		/* Clear out any initial interrupts  */
 		ret = i2c_smbus_write_byte(chip->client,
-			TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
-			TSL2X7X_CMD_PROXALS_INT_CLR);
+					   TSL2X7X_CMD_REG |
+					   TSL2X7X_CMD_SPL_FN |
+					   TSL2X7X_CMD_PROXALS_INT_CLR);
 		if (ret < 0) {
 			dev_err(&chip->client->dev,
 				"%s: Failed to clear Int status\n",
@@ -776,7 +787,7 @@ static int tsl2x7x_chip_off(struct iio_dev *indio_dev)
 	chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
 
 	ret = i2c_smbus_write_byte_data(chip->client,
-		TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00);
+					TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00);
 
 	if (chip->pdata && chip->pdata->power_off)
 		chip->pdata->power_off(chip->client);
@@ -819,7 +830,7 @@ int tsl2x7x_invoke_change(struct iio_dev *indio_dev)
 
 static
 void tsl2x7x_prox_calculate(int *data, int length,
-		struct tsl2x7x_prox_stat *statP)
+			    struct tsl2x7x_prox_stat *statP)
 {
 	int i;
 	int sample_sum;
@@ -843,7 +854,7 @@ void tsl2x7x_prox_calculate(int *data, int length,
 		tmp = data[i] - statP->mean;
 		sample_sum += tmp * tmp;
 	}
-	statP->stddev = int_sqrt((long)sample_sum)/length;
+	statP->stddev = int_sqrt((long)sample_sum) / length;
 }
 
 /**
@@ -886,20 +897,21 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
 		tsl2x7x_get_prox(indio_dev);
 		prox_history[i] = chip->prox_data;
 		dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
-			i, chip->prox_data);
+			 i, chip->prox_data);
 	}
 
 	tsl2x7x_chip_off(indio_dev);
 	calP = &prox_stat_data[PROX_STAT_CAL];
 	tsl2x7x_prox_calculate(prox_history,
-		chip->tsl2x7x_settings.prox_max_samples_cal, calP);
+			       chip->tsl2x7x_settings.prox_max_samples_cal,
+			       calP);
 	chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean;
 
 	dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
-		calP->min, calP->mean, calP->max);
+		 calP->min, calP->mean, calP->max);
 	dev_info(&chip->client->dev,
-		"%s proximity threshold set to %d\n",
-		chip->client->name, chip->tsl2x7x_settings.prox_thres_high);
+		 "%s proximity threshold set to %d\n",
+		 chip->client->name, chip->tsl2x7x_settings.prox_thres_high);
 
 	/* back to the way they were */
 	chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings;
@@ -908,7 +920,8 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
 }
 
 static ssize_t tsl2x7x_power_state_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+					struct device_attribute *attr,
+					char *buf)
 {
 	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
 
@@ -916,7 +929,8 @@ static ssize_t tsl2x7x_power_state_show(struct device *dev,
 }
 
 static ssize_t tsl2x7x_power_state_store(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+					 struct device_attribute *attr,
+					 const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	bool value;
@@ -933,7 +947,8 @@ static ssize_t tsl2x7x_power_state_store(struct device *dev,
 }
 
 static ssize_t tsl2x7x_gain_available_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+					   struct device_attribute *attr,
+					   char *buf)
 {
 	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
 
@@ -950,13 +965,15 @@ static ssize_t tsl2x7x_gain_available_show(struct device *dev,
 }
 
 static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+						struct device_attribute *attr,
+						char *buf)
 {
 		return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8");
 }
 
 static ssize_t tsl2x7x_als_time_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+				     struct device_attribute *attr,
+				     char *buf)
 {
 	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
 	int y, z;
@@ -970,7 +987,8 @@ static ssize_t tsl2x7x_als_time_show(struct device *dev,
 }
 
 static ssize_t tsl2x7x_als_time_store(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+				      struct device_attribute *attr,
+				      const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
@@ -986,7 +1004,7 @@ static ssize_t tsl2x7x_als_time_store(struct device *dev,
 			TSL2X7X_MAX_TIMER_CNT - (u8)result.fract;
 
 	dev_info(&chip->client->dev, "%s: als time = %d",
-		__func__, chip->tsl2x7x_settings.als_time);
+		 __func__, chip->tsl2x7x_settings.als_time);
 
 	tsl2x7x_invoke_change(indio_dev);
 
@@ -997,7 +1015,8 @@ static IIO_CONST_ATTR(in_illuminance0_integration_time_available,
 		".00272 - .696");
 
 static ssize_t tsl2x7x_als_cal_target_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+					   struct device_attribute *attr,
+					   char *buf)
 {
 	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
 
@@ -1006,7 +1025,8 @@ static ssize_t tsl2x7x_als_cal_target_show(struct device *dev,
 }
 
 static ssize_t tsl2x7x_als_cal_target_store(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+					    struct device_attribute *attr,
+					    const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
@@ -1025,7 +1045,8 @@ static ssize_t tsl2x7x_als_cal_target_store(struct device *dev,
 
 /* persistence settings */
 static ssize_t tsl2x7x_als_persistence_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+					    struct device_attribute *attr,
+					    char *buf)
 {
 	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
 	int y, z, filter_delay;
@@ -1041,7 +1062,8 @@ static ssize_t tsl2x7x_als_persistence_show(struct device *dev,
 }
 
 static ssize_t tsl2x7x_als_persistence_store(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+					     struct device_attribute *attr,
+					     const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
@@ -1063,7 +1085,7 @@ static ssize_t tsl2x7x_als_persistence_store(struct device *dev,
 	chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F);
 
 	dev_info(&chip->client->dev, "%s: als persistence = %d",
-		__func__, filter_delay);
+		 __func__, filter_delay);
 
 	tsl2x7x_invoke_change(indio_dev);
 
@@ -1071,7 +1093,8 @@ static ssize_t tsl2x7x_als_persistence_store(struct device *dev,
 }
 
 static ssize_t tsl2x7x_prox_persistence_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+					     struct device_attribute *attr,
+					     char *buf)
 {
 	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
 	int y, z, filter_delay;
@@ -1087,7 +1110,8 @@ static ssize_t tsl2x7x_prox_persistence_show(struct device *dev,
 }
 
 static ssize_t tsl2x7x_prox_persistence_store(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+					      struct device_attribute *attr,
+					      const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
@@ -1109,7 +1133,7 @@ static ssize_t tsl2x7x_prox_persistence_store(struct device *dev,
 	chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0);
 
 	dev_info(&chip->client->dev, "%s: prox persistence = %d",
-		__func__, filter_delay);
+		 __func__, filter_delay);
 
 	tsl2x7x_invoke_change(indio_dev);
 
@@ -1117,7 +1141,8 @@ static ssize_t tsl2x7x_prox_persistence_store(struct device *dev,
 }
 
 static ssize_t tsl2x7x_do_calibrate(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+				    struct device_attribute *attr,
+				    const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	bool value;
@@ -1134,7 +1159,8 @@ static ssize_t tsl2x7x_do_calibrate(struct device *dev,
 }
 
 static ssize_t tsl2x7x_luxtable_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+				     struct device_attribute *attr,
+				     char *buf)
 {
 	struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
 	int i = 0;
@@ -1146,8 +1172,10 @@ static ssize_t tsl2x7x_luxtable_show(struct device *dev,
 			chip->tsl2x7x_device_lux[i].ch0,
 			chip->tsl2x7x_device_lux[i].ch1);
 		if (chip->tsl2x7x_device_lux[i].ratio == 0) {
-			/* We just printed the first "0" entry.
-			 * Now get rid of the extra "," and break. */
+			/*
+			 * We just printed the first "0" entry.
+			 * Now get rid of the extra "," and break.
+			 */
 			offset--;
 			break;
 		}
@@ -1159,11 +1187,12 @@ static ssize_t tsl2x7x_luxtable_show(struct device *dev,
 }
 
 static ssize_t tsl2x7x_luxtable_store(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+				      struct device_attribute *attr,
+				      const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-	int value[ARRAY_SIZE(chip->tsl2x7x_device_lux)*3 + 1];
+	int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 3 + 1];
 	int n;
 
 	get_options(buf, ARRAY_SIZE(value), value);
@@ -1175,7 +1204,7 @@ static ssize_t tsl2x7x_luxtable_store(struct device *dev,
 	 */
 	n = value[0];
 	if ((n % 3) || n < 6 ||
-			n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) {
+	    n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) {
 		dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
 		return -EINVAL;
 	}
@@ -1198,7 +1227,8 @@ static ssize_t tsl2x7x_luxtable_store(struct device *dev,
 }
 
 static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t len)
+					 struct device_attribute *attr,
+					 const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	bool value;
@@ -1391,10 +1421,10 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
 }
 
 static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       int val,
-			       int val2,
-			       long mask)
+			     struct iio_chan_spec const *chan,
+			     int val,
+			     int val2,
+			     long mask)
 {
 	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
 
@@ -1524,12 +1554,12 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
 {
 	struct iio_dev *indio_dev = private;
 	struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-	s64 timestamp = iio_get_time_ns();
+	s64 timestamp = iio_get_time_ns(indio_dev);
 	int ret;
 	u8 value;
 
 	value = i2c_smbus_read_byte_data(chip->client,
-		TSL2X7X_CMD_REG | TSL2X7X_STATUS);
+					 TSL2X7X_CMD_REG | TSL2X7X_STATUS);
 
 	/* What type of interrupt do we need to process */
 	if (value & TSL2X7X_STA_PRX_INTR) {
@@ -1545,16 +1575,16 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
 	if (value & TSL2X7X_STA_ALS_INTR) {
 		tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */
 		iio_push_event(indio_dev,
-		       IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
-					    0,
-					    IIO_EV_TYPE_THRESH,
-					    IIO_EV_DIR_EITHER),
-					    timestamp);
+			       IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+						    0,
+						    IIO_EV_TYPE_THRESH,
+						    IIO_EV_DIR_EITHER),
+			       timestamp);
 	}
 	/* Clear interrupt now that we have handled it. */
 	ret = i2c_smbus_write_byte(chip->client,
-		TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
-		TSL2X7X_CMD_PROXALS_INT_CLR);
+				   TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+				   TSL2X7X_CMD_PROXALS_INT_CLR);
 	if (ret < 0)
 		dev_err(&chip->client->dev,
 			"Failed to clear irq from event handler. err = %d\n",
@@ -1616,6 +1646,7 @@ static struct attribute *tsl2X7X_ALS_event_attrs[] = {
 	&dev_attr_in_intensity0_thresh_period.attr,
 	NULL,
 };
+
 static struct attribute *tsl2X7X_PRX_event_attrs[] = {
 	&dev_attr_in_proximity0_thresh_period.attr,
 	NULL,
@@ -1857,7 +1888,7 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
 };
 
 static int tsl2x7x_probe(struct i2c_client *clientp,
-	const struct i2c_device_id *id)
+			 const struct i2c_device_id *id)
 {
 	int ret;
 	unsigned char device_id;
@@ -1873,14 +1904,14 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
 	i2c_set_clientdata(clientp, indio_dev);
 
 	ret = tsl2x7x_i2c_read(chip->client,
-		TSL2X7X_CHIPID, &device_id);
+			       TSL2X7X_CHIPID, &device_id);
 	if (ret < 0)
 		return ret;
 
 	if ((!tsl2x7x_device_id(&device_id, id->driver_data)) ||
-		(tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) {
+	    (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) {
 		dev_info(&chip->client->dev,
-				"%s: i2c device found does not match expected id\n",
+			 "%s: i2c device found does not match expected id\n",
 				__func__);
 		return -EINVAL;
 	}
@@ -1892,8 +1923,10 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
 		return ret;
 	}
 
-	/* ALS and PROX functions can be invoked via user space poll
-	 * or H/W interrupt. If busy return last sample. */
+	/*
+	 * ALS and PROX functions can be invoked via user space poll
+	 * or H/W interrupt. If busy return last sample.
+	 */
 	mutex_init(&chip->als_mutex);
 	mutex_init(&chip->prox_mutex);
 
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index 6928710..4b5f05f 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -333,7 +333,8 @@ static int ade7753_set_irq(struct device *dev, bool enable)
 
 	if (enable)
 		irqen |= BIT(3); /* Enables an interrupt when a data is
-				    present in the waveform register */
+				  * present in the waveform register
+				  */
 	else
 		irqen &= ~BIT(3);
 
@@ -528,7 +529,6 @@ static int ade7753_probe(struct spi_device *spi)
 	return iio_device_register(indio_dev);
 }
 
-/* fixme, confirm ordering in this function */
 static int ade7753_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index f4188e1..c46bef6 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -351,7 +351,8 @@ static int ade7754_set_irq(struct device *dev, bool enable)
 
 	if (enable)
 		irqen |= BIT(14); /* Enables an interrupt when a data is
-				     present in the waveform register */
+				   * present in the waveform register
+				   */
 	else
 		irqen &= ~BIT(14);
 
@@ -558,7 +559,6 @@ powerdown_on_error:
 	return ret;
 }
 
-/* fixme, confirm ordering in this function */
 static int ade7754_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h
index f6739e2..1d04ec9 100644
--- a/drivers/staging/iio/meter/ade7758.h
+++ b/drivers/staging/iio/meter/ade7758.h
@@ -129,6 +129,7 @@ struct ade7758_state {
 	unsigned char		tx_buf[8];
 
 };
+
 #ifdef CONFIG_IIO_BUFFER
 /* At the moment triggers are only used for ring buffer
  * filling. This may change!
@@ -138,25 +139,22 @@ void ade7758_remove_trigger(struct iio_dev *indio_dev);
 int ade7758_probe_trigger(struct iio_dev *indio_dev);
 
 ssize_t ade7758_read_data_from_ring(struct device *dev,
-		struct device_attribute *attr,
-		char *buf);
-
+				    struct device_attribute *attr, char *buf);
 
 int ade7758_configure_ring(struct iio_dev *indio_dev);
 void ade7758_unconfigure_ring(struct iio_dev *indio_dev);
 
 int ade7758_set_irq(struct device *dev, bool enable);
 
-int ade7758_spi_write_reg_8(struct device *dev,
-		u8 reg_address, u8 val);
-int ade7758_spi_read_reg_8(struct device *dev,
-		u8 reg_address, u8 *val);
+int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val);
+int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val);
 
 #else /* CONFIG_IIO_BUFFER */
 
 static inline void ade7758_remove_trigger(struct iio_dev *indio_dev)
 {
 }
+
 static inline int ade7758_probe_trigger(struct iio_dev *indio_dev)
 {
 	return 0;
@@ -166,16 +164,20 @@ static int ade7758_configure_ring(struct iio_dev *indio_dev)
 {
 	return 0;
 }
+
 static inline void ade7758_unconfigure_ring(struct iio_dev *indio_dev)
 {
 }
+
 static inline int ade7758_initialize_ring(struct iio_ring_buffer *ring)
 {
 	return 0;
 }
+
 static inline void ade7758_uninitialize_ring(struct iio_dev *indio_dev)
 {
 }
+
 #endif /* CONFIG_IIO_BUFFER */
 
 #endif
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index 40f5afa..ebb8a19 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -24,9 +24,7 @@
 #include "meter.h"
 #include "ade7758.h"
 
-int ade7758_spi_write_reg_8(struct device *dev,
-		u8 reg_address,
-		u8 val)
+int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
 {
 	int ret;
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -42,9 +40,8 @@ int ade7758_spi_write_reg_8(struct device *dev,
 	return ret;
 }
 
-static int ade7758_spi_write_reg_16(struct device *dev,
-		u8 reg_address,
-		u16 value)
+static int ade7758_spi_write_reg_16(struct device *dev, u8 reg_address,
+				    u16 value)
 {
 	int ret;
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -68,9 +65,8 @@ static int ade7758_spi_write_reg_16(struct device *dev,
 	return ret;
 }
 
-static int ade7758_spi_write_reg_24(struct device *dev,
-		u8 reg_address,
-		u32 value)
+static int ade7758_spi_write_reg_24(struct device *dev, u8 reg_address,
+				    u32 value)
 {
 	int ret;
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -95,9 +91,7 @@ static int ade7758_spi_write_reg_24(struct device *dev,
 	return ret;
 }
 
-int ade7758_spi_read_reg_8(struct device *dev,
-		u8 reg_address,
-		u8 *val)
+int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
@@ -124,7 +118,7 @@ int ade7758_spi_read_reg_8(struct device *dev,
 	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
 	if (ret) {
 		dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
-				reg_address);
+			reg_address);
 		goto error_ret;
 	}
 	*val = st->rx[0];
@@ -134,9 +128,8 @@ error_ret:
 	return ret;
 }
 
-static int ade7758_spi_read_reg_16(struct device *dev,
-		u8 reg_address,
-		u16 *val)
+static int ade7758_spi_read_reg_16(struct device *dev, u8 reg_address,
+				   u16 *val)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
@@ -156,7 +149,6 @@ static int ade7758_spi_read_reg_16(struct device *dev,
 		},
 	};
 
-
 	mutex_lock(&st->buf_lock);
 	st->tx[0] = ADE7758_READ_REG(reg_address);
 	st->tx[1] = 0;
@@ -165,7 +157,7 @@ static int ade7758_spi_read_reg_16(struct device *dev,
 	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
 	if (ret) {
 		dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
-				reg_address);
+			reg_address);
 		goto error_ret;
 	}
 
@@ -176,9 +168,8 @@ error_ret:
 	return ret;
 }
 
-static int ade7758_spi_read_reg_24(struct device *dev,
-		u8 reg_address,
-		u32 *val)
+static int ade7758_spi_read_reg_24(struct device *dev, u8 reg_address,
+				   u32 *val)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	struct ade7758_state *st = iio_priv(indio_dev);
@@ -207,7 +198,7 @@ static int ade7758_spi_read_reg_24(struct device *dev,
 	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
 	if (ret) {
 		dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
-				reg_address);
+			reg_address);
 		goto error_ret;
 	}
 	*val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
@@ -218,8 +209,7 @@ error_ret:
 }
 
 static ssize_t ade7758_read_8bit(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
+				 struct device_attribute *attr, char *buf)
 {
 	int ret;
 	u8 val = 0;
@@ -233,8 +223,7 @@ static ssize_t ade7758_read_8bit(struct device *dev,
 }
 
 static ssize_t ade7758_read_16bit(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
+				  struct device_attribute *attr, char *buf)
 {
 	int ret;
 	u16 val = 0;
@@ -248,8 +237,7 @@ static ssize_t ade7758_read_16bit(struct device *dev,
 }
 
 static ssize_t ade7758_read_24bit(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
+				  struct device_attribute *attr, char *buf)
 {
 	int ret;
 	u32 val = 0;
@@ -263,9 +251,8 @@ static ssize_t ade7758_read_24bit(struct device *dev,
 }
 
 static ssize_t ade7758_write_8bit(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
+				  struct device_attribute *attr,
+				  const char *buf, size_t len)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int ret;
@@ -281,9 +268,8 @@ error_ret:
 }
 
 static ssize_t ade7758_write_16bit(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
+				   struct device_attribute *attr,
+				   const char *buf, size_t len)
 {
 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	int ret;
@@ -427,7 +413,8 @@ int ade7758_set_irq(struct device *dev, bool enable)
 
 	if (enable)
 		irqen |= BIT(16); /* Enables an interrupt when a data is
-				     present in the waveform register */
+				   * present in the waveform register
+				   */
 	else
 		irqen &= ~BIT(16);
 
@@ -479,16 +466,13 @@ err_ret:
 }
 
 static ssize_t ade7758_read_frequency(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
+				      struct device_attribute *attr, char *buf)
 {
 	int ret;
 	u8 t;
 	int sps;
 
-	ret = ade7758_spi_read_reg_8(dev,
-			ADE7758_WAVMODE,
-			&t);
+	ret = ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &t);
 	if (ret)
 		return ret;
 
@@ -499,9 +483,8 @@ static ssize_t ade7758_read_frequency(struct device *dev,
 }
 
 static ssize_t ade7758_write_frequency(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
+				       struct device_attribute *attr,
+				       const char *buf, size_t len)
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 	u16 val;
@@ -532,18 +515,14 @@ static ssize_t ade7758_write_frequency(struct device *dev,
 		goto out;
 	}
 
-	ret = ade7758_spi_read_reg_8(dev,
-			ADE7758_WAVMODE,
-			&reg);
+	ret = ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &reg);
 	if (ret)
 		goto out;
 
 	reg &= ~(5 << 3);
 	reg |= t << 5;
 
-	ret = ade7758_spi_write_reg_8(dev,
-			ADE7758_WAVMODE,
-			reg);
+	ret = ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg);
 
 out:
 	mutex_unlock(&indio_dev->mlock);
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index 9a24e02..a6b76d4 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -33,7 +33,7 @@ static int ade7758_spi_read_burst(struct iio_dev *indio_dev)
 	return ret;
 }
 
-static int ade7758_write_waveform_type(struct device *dev, unsigned type)
+static int ade7758_write_waveform_type(struct device *dev, unsigned int type)
 {
 	int ret;
 	u8 reg;
@@ -85,7 +85,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
  **/
 static int ade7758_ring_preenable(struct iio_dev *indio_dev)
 {
-	unsigned channel;
+	unsigned int channel;
 
 	if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
 		return -EINVAL;
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index 684e612..80144d4 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -289,7 +289,8 @@ static int ade7759_set_irq(struct device *dev, bool enable)
 
 	if (enable)
 		irqen |= BIT(3); /* Enables an interrupt when a data is
-				    present in the waveform register */
+				  * present in the waveform register
+				  */
 	else
 		irqen &= ~BIT(3);
 
@@ -476,7 +477,6 @@ static int ade7759_probe(struct spi_device *spi)
 	return iio_device_register(indio_dev);
 }
 
-/* fixme, confirm ordering in this function */
 static int ade7759_remove(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
index 9e439af..75e8685 100644
--- a/drivers/staging/iio/meter/ade7854.c
+++ b/drivers/staging/iio/meter/ade7854.c
@@ -421,7 +421,8 @@ static int ade7854_set_irq(struct device *dev, bool enable)
 
 	if (enable)
 		irqen |= BIT(17); /* 1: interrupt enabled when all periodical
-				     (at 8 kHz rate) DSP computations finish. */
+				   * (at 8 kHz rate) DSP computations finish.
+				   */
 	else
 		irqen &= ~BIT(17);
 
diff --git a/drivers/staging/iio/resolver/ad2s1210.h b/drivers/staging/iio/resolver/ad2s1210.h
index c7158f6..e9b2147 100644
--- a/drivers/staging/iio/resolver/ad2s1210.h
+++ b/drivers/staging/iio/resolver/ad2s1210.h
@@ -12,9 +12,9 @@
 #define _AD2S1210_H
 
 struct ad2s1210_platform_data {
-	unsigned sample;
-	unsigned a[2];
-	unsigned res[2];
-	bool gpioin;
+	unsigned int		sample;
+	unsigned int		a[2];
+	unsigned int		res[2];
+	bool			gpioin;
 };
 #endif /* _AD2S1210_H */
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
index 035dd45..38dca69 100644
--- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -55,12 +55,12 @@ static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = {
 };
 
 struct bfin_tmr_state {
-	struct iio_trigger *trig;
-	struct bfin_timer *t;
-	unsigned timer_num;
-	bool output_enable;
-	unsigned int duty;
-	int irq;
+	struct iio_trigger	*trig;
+	struct bfin_timer	*t;
+	unsigned int		timer_num;
+	bool			output_enable;
+	unsigned int		duty;
+	int			irq;
 };
 
 static int iio_bfin_tmr_set_state(struct iio_trigger *trig, bool state)
@@ -178,7 +178,7 @@ static const struct iio_trigger_ops iio_bfin_tmr_trigger_ops = {
 
 static int iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
 {
-	struct iio_bfin_timer_trigger_pdata *pdata = pdev->dev.platform_data;
+	struct iio_bfin_timer_trigger_pdata *pdata;
 	struct bfin_tmr_state *st;
 	unsigned int config;
 	int ret;
@@ -221,6 +221,7 @@ static int iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
 
 	config = PWM_OUT | PERIOD_CNT | IRQ_ENA;
 
+	pdata =	dev_get_platdata(&pdev->dev);
 	if (pdata && pdata->output_enable) {
 		unsigned long long val;
 
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 047a7ba..73bf57d 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -132,6 +132,16 @@ void serial8250_rpm_put(struct uart_8250_port *p);
 int serial8250_em485_init(struct uart_8250_port *p);
 void serial8250_em485_destroy(struct uart_8250_port *p);
 
+static inline void serial8250_out_MCR(struct uart_8250_port *up, int value)
+{
+	serial_out(up, UART_MCR, value);
+}
+
+static inline int serial8250_in_MCR(struct uart_8250_port *up)
+{
+	return serial_in(up, UART_MCR);
+}
+
 #if defined(__alpha__) && !defined(CONFIG_PCI)
 /*
  * Digital did something really horribly wrong with the OUT1 and OUT2
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 6f76051..956f25a 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -274,7 +274,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
 	serial_out(up, UART_EFR, UART_EFR_ECB);
 
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-	serial_out(up, UART_MCR, UART_MCR_TCRTLR);
+	serial8250_out_MCR(up, UART_MCR_TCRTLR);
 	serial_out(up, UART_FCR, up->fcr);
 
 	omap8250_update_scr(up, priv);
@@ -290,7 +290,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
 	serial_out(up, UART_LCR, 0);
 
 	/* drop TCR + TLR access, we setup XON/XOFF later */
-	serial_out(up, UART_MCR, up->mcr);
+	serial8250_out_MCR(up, up->mcr);
 	serial_out(up, UART_IER, up->ier);
 
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -1459,10 +1459,10 @@ static int __init omap8250_console_fixup(void)
 	}
 
 	add_preferred_console("ttyS", idx, options);
-	pr_err("WARNING: Your 'console=ttyO%d' has been replaced by 'ttyS%d'\n",
+	pr_info("WARNING: Your 'console=ttyO%d' has been replaced by 'ttyS%d'\n",
 	       idx, idx);
-	pr_err("This ensures that you still see kernel messages. Please\n");
-	pr_err("update your kernel commandline.\n");
+	pr_info("This ensures that you still see kernel messages. Please\n");
+	pr_info("update your kernel commandline.\n");
 	return 0;
 }
 console_initcall(omap8250_console_fixup);
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index c9f6a49..7828991 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -528,13 +528,13 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
 
 static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
 {
-	unsigned char mcr = serial_in(p, UART_MCR);
+	unsigned char mcr = serial8250_in_MCR(p);
 
 	if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
 		mcr |= UART_MCR_RTS;
 	else
 		mcr &= ~UART_MCR_RTS;
-	serial_out(p, UART_MCR, mcr);
+	serial8250_out_MCR(p, mcr);
 }
 
 static void serial8250_em485_handle_start_tx(unsigned long arg);
@@ -786,10 +786,10 @@ static int size_fifo(struct uart_8250_port *up)
 	old_lcr = serial_in(up, UART_LCR);
 	serial_out(up, UART_LCR, 0);
 	old_fcr = serial_in(up, UART_FCR);
-	old_mcr = serial_in(up, UART_MCR);
+	old_mcr = serial8250_in_MCR(up);
 	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
 		    UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-	serial_out(up, UART_MCR, UART_MCR_LOOP);
+	serial8250_out_MCR(up, UART_MCR_LOOP);
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
 	old_dl = serial_dl_read(up);
 	serial_dl_write(up, 0x0001);
@@ -801,7 +801,7 @@ static int size_fifo(struct uart_8250_port *up)
 	     (count < 256); count++)
 		serial_in(up, UART_RX);
 	serial_out(up, UART_FCR, old_fcr);
-	serial_out(up, UART_MCR, old_mcr);
+	serial8250_out_MCR(up, old_mcr);
 	serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
 	serial_dl_write(up, old_dl);
 	serial_out(up, UART_LCR, old_lcr);
@@ -1041,17 +1041,17 @@ static void autoconfig_16550a(struct uart_8250_port *up)
 	 * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
 	 */
 	serial_out(up, UART_LCR, 0);
-	status1 = serial_in(up, UART_MCR);
+	status1 = serial8250_in_MCR(up);
 	serial_out(up, UART_LCR, 0xE0);
 	status2 = serial_in(up, 0x02); /* EXCR1 */
 
 	if (!((status2 ^ status1) & UART_MCR_LOOP)) {
 		serial_out(up, UART_LCR, 0);
-		serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP);
+		serial8250_out_MCR(up, status1 ^ UART_MCR_LOOP);
 		serial_out(up, UART_LCR, 0xE0);
 		status2 = serial_in(up, 0x02); /* EXCR1 */
 		serial_out(up, UART_LCR, 0);
-		serial_out(up, UART_MCR, status1);
+		serial8250_out_MCR(up, status1);
 
 		if ((status2 ^ status1) & UART_MCR_LOOP) {
 			unsigned short quot;
@@ -1225,7 +1225,7 @@ static void autoconfig(struct uart_8250_port *up)
 		}
 	}
 
-	save_mcr = serial_in(up, UART_MCR);
+	save_mcr = serial8250_in_MCR(up);
 	save_lcr = serial_in(up, UART_LCR);
 
 	/*
@@ -1238,9 +1238,9 @@ static void autoconfig(struct uart_8250_port *up)
 	 * that conflicts with COM 1-4 --- we hope!
 	 */
 	if (!(port->flags & UPF_SKIP_TEST)) {
-		serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+		serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A);
 		status1 = serial_in(up, UART_MSR) & 0xF0;
-		serial_out(up, UART_MCR, save_mcr);
+		serial8250_out_MCR(up, save_mcr);
 		if (status1 != 0x90) {
 			spin_unlock_irqrestore(&port->lock, flags);
 			DEBUG_AUTOCONF("LOOP test failed (%02x) ",
@@ -1306,7 +1306,7 @@ static void autoconfig(struct uart_8250_port *up)
 	if (port->type == PORT_RSA)
 		serial_out(up, UART_RSA_FRR, 0);
 #endif
-	serial_out(up, UART_MCR, save_mcr);
+	serial8250_out_MCR(up, save_mcr);
 	serial8250_clear_fifos(up);
 	serial_in(up, UART_RX);
 	if (up->capabilities & UART_CAP_UUE)
@@ -1347,19 +1347,18 @@ static void autoconfig_irq(struct uart_8250_port *up)
 
 	/* forget possible initially masked and pending IRQ */
 	probe_irq_off(probe_irq_on());
-	save_mcr = serial_in(up, UART_MCR);
+	save_mcr = serial8250_in_MCR(up);
 	save_ier = serial_in(up, UART_IER);
-	serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+	serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2);
 
 	irqs = probe_irq_on();
-	serial_out(up, UART_MCR, 0);
+	serial8250_out_MCR(up, 0);
 	udelay(10);
 	if (port->flags & UPF_FOURPORT) {
-		serial_out(up, UART_MCR,
-			    UART_MCR_DTR | UART_MCR_RTS);
+		serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
 	} else {
-		serial_out(up, UART_MCR,
-			    UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+		serial8250_out_MCR(up,
+			UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
 	}
 	serial_out(up, UART_IER, 0x0f);	/* enable all intrs */
 	serial_in(up, UART_LSR);
@@ -1370,7 +1369,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
 	udelay(20);
 	irq = probe_irq_off(irqs);
 
-	serial_out(up, UART_MCR, save_mcr);
+	serial8250_out_MCR(up, save_mcr);
 	serial_out(up, UART_IER, save_ier);
 
 	if (port->flags & UPF_FOURPORT)
@@ -1543,14 +1542,14 @@ static inline void start_tx_rs485(struct uart_port *port)
 	del_timer(&em485->stop_tx_timer);
 	em485->active_timer = NULL;
 
-	mcr = serial_in(up, UART_MCR);
+	mcr = serial8250_in_MCR(up);
 	if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
 	    !!(mcr & UART_MCR_RTS)) {
 		if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
 			mcr |= UART_MCR_RTS;
 		else
 			mcr &= ~UART_MCR_RTS;
-		serial_out(up, UART_MCR, mcr);
+		serial8250_out_MCR(up, mcr);
 
 		if (up->port.rs485.delay_rts_before_send > 0) {
 			em485->active_timer = &em485->start_tx_timer;
@@ -1923,7 +1922,7 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
 	mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
 
-	serial_port_out(port, UART_MCR, mcr);
+	serial8250_out_MCR(up, mcr);
 }
 EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
 
@@ -3072,7 +3071,7 @@ static void serial8250_console_restore(struct uart_8250_port *up)
 
 	serial8250_set_divisor(port, baud, quot, frac);
 	serial_port_out(port, UART_LCR, up->lcr);
-	serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+	serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
 }
 
 /*
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 0ee7c4c..1c4b477 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1591,6 +1591,31 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
 	return 0;
 }
 
+static int serial_omap_of_get_port_line(struct device_node *np)
+{
+	unsigned long val;
+	const char *hwmod;
+	int ret;
+
+	/* first try the serial alias */
+	ret = of_alias_get_id(np, "serial");
+	if (ret >= 0)
+		return ret;
+
+	/* no? calculate it from hwmods */
+	ret = of_property_read_string(np, "ti,hwmods", &hwmod);
+	if (ret != 0 || strncmp(hwmod, "uart", 4) ||
+			kstrtoul(hwmod + 4, 10, &val))
+		return -ENODEV;
+
+	/* numbering of hwmods is +1 */
+	ret = (int)val - 1;
+	if (ret < 0)
+		return -ENODEV;
+
+	return ret;
+}
+
 static int serial_omap_probe(struct platform_device *pdev)
 {
 	struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
@@ -1608,7 +1633,10 @@ static int serial_omap_probe(struct platform_device *pdev)
 			return -EPROBE_DEFER;
 		wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
 		omap_up_info = of_get_uart_port_info(&pdev->dev);
-		pdev->dev.platform_data = omap_up_info;
+		ret = platform_device_add_data(pdev, omap_up_info,
+				sizeof(*omap_up_info));
+		if (ret != 0)
+			return ret;
 	} else {
 		uartirq = platform_get_irq(pdev, 0);
 		if (uartirq < 0)
@@ -1634,7 +1662,7 @@ static int serial_omap_probe(struct platform_device *pdev)
 	up->port.ops = &serial_omap_pops;
 
 	if (pdev->dev.of_node)
-		ret = of_alias_get_id(pdev->dev.of_node, "serial");
+		ret = serial_omap_of_get_port_line(pdev->dev.of_node);
 	else
 		ret = pdev->id;
 
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 0214736..85b77ba 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -88,6 +88,24 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
 }
 EXPORT_SYMBOL_GPL(mctrl_gpio_get);
 
+unsigned int
+mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
+{
+	enum mctrl_gpio_idx i;
+
+	for (i = 0; i < UART_GPIO_MAX; i++) {
+		if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
+			if (gpiod_get_value(gpios->gpio[i]))
+				*mctrl |= mctrl_gpios_desc[i].mctrl;
+			else
+				*mctrl &= ~mctrl_gpios_desc[i].mctrl;
+		}
+	}
+
+	return *mctrl;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs);
+
 struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
 {
 	struct mctrl_gpios *gpios;
@@ -125,6 +143,9 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
 	struct uart_port *port = gpios->port;
 	u32 mctrl = gpios->mctrl_prev;
 	u32 mctrl_diff;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
 
 	mctrl_gpio_get(gpios, &mctrl);
 
@@ -147,6 +168,8 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
 		wake_up_interruptible(&port->state->port.delta_msr_wait);
 	}
 
+	spin_unlock_irqrestore(&port->lock, flags);
+
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h
index 9716db2..e8ad5e6 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.h
+++ b/drivers/tty/serial/serial_mctrl_gpio.h
@@ -50,12 +50,19 @@ struct mctrl_gpios;
 void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl);
 
 /*
- * Get state of the modem control output lines from GPIOs.
+ * Get state of the modem control input lines from GPIOs.
  * The mctrl flags are updated and returned.
  */
 unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
 
 /*
+ * Get state of the modem control output lines from GPIOs.
+ * The mctrl flags are updated and returned.
+ */
+unsigned int
+mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl);
+
+/*
  * Returns the associated struct gpio_desc to the modem line gidx
  */
 struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
@@ -109,6 +116,12 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
 	return *mctrl;
 }
 
+static inline unsigned int
+mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
+{
+	return *mctrl;
+}
+
 static inline
 struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
 				      enum mctrl_gpio_idx gidx)
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 52c98ce..05400bc 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -129,7 +129,7 @@ config UIO_PRUSS
 	select GENERIC_ALLOCATOR
 	depends on HAS_IOMEM && HAS_DMA
 	help
-	  PRUSS driver for OMAPL138/DA850/AM18XX devices
+	  PRUSS driver for OMAPL138/DA850/AM18XX and AM33XX devices
 	  PRUSS driver requires user space components, examples and user space
 	  driver is available from below SVN repo - you may use anonymous login
 
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c
index ca9e2fa..6559752 100644
--- a/drivers/uio/uio_pruss.c
+++ b/drivers/uio/uio_pruss.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
+#include <linux/of_gpio.h>
 #include <linux/uio_driver.h>
 #include <linux/platform_data/uio_pruss.h>
 #include <linux/io.h>
@@ -27,6 +28,11 @@
 #include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/genalloc.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
 
 #define DRV_NAME "pruss_uio"
 #define DRV_VERSION "1.0"
@@ -106,10 +112,12 @@ static void pruss_cleanup(struct device *dev, struct uio_pruss_dev *gdev)
 		dma_free_coherent(dev, extram_pool_sz, gdev->ddr_vaddr,
 			gdev->ddr_paddr);
 	}
+#ifdef CONFIG_ARCH_DAVINCI_DA850
 	if (gdev->sram_vaddr)
 		gen_pool_free(gdev->sram_pool,
 			      gdev->sram_vaddr,
 			      sram_pool_sz);
+#endif
 	kfree(gdev->info);
 	clk_put(gdev->pruss_clk);
 	kfree(gdev);
@@ -120,9 +128,15 @@ static int pruss_probe(struct platform_device *pdev)
 	struct uio_info *p;
 	struct uio_pruss_dev *gdev;
 	struct resource *regs_prussio;
+	struct resource res;
 	struct device *dev = &pdev->dev;
 	int ret = -ENODEV, cnt = 0, len;
 	struct uio_pruss_pdata *pdata = dev_get_platdata(dev);
+	struct pinctrl *pinctrl;
+
+	int count;
+	struct device_node *child;
+	const char *pin_name;
 
 	gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL);
 	if (!gdev)
@@ -133,7 +147,7 @@ static int pruss_probe(struct platform_device *pdev)
 		kfree(gdev);
 		return -ENOMEM;
 	}
-
+#ifdef CONFIG_ARCH_DAVINCI_DA850
 	/* Power on PRU in case its not done as part of boot-loader */
 	gdev->pruss_clk = clk_get(dev, "pruss");
 	if (IS_ERR(gdev->pruss_clk)) {
@@ -145,8 +159,25 @@ static int pruss_probe(struct platform_device *pdev)
 	} else {
 		clk_enable(gdev->pruss_clk);
 	}
+#endif
+
+	if (pdev->dev.of_node) {
+		pm_runtime_enable(&pdev->dev);
+		ret = pm_runtime_get_sync(&pdev->dev);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+			return ret;
+		}
 
-	regs_prussio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		ret = of_address_to_resource(pdev->dev.of_node, 0, &res);
+		if (IS_ERR_VALUE(ret)) {
+			dev_err(&pdev->dev, "failed to parse DT reg\n");
+			return ret;
+		}
+		regs_prussio = &res;
+	}
+	else
+		regs_prussio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!regs_prussio) {
 		dev_err(dev, "No PRUSS I/O resource specified\n");
 		goto out_free;
@@ -157,7 +188,50 @@ static int pruss_probe(struct platform_device *pdev)
 		goto out_free;
 	}
 
-	if (pdata->sram_pool) {
+
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl))
+		dev_warn(&pdev->dev,
+			"pins are not configured from the driver\n");
+	else{
+		count = of_get_child_count(pdev->dev.of_node);
+		if (!count){
+			dev_info(&pdev->dev, "No children\n");
+			return -ENODEV;
+		}
+		// Run through all children. They have lables for easy reference.
+		for_each_child_of_node(pdev->dev.of_node, child){
+			enum of_gpio_flags flags;
+			unsigned gpio;
+
+			count = of_gpio_count(child);
+
+			ret = of_property_count_strings(child, "pin-names");
+			if (ret < 0) {
+				dev_err(&pdev->dev, "Failed to get pin-names\n");
+				continue;
+			}
+			if(count != ret){
+				dev_err(&pdev->dev, "The number of gpios (%d) does not match"\
+					" the number of pin names (%d)\n", count, ret);
+				continue;
+			}
+
+			for(cnt=0; cnt<count; cnt++){
+				ret = of_property_read_string_index(child,
+					"pin-names", cnt, &pin_name);
+				if (ret != 0)
+					dev_err(&pdev->dev, "Error on pin-name #%d\n", cnt);
+				gpio = of_get_gpio_flags(child, cnt, &flags);
+				ret = devm_gpio_request_one(&pdev->dev, gpio, flags, pin_name);
+				if (ret < 0) {
+		                        dev_err(dev, "Failed to request GPIO %d (%s) flags: '%d', error %d\n",
+					gpio, pin_name, flags, ret);
+		                }
+			}
+		}
+	}
+	if (pdata && pdata->sram_pool) {
 		gdev->sram_pool = pdata->sram_pool;
 		gdev->sram_vaddr =
 			(unsigned long)gen_pool_dma_alloc(gdev->sram_pool,
@@ -182,7 +256,17 @@ static int pruss_probe(struct platform_device *pdev)
 		goto out_free;
 	}
 
-	gdev->pintc_base = pdata->pintc_base;
+	if (pdev->dev.of_node) {
+		ret = of_property_read_u32(pdev->dev.of_node,
+					   "ti,pintc-offset",
+					   &gdev->pintc_base);
+		if (ret < 0) {
+			dev_err(&pdev->dev,
+				"Can't parse ti,pintc-offset property\n");
+			goto out_free;
+		}
+	} else
+		gdev->pintc_base = pdata->pintc_base;
 	gdev->hostirq_start = platform_get_irq(pdev, 0);
 
 	for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++) {
@@ -190,6 +274,7 @@ static int pruss_probe(struct platform_device *pdev)
 		p->mem[0].size = resource_size(regs_prussio);
 		p->mem[0].memtype = UIO_MEM_PHYS;
 
+#ifdef CONFIG_ARCH_DAVINCI_DA850
 		p->mem[1].addr = gdev->sram_paddr;
 		p->mem[1].size = sram_pool_sz;
 		p->mem[1].memtype = UIO_MEM_PHYS;
@@ -197,7 +282,11 @@ static int pruss_probe(struct platform_device *pdev)
 		p->mem[2].addr = gdev->ddr_paddr;
 		p->mem[2].size = extram_pool_sz;
 		p->mem[2].memtype = UIO_MEM_PHYS;
-
+#else
+		p->mem[1].addr = gdev->ddr_paddr;
+		p->mem[1].size = extram_pool_sz;
+		p->mem[1].memtype = UIO_MEM_PHYS;
+#endif
 		p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", cnt);
 		p->version = DRV_VERSION;
 
@@ -227,11 +316,20 @@ static int pruss_remove(struct platform_device *dev)
 	return 0;
 }
 
+static const struct of_device_id pruss_dt_ids[] = {
+	{ .compatible = "ti,pruss-v1", .data = NULL, },
+	{ .compatible = "ti,pruss-v2", .data = NULL, },
+	{},
+};
+MODULE_DEVICE_TABLE(of, pruss_dt_ids);
+
+
 static struct platform_driver pruss_driver = {
 	.probe = pruss_probe,
 	.remove = pruss_remove,
 	.driver = {
 		   .name = DRV_NAME,
+		   .of_match_table = pruss_dt_ids,
 		   },
 };
 
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 053bac9..55120ef 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -109,15 +109,25 @@ static int host_start(struct ci_hdrc *ci)
 	struct ehci_hcd *ehci;
 	struct ehci_ci_priv *priv;
 	int ret;
+	struct device *dev = ci->dev;
 
-	if (usb_disabled())
+	if (usb_disabled() || !dev)
 		return -ENODEV;
 
-	hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
+	/*
+	 * USB Core will try to get child node under roothub,
+	 * but chipidea core has no of_node, and the child node
+	 * for controller is located at glue layer's node which
+	 * is chipidea core's parent.
+	 */
+	if (dev->parent && dev->parent->of_node)
+		dev->of_node = dev->parent->of_node;
+
+	hcd = usb_create_hcd(&ci_ehci_hc_driver, dev, dev_name(dev));
 	if (!hcd)
 		return -ENOMEM;
 
-	dev_set_drvdata(ci->dev, ci);
+	dev_set_drvdata(dev, ci);
 	hcd->rsrc_start = ci->hw_bank.phys;
 	hcd->rsrc_len = ci->hw_bank.size;
 	hcd->regs = ci->hw_bank.abs;
@@ -143,7 +153,7 @@ static int host_start(struct ci_hdrc *ci)
 		if (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON) {
 			ret = regulator_enable(ci->platdata->reg_vbus);
 			if (ret) {
-				dev_err(ci->dev,
+				dev_err(dev,
 				"Failed to enable vbus regulator, ret=%d\n",
 									ret);
 				goto put_hcd;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 1ab42bf..2f5012a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -26,6 +26,7 @@
 #include <linux/mutex.h>
 #include <linux/random.h>
 #include <linux/pm_qos.h>
+#include <linux/of_platform.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -1364,6 +1365,34 @@ static int hub_post_reset(struct usb_interface *intf)
 	return 0;
 }
 
+static int hub_of_children_register(struct usb_device *hdev)
+{
+	struct device *dev;
+
+	if (hdev->parent)
+		dev = &hdev->dev;
+	else
+		dev = bus_to_hcd(hdev->bus)->self.controller;
+
+	if (!dev->of_node)
+		return 0;
+
+	return of_platform_populate(dev->of_node, NULL, NULL, dev);
+}
+
+static void hub_of_children_unregister(struct usb_device *hdev)
+{
+	struct device *dev;
+
+	if (hdev->parent)
+		dev = &hdev->dev;
+	else
+		dev = bus_to_hcd(hdev->bus)->self.controller;
+
+	if (dev->of_node)
+		of_platform_depopulate(dev);
+}
+
 static int hub_configure(struct usb_hub *hub,
 	struct usb_endpoint_descriptor *endpoint)
 {
@@ -1707,6 +1736,7 @@ static void hub_disconnect(struct usb_interface *intf)
 	usb_set_intfdata(intf, NULL);
 	spin_unlock_irq(&device_state_lock);
 
+	hub_of_children_unregister(hdev);
 	for (; port1 > 0; --port1)
 		usb_hub_remove_port_device(hub, port1);
 
@@ -1731,6 +1761,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_device *hdev;
 	struct usb_hub *hub;
+	int ret;
 
 	desc = intf->cur_altsetting;
 	hdev = interface_to_usbdev(intf);
@@ -1850,6 +1881,12 @@ descriptor_error:
 	if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
 		hub->quirk_check_port_auto_suspend = 1;
 
+	ret = hub_of_children_register(hdev);
+	if (ret) {
+		dev_err(&hdev->dev, "Failed to register child device\n");
+		return ret;
+	}
+
 	if (hub_configure(hub, endpoint) >= 0)
 		return 0;
 
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index f7a7fc2..089e2c4 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -268,3 +268,13 @@ config USB_CHAOSKEY
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called chaoskey.
+
+config USB_ONBOARD_DEVICE
+	tristate "Generic USB Onboard Device"
+	help
+	  depends on OF
+	  Say Y here if your board has an onboard device, and this device
+	  needs to control its PHY clock and reset pin through external
+	  signals. If you are not sure, say N.
+
+	  To compile this driver as a module, choose M here.
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 45fd4ac..60731bb 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_USB_CHAOSKEY)		+= chaoskey.o
 
 obj-$(CONFIG_USB_SISUSBVGA)		+= sisusbvga/
 obj-$(CONFIG_USB_LINK_LAYER_TEST)	+= lvstest.o
+obj-$(CONFIG_USB_ONBOARD_DEVICE)	+= generic_onboard_device.o
diff --git b/drivers/usb/misc/generic_onboard_device.c b/drivers/usb/misc/generic_onboard_device.c
new file mode 100644
index 0000000..0111bd9
--- /dev/null
+++ b/drivers/usb/misc/generic_onboard_device.c
@@ -0,0 +1,144 @@
+/*
+ * generic_onboard_device.c	The generic onboard USB device driver
+ *
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Author: Peter Chen <peter.chen@freescale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This driver is only for the USB HUB devices which need to control
+ * their external pins(clock, reset, etc), and these USB HUB devices
+ * are soldered at the board.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+struct usb_generic_onboard_data {
+	struct clk *clk;
+};
+
+static int usb_generic_onboard_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct usb_generic_onboard_data *hub_data;
+	int ret = -EINVAL;
+	struct gpio_desc *gpiod_reset = NULL;
+	struct device_node *node = dev->of_node;
+	u32 duration_us = 50, clk_rate = 0;
+
+	/* Only support device tree now */
+	if (!node)
+		return ret;
+
+	hub_data = devm_kzalloc(dev, sizeof(*hub_data), GFP_KERNEL);
+	if (!hub_data)
+		return -ENOMEM;
+
+	hub_data->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(hub_data->clk)) {
+		dev_dbg(dev, "Can't get clock: %ld\n",
+			PTR_ERR(hub_data->clk));
+		hub_data->clk = NULL;
+	} else {
+		ret = clk_prepare_enable(hub_data->clk);
+		if (ret) {
+			dev_err(dev,
+				"Can't enable external clock: %d\n",
+				ret);
+			return ret;
+		}
+
+		of_property_read_u32(node, "clock-frequency", &clk_rate);
+		if (clk_rate) {
+			ret = clk_set_rate(hub_data->clk, clk_rate);
+			if (ret) {
+				dev_err(dev, "Error setting clock rate\n");
+				goto disable_clk;
+			}
+		}
+	}
+
+	gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);
+	ret = PTR_ERR_OR_ZERO(gpiod_reset);
+	if (ret) {
+		dev_err(dev, "Failed to get reset gpio, err = %d\n", ret);
+		goto disable_clk;
+	}
+
+	of_property_read_u32(node, "reset-duration-us", &duration_us);
+
+	if (gpiod_reset) {
+		gpiod_direction_output(gpiod_reset, 1);
+
+		gpiod_set_value(gpiod_reset, 1);
+		usleep_range(duration_us, duration_us + 10);
+		gpiod_set_value(gpiod_reset, 0);
+	}
+
+	dev_set_drvdata(dev, hub_data);
+	return ret;
+
+disable_clk:
+	clk_disable_unprepare(hub_data->clk);
+	return ret;
+}
+
+static int usb_generic_onboard_remove(struct platform_device *pdev)
+{
+	struct usb_generic_onboard_data *hub_data = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(hub_data->clk);
+	return 0;
+}
+
+static const struct of_device_id usb_generic_onboard_dt_ids[] = {
+	{.compatible = "generic-onboard-device"},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, usb_generic_onboard_dt_ids);
+
+static struct platform_driver usb_generic_onboard_driver = {
+	.probe = usb_generic_onboard_probe,
+	.remove = usb_generic_onboard_remove,
+	.driver = {
+		.name = "usb_generic_onboard",
+		.of_match_table = usb_generic_onboard_dt_ids,
+	 },
+};
+
+static int __init usb_generic_onboard_init(void)
+{
+	return platform_driver_register(&usb_generic_onboard_driver);
+}
+subsys_initcall(usb_generic_onboard_init);
+
+static void __exit usb_generic_onboard_exit(void)
+{
+	platform_driver_unregister(&usb_generic_onboard_driver);
+}
+module_exit(usb_generic_onboard_exit);
+
+MODULE_AUTHOR("Peter Chen <peter.chen@freescale.com>");
+MODULE_DESCRIPTION("Generic Onboard USB HUB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/firmware/am335x-bone-scale-data.bin b/firmware/am335x-bone-scale-data.bin
new file mode 100644
index 0000000000000000000000000000000000000000..296903ec2c0fe1518566039b601b445c270e1c98
GIT binary patch
literal 72
ocmd-HXHa4=VN&7FWl|AfLZWk+R0P|Ad@v1H!2wkPqES=;07<$Dx&QzG

literal 0
HcmV?d00001

diff --git a/firmware/am335x-evm-scale-data.bin b/firmware/am335x-evm-scale-data.bin
new file mode 100644
index 0000000000000000000000000000000000000000..7e18ce7208b7d0d669dd6e199a7969bf98a74ee8
GIT binary patch
literal 16
Tcmd-HXJBJ6VbWEV2b0<W4kZD^

literal 0
HcmV?d00001

diff --git a/firmware/am43x-evm-scale-data.bin b/firmware/am43x-evm-scale-data.bin
new file mode 100644
index 0000000000000000000000000000000000000000..805338a032540ab0f1cab3b44693768bd2dab018
GIT binary patch
literal 40
gcmd-HXAojAVNwyuW>OLB0@CSBDpGB5k(n?N0C+M6fdBvi

literal 0
HcmV?d00001

diff --git a/fs/dcache.c b/fs/dcache.c
index 90b6689..abc87dc 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -579,6 +579,7 @@ static struct dentry *dentry_kill(struct dentry *dentry)
 
 failed:
 	spin_unlock(&dentry->d_lock);
+	cpu_chill();
 	return dentry; /* try again with same dentry */
 }
 
@@ -748,14 +749,10 @@ static inline bool fast_dput(struct dentry *dentry)
  */
 void dput(struct dentry *dentry)
 {
-	struct dentry *parent;
-
 	if (unlikely(!dentry))
 		return;
 
 repeat:
-	might_sleep();
-
 	rcu_read_lock();
 	if (likely(fast_dput(dentry))) {
 		rcu_read_unlock();
@@ -786,20 +783,9 @@ repeat:
 	return;
 
 kill_it:
-	parent = dentry_kill(dentry);
-	if (parent) {
-		int r;
-
-		if (parent == dentry) {
-			/* the task with the highest priority won't schedule */
-			r = cond_resched();
-			if (!r)
-				cpu_chill();
-		} else {
-			dentry = parent;
-		}
+	dentry = dentry_kill(dentry);
+	if (dentry)
 		goto repeat;
-	}
 }
 EXPORT_SYMBOL(dput);
 
diff --git b/include/dt-bindings/board/am335x-bbw-bbb-base.h b/include/dt-bindings/board/am335x-bbw-bbb-base.h
new file mode 100644
index 0000000..35f6d57
--- /dev/null
+++ b/include/dt-bindings/board/am335x-bbw-bbb-base.h
@@ -0,0 +1,103 @@
+/*
+ * This header provides constants for bbw/bbb pinctrl bindings.
+ *
+ * Copyright (C) 2014 Robert Nelson <robertcnelson@gmail.com>
+ *
+ * Numbers Based on: https://github.com/derekmolloy/boneDeviceTree/tree/master/docs
+ */
+
+#ifndef _DT_BINDINGS_BOARD_AM335X_BBW_BBB_BASE_H
+#define _DT_BINDINGS_BOARD_AM335X_BBW_BBB_BASE_H
+
+#define BONE_P8_03 0x018
+#define BONE_P8_04 0x01C
+
+#define BONE_P8_05 0x008
+#define BONE_P8_06 0x00C
+#define BONE_P8_07 0x090
+#define BONE_P8_08 0x094
+
+#define BONE_P8_09 0x09C
+#define BONE_P8_10 0x098
+#define BONE_P8_11 0x034
+#define BONE_P8_12 0x030
+
+#define BONE_P8_13 0x024
+#define BONE_P8_14 0x028
+#define BONE_P8_15 0x03C
+#define BONE_P8_16 0x038
+
+#define BONE_P8_17 0x02C
+#define BONE_P8_18 0x08C
+#define BONE_P8_19 0x020
+#define BONE_P8_20 0x084
+
+#define BONE_P8_21 0x080
+#define BONE_P8_22 0x014
+#define BONE_P8_23 0x010
+#define BONE_P8_24 0x004
+
+#define BONE_P8_25 0x000
+#define BONE_P8_26 0x07C
+#define BONE_P8_27 0x0E0
+#define BONE_P8_28 0x0E8
+
+#define BONE_P8_29 0x0E4
+#define BONE_P8_30 0x0EC
+#define BONE_P8_31 0x0D8
+#define BONE_P8_32 0x0DC
+
+#define BONE_P8_33 0x0D4
+#define BONE_P8_34 0x0CC
+#define BONE_P8_35 0x0D0
+#define BONE_P8_36 0x0C8
+
+#define BONE_P8_37 0x0C0
+#define BONE_P8_38 0x0C4
+#define BONE_P8_39 0x0B8
+#define BONE_P8_40 0x0BC
+
+#define BONE_P8_41 0x0B0
+#define BONE_P8_42 0x0B4
+#define BONE_P8_43 0x0A8
+#define BONE_P8_44 0x0AC
+
+#define BONE_P8_45 0x0A0
+#define BONE_P8_46 0x0A4
+
+#define BONE_P9_11 0x070
+#define BONE_P9_12 0x078
+
+#define BONE_P9_13 0x074
+#define BONE_P9_14 0x048
+#define BONE_P9_15 0x040
+#define BONE_P9_16 0x04C
+
+#define BONE_P9_17 0x15C
+#define BONE_P9_18 0x158
+#define BONE_P9_19 0x17C
+#define BONE_P9_20 0x178
+
+#define BONE_P9_21 0x154
+#define BONE_P9_22 0x150
+#define BONE_P9_23 0x044
+#define BONE_P9_24 0x184
+
+#define BONE_P9_25 0x1AC
+#define BONE_P9_26 0x180
+#define BONE_P9_27 0x1A4
+#define BONE_P9_28 0x19C
+
+#define BONE_P9_29 0x194
+#define BONE_P9_30 0x198
+#define BONE_P9_31 0x190
+
+/* Shared P21 of P11 */
+#define BONE_P9_41A 0x1B4
+#define BONE_P9_41B 0x1A8
+
+/* Shared P22 of P11 */
+#define BONE_P9_42A 0x164
+#define BONE_P9_42B 0x1A0
+
+#endif
diff --git a/include/dt-bindings/clock/exynos3250.h b/include/dt-bindings/clock/exynos3250.h
index 63d01c1..c796ff0 100644
--- a/include/dt-bindings/clock/exynos3250.h
+++ b/include/dt-bindings/clock/exynos3250.h
@@ -79,6 +79,8 @@
 #define CLK_MOUT_CORE			58
 #define CLK_MOUT_APLL			59
 #define CLK_MOUT_ACLK_266_SUB		60
+#define CLK_MOUT_UART2			61
+#define CLK_MOUT_MMC2			62
 
 /* Dividers */
 #define CLK_DIV_GPL			64
@@ -127,6 +129,9 @@
 #define CLK_DIV_CORE			107
 #define CLK_DIV_HPM			108
 #define CLK_DIV_COPY			109
+#define CLK_DIV_UART2			110
+#define CLK_DIV_MMC2_PRE		111
+#define CLK_DIV_MMC2			112
 
 /* Gates */
 #define CLK_ASYNC_G3D			128
@@ -223,6 +228,8 @@
 #define CLK_BLOCK_MFC			219
 #define CLK_BLOCK_CAM			220
 #define CLK_SMIES			221
+#define CLK_UART2			222
+#define CLK_SDMMC2			223
 
 /* Special clocks */
 #define CLK_SCLK_JPEG			224
@@ -249,12 +256,14 @@
 #define CLK_SCLK_SPI0			245
 #define CLK_SCLK_UART1			246
 #define CLK_SCLK_UART0			247
+#define CLK_SCLK_UART2			248
+#define CLK_SCLK_MMC2			249
 
 /*
  * Total number of clocks of main CMU.
  * NOTE: Must be equal to last clock ID increased by one.
  */
-#define CLK_NR_CLKS			248
+#define CLK_NR_CLKS			250
 
 /*
  * CMU DMC
diff --git b/include/dt-bindings/iio/adi,ad5592r.h b/include/dt-bindings/iio/adi,ad5592r.h
new file mode 100644
index 0000000..c48aca1
--- /dev/null
+++ b/include/dt-bindings/iio/adi,ad5592r.h
@@ -0,0 +1,16 @@
+
+#ifndef _DT_BINDINGS_ADI_AD5592R_H
+#define _DT_BINDINGS_ADI_AD5592R_H
+
+#define CH_MODE_UNUSED			0
+#define CH_MODE_ADC			1
+#define CH_MODE_DAC			2
+#define CH_MODE_DAC_AND_ADC		3
+#define CH_MODE_GPIO			8
+
+#define CH_OFFSTATE_PULLDOWN		0
+#define CH_OFFSTATE_OUT_LOW		1
+#define CH_OFFSTATE_OUT_HIGH		2
+#define CH_OFFSTATE_OUT_TRISTATE	3
+
+#endif /* _DT_BINDINGS_ADI_AD5592R_H */
diff --git a/include/dt-bindings/pinctrl/dra.h b/include/dt-bindings/pinctrl/dra.h
index 5c75e80..5a60e3b 100644
--- a/include/dt-bindings/pinctrl/dra.h
+++ b/include/dt-bindings/pinctrl/dra.h
@@ -50,6 +50,8 @@
 
 #define MODE_SELECT		(1 << 8)
 
+#define MANUAL_MODE		MODE_SELECT
+
 #define PULL_ENA		(0 << 16)
 #define PULL_DIS		(1 << 16)
 #define PULL_UP			(1 << 17)
@@ -73,5 +75,9 @@
  */
 #define DRA7XX_CORE_IOPAD(pa, val)	(((pa) & 0xffff) - 0x3400) (val)
 
+/* DRA7 IODELAY configuration parameters */
+#define A_DELAY(val)		((val) & 0xFFFF)
+#define G_DELAY(val)		(((val) & 0xFFFF) << 16)
+
 #endif
 
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 72cb210..dea12a6 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -713,7 +713,6 @@ static inline void __ftrace_enabled_restore(int enabled)
 #define CALLER_ADDR5 ((unsigned long)ftrace_return_address(5))
 #define CALLER_ADDR6 ((unsigned long)ftrace_return_address(6))
 
-#ifdef CONFIG_USING_GET_LOCK_PARENT_IP
 static inline unsigned long get_lock_parent_ip(void)
 {
 	unsigned long addr = CALLER_ADDR0;
@@ -725,7 +724,6 @@ static inline unsigned long get_lock_parent_ip(void)
 		return addr;
 	return CALLER_ADDR2;
 }
-#endif
 
 #ifdef CONFIG_IRQSOFF_TRACER
   extern void time_hardirqs_on(unsigned long a0, unsigned long a1);
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
index b5f9a00..d4c1d12 100644
--- a/include/linux/i2c-mux.h
+++ b/include/linux/i2c-mux.h
@@ -27,22 +27,49 @@
 
 #ifdef __KERNEL__
 
+#include <linux/bitops.h>
+
+struct i2c_mux_core {
+	struct i2c_adapter *parent;
+	struct device *dev;
+	bool mux_locked;
+
+	void *priv;
+
+	int (*select)(struct i2c_mux_core *, u32 chan_id);
+	int (*deselect)(struct i2c_mux_core *, u32 chan_id);
+
+	int num_adapters;
+	int max_adapters;
+	struct i2c_adapter *adapter[0];
+};
+
+struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
+				   struct device *dev, int max_adapters,
+				   int sizeof_priv, u32 flags,
+				   int (*select)(struct i2c_mux_core *, u32),
+				   int (*deselect)(struct i2c_mux_core *, u32));
+
+/* flags for i2c_mux_alloc */
+#define I2C_MUX_LOCKED BIT(0)
+
+static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
+{
+	return muxc->priv;
+}
+
+struct i2c_adapter *i2c_root_adapter(struct device *dev);
+
 /*
- * Called to create a i2c bus on a multiplexed bus segment.
- * The mux_dev and chan_id parameters are passed to the select
- * and deselect callback functions to perform hardware-specific
- * mux control.
+ * Called to create an i2c bus on a multiplexed bus segment.
+ * The chan_id parameter is passed to the select and deselect
+ * callback functions to perform hardware-specific mux control.
  */
-struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
-				struct device *mux_dev,
-				void *mux_priv, u32 force_nr, u32 chan_id,
-				unsigned int class,
-				int (*select) (struct i2c_adapter *,
-					       void *mux_dev, u32 chan_id),
-				int (*deselect) (struct i2c_adapter *,
-						 void *mux_dev, u32 chan_id));
-
-void i2c_del_mux_adapter(struct i2c_adapter *adap);
+int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
+			u32 force_nr, u32 chan_id,
+			unsigned int class);
+
+void i2c_mux_del_adapters(struct i2c_mux_core *muxc);
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 200cf13..96a25ae 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -524,6 +524,7 @@ struct i2c_adapter {
 
 	/* data fields that are valid for all devices	*/
 	struct rt_mutex bus_lock;
+	struct rt_mutex mux_lock;
 
 	int timeout;			/* in jiffies */
 	int retries;
@@ -538,6 +539,10 @@ struct i2c_adapter {
 
 	struct i2c_bus_recovery_info *bus_recovery_info;
 	const struct i2c_adapter_quirks *quirks;
+
+	void (*lock_bus)(struct i2c_adapter *, unsigned int flags);
+	int (*trylock_bus)(struct i2c_adapter *, unsigned int flags);
+	void (*unlock_bus)(struct i2c_adapter *, unsigned int flags);
 };
 #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 
@@ -567,8 +572,44 @@ i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
 int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *));
 
 /* Adapter locking functions, exported for shared pin cases */
-void i2c_lock_adapter(struct i2c_adapter *);
-void i2c_unlock_adapter(struct i2c_adapter *);
+#define I2C_LOCK_ROOT_ADAPTER BIT(0)
+#define I2C_LOCK_SEGMENT      BIT(1)
+
+/**
+ * i2c_lock_bus - Get exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT
+ *	locks only this branch in the adapter tree
+ */
+static inline void
+i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+	adapter->lock_bus(adapter, flags);
+}
+
+/**
+ * i2c_unlock_bus - Release exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ * @flags: I2C_LOCK_ROOT_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT
+ *	unlocks only this branch in the adapter tree
+ */
+static inline void
+i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+	adapter->unlock_bus(adapter, flags);
+}
+
+static inline void
+i2c_lock_adapter(struct i2c_adapter *adapter)
+{
+	i2c_lock_bus(adapter, I2C_LOCK_ROOT_ADAPTER);
+}
+
+static inline void
+i2c_unlock_adapter(struct i2c_adapter *adapter)
+{
+	i2c_unlock_bus(adapter, I2C_LOCK_ROOT_ADAPTER);
+}
 
 /*flags for the client struct: */
 #define I2C_CLIENT_PEC		0x04	/* Use Packet Error Checking */
@@ -654,6 +695,11 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
 	return adap->nr;
 }
 
+static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
+{
+	return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0);
+}
+
 /**
  * module_i2c_driver() - Helper macro for registering a modular I2C driver
  * @__i2c_driver: i2c_driver struct
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index 2ec3ad5..70a5164 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -83,10 +83,12 @@ struct iio_buffer_access_funcs {
  * @access:		[DRIVER] buffer access functions associated with the
  *			implementation.
  * @scan_el_dev_attr_list:[INTERN] list of scan element related attributes.
+ * @buffer_group:	[INTERN] attributes of the buffer group
  * @scan_el_group:	[DRIVER] attribute group for those attributes not
  *			created from the iio_chan_info array.
  * @pollq:		[INTERN] wait queue to allow for polling on the buffer.
  * @stufftoread:	[INTERN] flag to indicate new data.
+ * @attrs:		[INTERN] standard attributes of the buffer
  * @demux_list:		[INTERN] list of operations required to demux the scan.
  * @demux_bounce:	[INTERN] buffer for doing gather from incoming scan.
  * @buffer_list:	[INTERN] entry in the devices list of current buffers.
diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h
index 6670c3d..228bd44 100644
--- a/include/linux/iio/common/st_sensors.h
+++ b/include/linux/iio/common/st_sensors.h
@@ -37,6 +37,7 @@
 #define ST_SENSORS_DEFAULT_AXIS_ADDR		0x20
 #define ST_SENSORS_DEFAULT_AXIS_MASK		0x07
 #define ST_SENSORS_DEFAULT_AXIS_N_BIT		3
+#define ST_SENSORS_DEFAULT_STAT_ADDR		0x27
 
 #define ST_SENSORS_MAX_NAME			17
 #define ST_SENSORS_MAX_4WAI			7
@@ -121,6 +122,9 @@ struct st_sensor_bdu {
  * @mask_int2: mask to enable/disable IRQ on INT2 pin.
  * @addr_ihl: address to enable/disable active low on the INT lines.
  * @mask_ihl: mask to enable/disable active low on the INT lines.
+ * @addr_od: address to enable/disable Open Drain on the INT lines.
+ * @mask_od: mask to enable/disable Open Drain on the INT lines.
+ * @addr_stat_drdy: address to read status of DRDY (data ready) interrupt
  * struct ig1 - represents the Interrupt Generator 1 of sensors.
  * @en_addr: address of the enable ig1 register.
  * @en_mask: mask to write the on/off value for enable.
@@ -131,6 +135,9 @@ struct st_sensor_data_ready_irq {
 	u8 mask_int2;
 	u8 addr_ihl;
 	u8 mask_ihl;
+	u8 addr_od;
+	u8 mask_od;
+	u8 addr_stat_drdy;
 	struct {
 		u8 en_addr;
 		u8 en_mask;
@@ -212,9 +219,13 @@ struct st_sensor_settings {
  * @odr: Output data rate of the sensor [Hz].
  * num_data_channels: Number of data channels used in buffer.
  * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
+ * @int_pin_open_drain: Set the interrupt/DRDY to open drain.
  * @get_irq_data_ready: Function to get the IRQ used for data ready signal.
  * @tf: Transfer function structure used by I/O operations.
  * @tb: Transfer buffers and mutex used by I/O operations.
+ * @edge_irq: the IRQ triggers on edges and need special handling.
+ * @hw_irq_trigger: if we're using the hardware interrupt on the sensor.
+ * @hw_timestamp: Latest timestamp from the interrupt handler, when in use.
  */
 struct st_sensor_data {
 	struct device *dev;
@@ -233,17 +244,20 @@ struct st_sensor_data {
 	unsigned int num_data_channels;
 
 	u8 drdy_int_pin;
+	bool int_pin_open_drain;
 
 	unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev);
 
 	const struct st_sensor_transfer_function *tf;
 	struct st_sensor_transfer_buffer tb;
+
+	bool edge_irq;
+	bool hw_irq_trigger;
+	s64 hw_timestamp;
 };
 
 #ifdef CONFIG_IIO_BUFFER
 irqreturn_t st_sensors_trigger_handler(int irq, void *p);
-
-int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf);
 #endif
 
 #ifdef CONFIG_IIO_TRIGGER
@@ -251,7 +265,8 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 				const struct iio_trigger_ops *trigger_ops);
 
 void st_sensors_deallocate_trigger(struct iio_dev *indio_dev);
-
+int st_sensors_validate_device(struct iio_trigger *trig,
+			       struct iio_dev *indio_dev);
 #else
 static inline int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 				const struct iio_trigger_ops *trigger_ops)
@@ -262,6 +277,7 @@ static inline void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
 {
 	return;
 }
+#define st_sensors_validate_device NULL
 #endif
 
 int st_sensors_init_sensor(struct iio_dev *indio_dev,
@@ -271,7 +287,7 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable);
 
 int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable);
 
-void st_sensors_power_enable(struct iio_dev *indio_dev);
+int st_sensors_power_enable(struct iio_dev *indio_dev);
 
 void st_sensors_power_disable(struct iio_dev *indio_dev);
 
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index fad5867..3d672f7 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -49,6 +49,33 @@ struct iio_channel *iio_channel_get(struct device *dev,
 void iio_channel_release(struct iio_channel *chan);
 
 /**
+ * devm_iio_channel_get() - Resource managed version of iio_channel_get().
+ * @dev:		Pointer to consumer device. Device name must match
+ *			the name of the device as provided in the iio_map
+ *			with which the desired provider to consumer mapping
+ *			was registered.
+ * @consumer_channel:	Unique name to identify the channel on the consumer
+ *			side. This typically describes the channels use within
+ *			the consumer. E.g. 'battery_voltage'
+ *
+ * Returns a pointer to negative errno if it is not able to get the iio channel
+ * otherwise returns valid pointer for iio channel.
+ *
+ * The allocated iio channel is automatically released when the device is
+ * unbound.
+ */
+struct iio_channel *devm_iio_channel_get(struct device *dev,
+					 const char *consumer_channel);
+/**
+ * devm_iio_channel_release() - Resource managed version of
+ *				iio_channel_release().
+ * @dev:		Pointer to consumer device for which resource
+ *			is allocared.
+ * @chan:		The channel to be released.
+ */
+void devm_iio_channel_release(struct device *dev, struct iio_channel *chan);
+
+/**
  * iio_channel_get_all() - get all channels associated with a client
  * @dev:		Pointer to consumer device.
  *
@@ -65,6 +92,32 @@ struct iio_channel *iio_channel_get_all(struct device *dev);
  */
 void iio_channel_release_all(struct iio_channel *chan);
 
+/**
+ * devm_iio_channel_get_all() - Resource managed version of
+ *				iio_channel_get_all().
+ * @dev: Pointer to consumer device.
+ *
+ * Returns a pointer to negative errno if it is not able to get the iio channel
+ * otherwise returns an array of iio_channel structures terminated with one with
+ * null iio_dev pointer.
+ *
+ * This function is used by fairly generic consumers to get all the
+ * channels registered as having this consumer.
+ *
+ * The allocated iio channels are automatically released when the device is
+ * unbounded.
+ */
+struct iio_channel *devm_iio_channel_get_all(struct device *dev);
+
+/**
+ * devm_iio_channel_release_all() - Resource managed version of
+ *				    iio_channel_release_all().
+ * @dev:		Pointer to consumer device for which resource
+ *			is allocared.
+ * @chan:		Array channel to be released.
+ */
+void devm_iio_channel_release_all(struct device *dev, struct iio_channel *chan);
+
 struct iio_cb_buffer;
 /**
  * iio_channel_get_all_cb() - register callback for triggered capture
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index b2b1677..854e2da 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -148,6 +148,37 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
 }
 
 /**
+ * struct iio_mount_matrix - iio mounting matrix
+ * @rotation: 3 dimensional space rotation matrix defining sensor alignment with
+ *            main hardware
+ */
+struct iio_mount_matrix {
+	const char *rotation[9];
+};
+
+ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv,
+			      const struct iio_chan_spec *chan, char *buf);
+int of_iio_read_mount_matrix(const struct device *dev, const char *propname,
+			     struct iio_mount_matrix *matrix);
+
+typedef const struct iio_mount_matrix *
+	(iio_get_mount_matrix_t)(const struct iio_dev *indio_dev,
+				 const struct iio_chan_spec *chan);
+
+/**
+ * IIO_MOUNT_MATRIX() - Initialize mount matrix extended channel attribute
+ * @_shared:	Whether the attribute is shared between all channels
+ * @_get:	Pointer to an iio_get_mount_matrix_t accessor
+ */
+#define IIO_MOUNT_MATRIX(_shared, _get) \
+{ \
+	.name = "mount_matrix", \
+	.shared = (_shared), \
+	.read = iio_show_mount_matrix, \
+	.private = (uintptr_t)(_get), \
+}
+
+/**
  * struct iio_event_spec - specification for a channel event
  * @type:		    Type of the event
  * @dir:		    Direction of the event
@@ -281,13 +312,8 @@ static inline bool iio_channel_has_info(const struct iio_chan_spec *chan,
 		},							\
 }
 
-/**
- * iio_get_time_ns() - utility function to get a time stamp for events etc
- **/
-static inline s64 iio_get_time_ns(void)
-{
-	return ktime_get_real_ns();
-}
+s64 iio_get_time_ns(const struct iio_dev *indio_dev);
+unsigned int iio_get_time_res(const struct iio_dev *indio_dev);
 
 /* Device operating modes */
 #define INDIO_DIRECT_MODE		0x01
@@ -466,6 +492,7 @@ struct iio_buffer_setup_ops {
  * @chan_attr_group:	[INTERN] group for all attrs in base directory
  * @name:		[DRIVER] name of the device.
  * @info:		[DRIVER] callbacks and constant info from driver
+ * @clock_id:		[INTERN] timestamping clock posix identifier
  * @info_exist_lock:	[INTERN] lock to prevent use during removal
  * @setup_ops:		[DRIVER] callbacks to call before and after buffer
  *			enable/disable
@@ -506,6 +533,7 @@ struct iio_dev {
 	struct attribute_group		chan_attr_group;
 	const char			*name;
 	const struct iio_info		*info;
+	clockid_t			clock_id;
 	struct mutex			info_exist_lock;
 	const struct iio_buffer_setup_ops	*setup_ops;
 	struct cdev			chrdev;
@@ -527,12 +555,14 @@ void iio_device_unregister(struct iio_dev *indio_dev);
 int devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev);
 void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev);
 int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp);
+int iio_device_claim_direct_mode(struct iio_dev *indio_dev);
+void iio_device_release_direct_mode(struct iio_dev *indio_dev);
 
 extern struct bus_type iio_bus_type;
 
 /**
  * iio_device_put() - reference counted deallocation of struct device
- * @indio_dev: 		IIO device structure containing the device
+ * @indio_dev: IIO device structure containing the device
  **/
 static inline void iio_device_put(struct iio_dev *indio_dev)
 {
@@ -541,6 +571,15 @@ static inline void iio_device_put(struct iio_dev *indio_dev)
 }
 
 /**
+ * iio_device_get_clock() - Retrieve current timestamping clock for the device
+ * @indio_dev: IIO device structure containing the device
+ */
+static inline clockid_t iio_device_get_clock(const struct iio_dev *indio_dev)
+{
+	return indio_dev->clock_id;
+}
+
+/**
  * dev_to_iio_dev() - Get IIO device struct from a device struct
  * @dev: 		The device embedded in the IIO device
  *
diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
index fa2d01e..360da7d 100644
--- a/include/linux/iio/imu/adis.h
+++ b/include/linux/iio/imu/adis.h
@@ -41,6 +41,7 @@ struct adis_data {
 	unsigned int diag_stat_reg;
 
 	unsigned int self_test_mask;
+	bool self_test_no_autoclear;
 	unsigned int startup_delay;
 
 	const char * const *status_error_msgs;
diff --git b/include/linux/iio/magnetometer/ak8975.h b/include/linux/iio/magnetometer/ak8975.h
new file mode 100644
index 0000000..c840095
--- /dev/null
+++ b/include/linux/iio/magnetometer/ak8975.h
@@ -0,0 +1,16 @@
+#ifndef __IIO_MAGNETOMETER_AK8975_H__
+#define __IIO_MAGNETOMETER_AK8975_H__
+
+#include <linux/iio/iio.h>
+
+/**
+ * struct ak8975_platform_data - AK8975 magnetometer driver platform data
+ * @eoc_gpio:    data ready event gpio
+ * @orientation: mounting matrix relative to main hardware
+ */
+struct ak8975_platform_data {
+	int                     eoc_gpio;
+	struct iio_mount_matrix orientation;
+};
+
+#endif
diff --git b/include/linux/iio/sw_device.h b/include/linux/iio/sw_device.h
new file mode 100644
index 0000000..23ca415
--- /dev/null
+++ b/include/linux/iio/sw_device.h
@@ -0,0 +1,70 @@
+/*
+ * Industrial I/O software device interface
+ *
+ * Copyright (c) 2016 Intel Corporation
+ *
+ * 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 __IIO_SW_DEVICE
+#define __IIO_SW_DEVICE
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/configfs.h>
+
+#define module_iio_sw_device_driver(__iio_sw_device_type) \
+	module_driver(__iio_sw_device_type, iio_register_sw_device_type, \
+		      iio_unregister_sw_device_type)
+
+struct iio_sw_device_ops;
+
+struct iio_sw_device_type {
+	const char *name;
+	struct module *owner;
+	const struct iio_sw_device_ops *ops;
+	struct list_head list;
+	struct config_group *group;
+};
+
+struct iio_sw_device {
+	struct iio_dev *device;
+	struct iio_sw_device_type *device_type;
+	struct config_group group;
+};
+
+struct iio_sw_device_ops {
+	struct iio_sw_device* (*probe)(const char *);
+	int (*remove)(struct iio_sw_device *);
+};
+
+static inline
+struct iio_sw_device *to_iio_sw_device(struct config_item *item)
+{
+	return container_of(to_config_group(item), struct iio_sw_device,
+			    group);
+}
+
+int iio_register_sw_device_type(struct iio_sw_device_type *dt);
+void iio_unregister_sw_device_type(struct iio_sw_device_type *dt);
+
+struct iio_sw_device *iio_sw_device_create(const char *, const char *);
+void iio_sw_device_destroy(struct iio_sw_device *);
+
+int iio_sw_device_type_configfs_register(struct iio_sw_device_type *dt);
+void iio_sw_device_type_configfs_unregister(struct iio_sw_device_type *dt);
+
+static inline
+void iio_swd_group_init_type_name(struct iio_sw_device *d,
+				  const char *name,
+				  struct config_item_type *type)
+{
+#ifdef CONFIG_CONFIGFS_FS
+	config_group_init_type_name(&d->group, name, type);
+#endif
+}
+
+#endif /* __IIO_SW_DEVICE */
diff --git a/include/linux/input/touchscreen.h b/include/linux/input/touchscreen.h
index c91e137..09d22cc 100644
--- a/include/linux/input/touchscreen.h
+++ b/include/linux/input/touchscreen.h
@@ -10,7 +10,26 @@
 #define _TOUCHSCREEN_H
 
 struct input_dev;
+struct input_mt_pos;
 
-void touchscreen_parse_properties(struct input_dev *dev, bool multitouch);
+struct touchscreen_properties {
+	unsigned int max_x;
+	unsigned int max_y;
+	bool invert_x;
+	bool invert_y;
+	bool swap_x_y;
+};
+
+void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
+				  struct touchscreen_properties *prop);
+
+void touchscreen_set_mt_pos(struct input_mt_pos *pos,
+			    const struct touchscreen_properties *prop,
+			    unsigned int x, unsigned int y);
+
+void touchscreen_report_pos(struct input_dev *input,
+			    const struct touchscreen_properties *prop,
+			    unsigned int x, unsigned int y,
+			    bool multitouch);
 
 #endif
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 4d06168..1191d79 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -97,11 +97,6 @@ enum mem_cgroup_events_target {
 #define MEM_CGROUP_ID_SHIFT	16
 #define MEM_CGROUP_ID_MAX	USHRT_MAX
 
-struct mem_cgroup_id {
-	int id;
-	atomic_t ref;
-};
-
 struct mem_cgroup_stat_cpu {
 	long count[MEMCG_NR_STAT];
 	unsigned long events[MEMCG_NR_EVENTS];
@@ -177,9 +172,6 @@ enum memcg_kmem_state {
 struct mem_cgroup {
 	struct cgroup_subsys_state css;
 
-	/* Private memcg ID. Used to ID objects that outlive the cgroup */
-	struct mem_cgroup_id id;
-
 	/* Accounted resources */
 	struct page_counter memory;
 	struct page_counter swap;
@@ -338,9 +330,22 @@ static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)
 	if (mem_cgroup_disabled())
 		return 0;
 
-	return memcg->id.id;
+	return memcg->css.id;
+}
+
+/**
+ * mem_cgroup_from_id - look up a memcg from an id
+ * @id: the id to look up
+ *
+ * Caller must hold rcu_read_lock() and use css_tryget() as necessary.
+ */
+static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
+{
+	struct cgroup_subsys_state *css;
+
+	css = css_from_id(id, &memory_cgrp_subsys);
+	return mem_cgroup_from_css(css);
 }
-struct mem_cgroup *mem_cgroup_from_id(unsigned short id);
 
 /**
  * parent_mem_cgroup - find the accounting parent of a memcg
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
index ac7fba4..05d24a6 100644
--- a/include/linux/mfd/tps65217.h
+++ b/include/linux/mfd/tps65217.h
@@ -257,6 +257,11 @@ struct tps65217 {
 	unsigned long id;
 	struct regulator_desc desc[TPS65217_NUM_REGULATOR];
 	struct regmap *regmap;
+
+	/* Power button and IRQ handling */
+	int irq_gpio;	/* might not be set */
+	int irq;
+	struct input_dev *pwr_but;
 };
 
 static inline struct tps65217 *dev_to_tps65217(struct device *dev)
diff --git a/include/linux/of.h b/include/linux/of.h
index 3175803..927c3f9 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -25,6 +25,7 @@
 #include <linux/notifier.h>
 #include <linux/property.h>
 #include <linux/list.h>
+#include <linux/rhashtable.h>
 
 #include <asm/byteorder.h>
 #include <asm/errno.h>
@@ -52,6 +53,7 @@ struct device_node {
 	phandle phandle;
 	const char *full_name;
 	struct fwnode_handle fwnode;
+	struct rhash_head ht_node;
 
 	struct	property *properties;
 	struct	property *deadprops;	/* removed properties */
@@ -1037,6 +1039,27 @@ static inline int of_changeset_update_property(struct of_changeset *ocs,
 {
 	return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop);
 }
+
+struct device_node *of_changeset_create_device_nodev(
+	struct of_changeset *ocs, struct device_node *parent,
+	const char *fmt, va_list vargs);
+__printf(3, 4) struct device_node *of_changeset_create_device_node(
+	struct of_changeset *ocs, struct device_node *parent,
+	const char *fmt, ...);
+int of_changeset_add_property_copy(struct of_changeset *ocs,
+	struct device_node *np, const char *name,
+	const void *value, int length);
+int of_changeset_add_property_string(struct of_changeset *ocs,
+	struct device_node *np, const char *name, const char *str);
+__printf(4, 5) int of_changeset_add_property_stringf(struct of_changeset *ocs,
+		struct device_node *np, const char *name, const char *fmt, ...);
+int of_changeset_add_property_string_list(struct of_changeset *ocs,
+	struct device_node *np, const char *name, const char **strs, int count);
+int of_changeset_add_property_u32(struct of_changeset *ocs,
+	struct device_node *np, const char *name, u32 val);
+int of_changeset_add_property_bool(struct of_changeset *ocs,
+	struct device_node *np, const char *name);
+
 #else /* CONFIG_OF_DYNAMIC */
 static inline int of_reconfig_notifier_register(struct notifier_block *nb)
 {
@@ -1056,6 +1079,59 @@ static inline int of_reconfig_get_state_change(unsigned long action,
 {
 	return -EINVAL;
 }
+
+static inline int of_changeset_create_device_node(struct of_changeset *ocs,
+	struct device_node *parent, const char *fmt, ...)
+{
+	return -EINVAL;
+}
+
+int of_changeset_add_property_copy(struct of_changeset *ocs,
+	struct device_node *np, const char *name,
+	const void *value, int length)
+{
+	return -EINVAL;
+}
+
+int of_changeset_add_property_string(struct of_changeset *ocs,
+	struct device_node *np, const char *name, const char *str)
+{
+	return -EINVAL;
+}
+
+static inline struct device_node *of_changeset_create_device_nodev(
+	struct of_changeset *ocs, struct device_node *parent,
+	const char *fmt, va_list vargs)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline __printf(4, 5) struct device_node *
+	of_changeset_add_property_stringf(
+		struct of_changeset *ocs, struct device_node *np,
+		const char *name, const char *fmt, ...)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int of_changeset_add_property_string_list(
+	struct of_changeset *ocs, struct device_node *np, const char *name,
+	const char **strs, int count)
+{
+	return -EINVAL;
+}
+
+static inline int of_changeset_add_property_u32(struct of_changeset *ocs,
+	struct device_node *np, const char *name, u32 val)
+{
+	return -EINVAL;
+}
+
+static inline int of_changeset_add_property_bool(struct of_changeset *ocs,
+	struct device_node *np, const char *name)
+{
+	return -EINVAL;
+}
 #endif /* CONFIG_OF_DYNAMIC */
 
 /* CONFIG_OF_RESOLVE api */
@@ -1083,6 +1159,10 @@ int of_overlay_create(struct device_node *tree);
 int of_overlay_destroy(int id);
 int of_overlay_destroy_all(void);
 
+int of_overlay_create_indirect(struct device_node *tree, const char *id);
+int of_overlay_create_target_root(struct device_node *tree,
+		struct device_node *target_root);
+
 #else
 
 static inline int of_overlay_create(struct device_node *tree)
@@ -1100,6 +1180,18 @@ static inline int of_overlay_destroy_all(void)
 	return -ENOTSUPP;
 }
 
+static inline int of_overlay_create_indirect(struct device_node *tree,
+		const char *id)
+{
+	return -ENOTSUPP;
+}
+
+static inline int of_overlay_create_target_root(struct device_node *tree,
+		struct device_node *target_root)
+{
+	return -ENOTSUPP;
+}
+
 #endif
 
 #endif /* _LINUX_OF_H */
diff --git a/include/linux/platform_data/st_sensors_pdata.h b/include/linux/platform_data/st_sensors_pdata.h
index 7538391..79b0e4c 100644
--- a/include/linux/platform_data/st_sensors_pdata.h
+++ b/include/linux/platform_data/st_sensors_pdata.h
@@ -16,9 +16,11 @@
  * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
  *	Available only for accelerometer and pressure sensors.
  *	Accelerometer DRDY on LSM330 available only on pin 1 (see datasheet).
+ * @open_drain: set the interrupt line to be open drain if possible.
  */
 struct st_sensors_platform_data {
 	u8 drdy_int_pin;
+	bool open_drain;
 };
 
 #endif /* ST_SENSORS_PDATA_H */
diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h
index c077617..22e5e58 100644
--- a/include/uapi/linux/iio/types.h
+++ b/include/uapi/linux/iio/types.h
@@ -38,6 +38,8 @@ enum iio_chan_type {
 	IIO_CONCENTRATION,
 	IIO_RESISTANCE,
 	IIO_PH,
+	IIO_UVINDEX,
+	IIO_ELECTRICALCONDUCTIVITY,
 };
 
 enum iio_modifier {
@@ -77,6 +79,7 @@ enum iio_modifier {
 	IIO_MOD_Q,
 	IIO_MOD_CO2,
 	IIO_MOD_VOC,
+	IIO_MOD_LIGHT_UV,
 };
 
 enum iio_event_type {
diff --git a/include/video/mipi_display.h b/include/video/mipi_display.h
index ddcc8ca..19aa65a 100644
--- a/include/video/mipi_display.h
+++ b/include/video/mipi_display.h
@@ -115,6 +115,14 @@ enum {
 	MIPI_DCS_READ_MEMORY_CONTINUE	= 0x3E,
 	MIPI_DCS_SET_TEAR_SCANLINE	= 0x44,
 	MIPI_DCS_GET_SCANLINE		= 0x45,
+	MIPI_DCS_SET_DISPLAY_BRIGHTNESS = 0x51,		/* MIPI DCS 1.3 */
+	MIPI_DCS_GET_DISPLAY_BRIGHTNESS = 0x52,		/* MIPI DCS 1.3 */
+	MIPI_DCS_WRITE_CONTROL_DISPLAY  = 0x53,		/* MIPI DCS 1.3 */
+	MIPI_DCS_GET_CONTROL_DISPLAY	= 0x54,		/* MIPI DCS 1.3 */
+	MIPI_DCS_WRITE_POWER_SAVE	= 0x55,		/* MIPI DCS 1.3 */
+	MIPI_DCS_GET_POWER_SAVE		= 0x56,		/* MIPI DCS 1.3 */
+	MIPI_DCS_SET_CABC_MIN_BRIGHTNESS = 0x5E,	/* MIPI DCS 1.3 */
+	MIPI_DCS_GET_CABC_MIN_BRIGHTNESS = 0x5F,	/* MIPI DCS 1.3 */
 	MIPI_DCS_READ_DDB_START		= 0xA1,
 	MIPI_DCS_READ_DDB_CONTINUE	= 0xA8,
 };
diff --git a/kernel/Makefile b/kernel/Makefile
index c60cc91..f0c40bf 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -11,13 +11,6 @@ obj-y     = fork.o exec_domain.o panic.o \
 	    notifier.o ksysfs.o cred.o reboot.o \
 	    async.o range.o smpboot.o
 
-# Tracing may do some dangerous __builtin_return_address() operations
-# We know they are dangerous, we don't need gcc telling us that.
-ifdef CONFIG_USING_GET_LOCK_PARENT_IP
-FRAME_CFLAGS := $(call cc-disable-warning,frame-address)
-KBUILD_CFLAGS += $(FRAME_CFLAGS)
-endif
-
 obj-$(CONFIG_MULTIUSER) += groups.o
 
 ifdef CONFIG_FUNCTION_TRACER
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 410c04b..7c7d945 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -480,10 +480,12 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk)
 	* users are removed, this can be killed.
 	*/
 	remainder = tk->tkr_mono.xtime_nsec & ((1ULL << tk->tkr_mono.shift) - 1);
-	tk->tkr_mono.xtime_nsec -= remainder;
-	tk->tkr_mono.xtime_nsec += 1ULL << tk->tkr_mono.shift;
-	tk->ntp_error += remainder << tk->ntp_error_shift;
-	tk->ntp_error -= (1ULL << tk->tkr_mono.shift) << tk->ntp_error_shift;
+	if (remainder != 0) {
+		tk->tkr_mono.xtime_nsec -= remainder;
+		tk->tkr_mono.xtime_nsec += 1ULL << tk->tkr_mono.shift;
+		tk->ntp_error += remainder << tk->ntp_error_shift;
+		tk->ntp_error -= (1ULL << tk->tkr_mono.shift) << tk->ntp_error_shift;
+	}
 }
 #else
 #define old_vsyscall_fixup(tk)
@@ -2186,6 +2188,7 @@ struct timespec64 get_monotonic_coarse64(void)
 
 	return now;
 }
+EXPORT_SYMBOL(get_monotonic_coarse64);
 
 /*
  * Must hold jiffies_lock
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 9aae45f..364ccd0 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -215,7 +215,6 @@ config PREEMPT_TRACER
 	select RING_BUFFER_ALLOW_SWAP
 	select TRACER_SNAPSHOT
 	select TRACER_SNAPSHOT_PER_CPU_SWAP
-	select USING_GET_LOCK_PARENT_IP
 	help
 	  This option measures the time spent in preemption-off critical
 	  sections, with microsecond accuracy.
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 0adcc99..1e9a607 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -962,7 +962,6 @@ config TIMER_STATS
 config DEBUG_PREEMPT
 	bool "Debug preemptible kernel"
 	depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
-	select USING_GET_LOCK_PARENT_IP
 	default y
 	help
 	  If you say Y here then the kernel will use a debug variant of the
@@ -1145,17 +1144,8 @@ config LOCK_TORTURE_TEST
 
 endmenu # lock debugging
 
-config USING_GET_LOCK_PARENT_IP
-        bool
-	help
-	  Enables the use of the function get_lock_parent_ip() that
-	  will use __builtin_return_address(n) with n > 0 causing
-	  some gcc warnings. When this is selected, those warnings
-	  will be suppressed.
-
 config TRACE_IRQFLAGS
 	bool
-	select USING_GET_LOCK_PARENT_IP
 	help
 	  Enables hooks to interrupt enabling and disabling for
 	  either tracing or lock debugging.
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index ccb664b..f03c70a 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -34,6 +34,7 @@
 #ifdef CONFIG_BLOCK
 #include <linux/blkdev.h>
 #endif
+#include <linux/of.h>
 
 #include "../mm/internal.h"	/* For the trace_print_flags arrays */
 
@@ -1475,6 +1476,141 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)
 	return format_flags(buf, end, flags, names);
 }
 
+/* helper method for calculating extends on first pass  and filling in later */
+static noinline_for_stack
+void append_str(const char *str, int pass, int *lenp, char **bufp, char *end)
+{
+	int len;
+
+	len = strlen(str);
+	if (pass == 1)
+		*lenp += len;
+	else {
+		if (len > (end - *bufp))
+			len = end - *bufp;
+		memcpy(*bufp, str, len);
+		*bufp += len;
+	}
+}
+
+static noinline_for_stack
+char *device_node_string(char *buf, char *end, struct device_node *dn,
+			 struct printf_spec spec, const char *fmt)
+{
+	char tbuf[sizeof("xxxxxxxxxx") + 1];
+	const char *fmtp, *p;
+	int len, ret, i, j, pass;
+	char c;
+
+	if (!IS_ENABLED(CONFIG_OF)) {
+		/* if OF is not enabled just print the pointer */
+		spec.flags |= SMALL;
+		if (spec.field_width == -1) {
+			spec.field_width = 2 * sizeof(void *);
+			spec.flags |= ZEROPAD;
+		}
+		spec.base = 16;
+		return number(buf, end, (unsigned long) dn, spec);
+	}
+
+	if ((unsigned long)dn < PAGE_SIZE)
+		return string(buf, end, "(null)", spec);
+
+	/* simple case without anything any more format specifiers */
+	if (fmt[1] == '\0' || isspace(fmt[1]))
+		fmt = "Of";
+
+	len = 0;
+
+	/* two passes; the first calculates length, the second fills in */
+	for (pass = 1; pass <= 2; pass++) {
+		if (pass == 2 && !(spec.flags & LEFT)) {
+			/* padding */
+			while (len < spec.field_width--) {
+				if (buf < end)
+					*buf = ' ';
+				++buf;
+			}
+		}
+
+		for (fmtp = fmt + 1, j = 0; (c = *fmtp++) != '\0'; ) {
+
+			/* validate option */
+			if (c != 'f' && c != 'n' && c != 'p' && c != 'P' &&
+			    c != 'F' && c != 'c' && c != 'C' && c != 'r')
+				continue;
+
+			/* handle separator */
+			if (j++ > 0)
+				append_str("|", pass, &len, &buf, end);
+
+			switch (c) {
+			case 'f':	/* full_name */
+				append_str(of_node_full_name(dn), pass, &len,
+						&buf, end);
+				break;
+			case 'n':	/* name */
+				append_str(dn->name, pass, &len, &buf, end);
+				break;
+			case 'p':	/* phandle */
+				snprintf(tbuf, sizeof(tbuf), "%u",
+						(unsigned int)dn->phandle);
+				append_str(tbuf, pass, &len, &buf, end);
+				break;
+			case 'P':	/* path-spec */
+				append_str(dn->name, pass, &len, &buf, end);
+				/* need to tack on the @ postfix */
+				p = strchr(of_node_full_name(dn), '@');
+				if (p)
+					append_str(p, pass, &len, &buf, end);
+				break;
+			case 'F':	/* flags */
+				snprintf(tbuf, sizeof(tbuf), "%c%c%c%c",
+					of_node_check_flag(dn, OF_DYNAMIC) ?
+						'D' : '-',
+					of_node_check_flag(dn, OF_DETACHED) ?
+						'd' : '-',
+					of_node_check_flag(dn, OF_POPULATED) ?
+						'P' : '-',
+					of_node_check_flag(dn,
+						OF_POPULATED_BUS) ?  'B' : '-');
+				append_str(tbuf, pass, &len, &buf, end);
+				break;
+			case 'c':	/* major compatible string */
+				ret = of_property_read_string(dn, "compatible",
+						&p);
+				if (ret == 0)
+					append_str(p, pass, &len, &buf, end);
+				break;
+			case 'C':	/* full compatible string */
+				i = 0;
+				while (of_property_read_string_index(dn,
+						"compatible", i, &p) == 0) {
+					append_str(i == 0 ? "\"" : "\",\"",
+							pass, &len, &buf, end);
+					append_str(p, pass, &len, &buf, end);
+					i++;
+				}
+				if (i > 0)
+					append_str("\"", pass, &len, &buf, end);
+				break;
+			case 'r':	/* node reference count */
+				snprintf(tbuf, sizeof(tbuf), "%u",
+					atomic_read(&dn->kobj.kref.refcount));
+				append_str(tbuf, pass, &len, &buf, end);
+				break;
+			default:
+				break;
+			}
+		}
+	}
+	/* finish up */
+	while (buf < end && len < spec.field_width--)
+		*buf++ = ' ';
+
+	return buf;
+}
+
 int kptr_restrict __read_mostly;
 
 /*
@@ -1568,6 +1704,16 @@ int kptr_restrict __read_mostly;
  *       p page flags (see struct page) given as pointer to unsigned long
  *       g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
  *       v vma flags (VM_*) given as pointer to unsigned long
+ * - 'O[fnpPcCFr]' For an DT device node
+ *                Without any optional arguments prints the full_name
+ *                f device node full_name
+ *                n device node name
+ *                p device node phandle
+ *                P device node path spec (name + @unit)
+ *                F device node flags
+ *                c major compatible string
+ *                C full compatible string
+ *                r node reference count
  *
  * ** Please update also Documentation/printk-formats.txt when making changes **
  *
@@ -1723,6 +1869,10 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 
 	case 'G':
 		return flags_string(buf, end, ptr, fmt);
+
+	case 'O':
+		return device_node_string(buf, end, ptr, spec, fmt);
+
 	}
 	spec.flags |= SMALL;
 	if (spec.field_width == -1) {
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index caee835..9764ec4 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4044,88 +4044,6 @@ static struct cftype mem_cgroup_legacy_files[] = {
 	{ },	/* terminate */
 };
 
-/*
- * Private memory cgroup IDR
- *
- * Swap-out records and page cache shadow entries need to store memcg
- * references in constrained space, so we maintain an ID space that is
- * limited to 16 bit (MEM_CGROUP_ID_MAX), limiting the total number of
- * memory-controlled cgroups to 64k.
- *
- * However, there usually are many references to the oflline CSS after
- * the cgroup has been destroyed, such as page cache or reclaimable
- * slab objects, that don't need to hang on to the ID. We want to keep
- * those dead CSS from occupying IDs, or we might quickly exhaust the
- * relatively small ID space and prevent the creation of new cgroups
- * even when there are much fewer than 64k cgroups - possibly none.
- *
- * Maintain a private 16-bit ID space for memcg, and allow the ID to
- * be freed and recycled when it's no longer needed, which is usually
- * when the CSS is offlined.
- *
- * The only exception to that are records of swapped out tmpfs/shmem
- * pages that need to be attributed to live ancestors on swapin. But
- * those references are manageable from userspace.
- */
-
-static DEFINE_IDR(mem_cgroup_idr);
-
-static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n)
-{
-	atomic_add(n, &memcg->id.ref);
-}
-
-static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg)
-{
-	while (!atomic_inc_not_zero(&memcg->id.ref)) {
-		/*
-		 * The root cgroup cannot be destroyed, so it's refcount must
-		 * always be >= 1.
-		 */
-		if (WARN_ON_ONCE(memcg == root_mem_cgroup)) {
-			VM_BUG_ON(1);
-			break;
-		}
-		memcg = parent_mem_cgroup(memcg);
-		if (!memcg)
-			memcg = root_mem_cgroup;
-	}
-	return memcg;
-}
-
-static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n)
-{
-	if (atomic_sub_and_test(n, &memcg->id.ref)) {
-		idr_remove(&mem_cgroup_idr, memcg->id.id);
-		memcg->id.id = 0;
-
-		/* Memcg ID pins CSS */
-		css_put(&memcg->css);
-	}
-}
-
-static inline void mem_cgroup_id_get(struct mem_cgroup *memcg)
-{
-	mem_cgroup_id_get_many(memcg, 1);
-}
-
-static inline void mem_cgroup_id_put(struct mem_cgroup *memcg)
-{
-	mem_cgroup_id_put_many(memcg, 1);
-}
-
-/**
- * mem_cgroup_from_id - look up a memcg from a memcg id
- * @id: the memcg id to look up
- *
- * Caller must hold rcu_read_lock().
- */
-struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
-{
-	WARN_ON_ONCE(!rcu_read_lock_held());
-	return idr_find(&mem_cgroup_idr, id);
-}
-
 static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
 {
 	struct mem_cgroup_per_node *pn;
@@ -4185,12 +4103,6 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
 	if (!memcg)
 		return NULL;
 
-	memcg->id.id = idr_alloc(&mem_cgroup_idr, NULL,
-				 1, MEM_CGROUP_ID_MAX,
-				 GFP_KERNEL);
-	if (memcg->id.id < 0)
-		goto fail;
-
 	memcg->stat = alloc_percpu(struct mem_cgroup_stat_cpu);
 	if (!memcg->stat)
 		goto fail;
@@ -4217,11 +4129,8 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
 #ifdef CONFIG_CGROUP_WRITEBACK
 	INIT_LIST_HEAD(&memcg->cgwb_list);
 #endif
-	idr_replace(&mem_cgroup_idr, memcg, memcg->id.id);
 	return memcg;
 fail:
-	if (memcg->id.id > 0)
-		idr_remove(&mem_cgroup_idr, memcg->id.id);
 	mem_cgroup_free(memcg);
 	return NULL;
 }
@@ -4281,14 +4190,15 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 	return &memcg->css;
 fail:
 	mem_cgroup_free(memcg);
-	return ERR_PTR(-ENOMEM);
+	return NULL;
 }
 
-static int mem_cgroup_css_online(struct cgroup_subsys_state *css)
+static int
+mem_cgroup_css_online(struct cgroup_subsys_state *css)
 {
-	/* Online state pins memcg ID, memcg ID pins CSS */
-	mem_cgroup_id_get(mem_cgroup_from_css(css));
-	css_get(css);
+	if (css->id > MEM_CGROUP_ID_MAX)
+		return -ENOSPC;
+
 	return 0;
 }
 
@@ -4311,8 +4221,6 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
 
 	memcg_offline_kmem(memcg);
 	wb_memcg_offline(memcg);
-
-	mem_cgroup_id_put(memcg);
 }
 
 static void mem_cgroup_css_released(struct cgroup_subsys_state *css)
@@ -4750,8 +4658,6 @@ static void __mem_cgroup_clear_mc(void)
 		if (!mem_cgroup_is_root(mc.from))
 			page_counter_uncharge(&mc.from->memsw, mc.moved_swap);
 
-		mem_cgroup_id_put_many(mc.from, mc.moved_swap);
-
 		/*
 		 * we charged both to->memory and to->memsw, so we
 		 * should uncharge to->memory.
@@ -4759,9 +4665,9 @@ static void __mem_cgroup_clear_mc(void)
 		if (!mem_cgroup_is_root(mc.to))
 			page_counter_uncharge(&mc.to->memory, mc.moved_swap);
 
-		mem_cgroup_id_get_many(mc.to, mc.moved_swap);
-		css_put_many(&mc.to->css, mc.moved_swap);
+		css_put_many(&mc.from->css, mc.moved_swap);
 
+		/* we've already done css_get(mc.to) */
 		mc.moved_swap = 0;
 	}
 	memcg_oom_recover(from);
@@ -5624,7 +5530,6 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage)
 	struct mem_cgroup *memcg;
 	unsigned int nr_pages;
 	bool compound;
-	unsigned long flags;
 
 	VM_BUG_ON_PAGE(!PageLocked(oldpage), oldpage);
 	VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
@@ -5655,10 +5560,10 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage)
 
 	commit_charge(newpage, memcg, false);
 
-	local_lock_irqsave(event_lock, flags);
+	local_lock_irq(event_lock);
 	mem_cgroup_charge_statistics(memcg, newpage, compound, nr_pages);
 	memcg_check_events(memcg, newpage);
-	local_unlock_irqrestore(event_lock, flags);
+	local_unlock_irq(event_lock);
 }
 
 DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key);
@@ -5821,7 +5726,7 @@ subsys_initcall(mem_cgroup_init);
  */
 void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
 {
-	struct mem_cgroup *memcg, *swap_memcg;
+	struct mem_cgroup *memcg;
 	unsigned short oldid;
 	unsigned long flags;
 
@@ -5837,27 +5742,15 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
 	if (!memcg)
 		return;
 
-	/*
-	 * In case the memcg owning these pages has been offlined and doesn't
-	 * have an ID allocated to it anymore, charge the closest online
-	 * ancestor for the swap instead and transfer the memory+swap charge.
-	 */
-	swap_memcg = mem_cgroup_id_get_online(memcg);
-	oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg));
+	oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg));
 	VM_BUG_ON_PAGE(oldid, page);
-	mem_cgroup_swap_statistics(swap_memcg, true);
+	mem_cgroup_swap_statistics(memcg, true);
 
 	page->mem_cgroup = NULL;
 
 	if (!mem_cgroup_is_root(memcg))
 		page_counter_uncharge(&memcg->memory, 1);
 
-	if (memcg != swap_memcg) {
-		if (!mem_cgroup_is_root(swap_memcg))
-			page_counter_charge(&swap_memcg->memsw, 1);
-		page_counter_uncharge(&memcg->memsw, 1);
-	}
-
 	/*
 	 * Interrupts should be disabled here because the caller holds the
 	 * mapping->tree_lock lock which is taken with interrupts-off. It is
@@ -5870,9 +5763,6 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
 #endif
 	mem_cgroup_charge_statistics(memcg, page, false, -1);
 	memcg_check_events(memcg, page);
-
-	if (!mem_cgroup_is_root(memcg))
-		css_put(&memcg->css);
 	local_unlock_irqrestore(event_lock, flags);
 }
 
@@ -5900,18 +5790,15 @@ int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
 	if (!memcg)
 		return 0;
 
-	memcg = mem_cgroup_id_get_online(memcg);
-
 	if (!mem_cgroup_is_root(memcg) &&
-	    !page_counter_try_charge(&memcg->swap, 1, &counter)) {
-		mem_cgroup_id_put(memcg);
+	    !page_counter_try_charge(&memcg->swap, 1, &counter))
 		return -ENOMEM;
-	}
 
 	oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg));
 	VM_BUG_ON_PAGE(oldid, page);
 	mem_cgroup_swap_statistics(memcg, true);
 
+	css_get(&memcg->css);
 	return 0;
 }
 
@@ -5940,7 +5827,7 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry)
 				page_counter_uncharge(&memcg->memsw, 1);
 		}
 		mem_cgroup_swap_statistics(memcg, false);
-		mem_cgroup_id_put(memcg);
+		css_put(&memcg->css);
 	}
 	rcu_read_unlock();
 }
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 3ac9e66..3239bfd 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -526,8 +526,8 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg,
 		goto out_unlock;
 
 	cgroup_name(css->cgroup, memcg_name_buf, sizeof(memcg_name_buf));
-	cache_name = kasprintf(GFP_KERNEL, "%s(%llu:%s)", root_cache->name,
-			       css->serial_nr, memcg_name_buf);
+	cache_name = kasprintf(GFP_KERNEL, "%s(%d:%s)", root_cache->name,
+			       css->id, memcg_name_buf);
 	if (!cache_name)
 		goto out_unlock;
 
diff --git a/mm/swap.c b/mm/swap.c
index 6ac7186..d3558eb 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -243,7 +243,7 @@ void rotate_reclaimable_page(struct page *page)
 		get_page(page);
 		local_lock_irqsave(rotate_lock, flags);
 		pvec = this_cpu_ptr(&lru_rotate_pvecs);
-		if (!pagevec_add(pvec, page) || PageCompound(page))
+		if (!pagevec_add(pvec, page))
 			pagevec_move_tail(pvec);
 		local_unlock_irqrestore(rotate_lock, flags);
 	}
@@ -300,7 +300,7 @@ void activate_page(struct page *page)
 						       activate_page_pvecs);
 
 		get_page(page);
-		if (!pagevec_add(pvec, page) || PageCompound(page))
+		if (!pagevec_add(pvec, page))
 			pagevec_lru_move_fn(pvec, __activate_page, NULL);
 		put_locked_var(swapvec_lock, activate_page_pvecs);
 	}
@@ -395,8 +395,9 @@ static void __lru_cache_add(struct page *page)
 	struct pagevec *pvec = &get_locked_var(swapvec_lock, lru_add_pvec);
 
 	get_page(page);
-	if (!pagevec_add(pvec, page) || PageCompound(page))
+	if (!pagevec_space(pvec))
 		__pagevec_lru_add(pvec);
+	pagevec_add(pvec, page);
 	put_locked_var(swapvec_lock, lru_add_pvec);
 }
 
@@ -638,7 +639,7 @@ void deactivate_file_page(struct page *page)
 		struct pagevec *pvec = &get_locked_var(swapvec_lock,
 						       lru_deactivate_file_pvecs);
 
-		if (!pagevec_add(pvec, page) || PageCompound(page))
+		if (!pagevec_add(pvec, page))
 			pagevec_lru_move_fn(pvec, lru_deactivate_file_fn, NULL);
 		put_locked_var(swapvec_lock, lru_deactivate_file_pvecs);
 	}
@@ -659,7 +660,7 @@ void deactivate_page(struct page *page)
 						       lru_deactivate_pvecs);
 
 		get_page(page);
-		if (!pagevec_add(pvec, page) || PageCompound(page))
+		if (!pagevec_add(pvec, page))
 			pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL);
 		put_locked_var(swapvec_lock, lru_deactivate_pvecs);
 	}
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 63731fd..c1f1d50 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -78,7 +78,6 @@
 #include <linux/string.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/slab.h>
-#include <linux/locallock.h>
 #include <net/snmp.h>
 #include <net/ip.h>
 #include <net/route.h>
@@ -206,8 +205,6 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
  *
  *	On SMP we have one ICMP socket per-cpu.
  */
-static DEFINE_LOCAL_IRQ_LOCK(icmp_sk_lock);
-
 static struct sock *icmp_sk(struct net *net)
 {
 	return *this_cpu_ptr(net->ipv4.icmp_sk);
@@ -219,14 +216,12 @@ static inline struct sock *icmp_xmit_lock(struct net *net)
 
 	local_bh_disable();
 
-	local_lock(icmp_sk_lock);
 	sk = icmp_sk(net);
 
 	if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
 		/* This can happen if the output path signals a
 		 * dst_link_failure() for an outgoing ICMP packet.
 		 */
-		local_unlock(icmp_sk_lock);
 		local_bh_enable();
 		return NULL;
 	}
@@ -236,7 +231,6 @@ static inline struct sock *icmp_xmit_lock(struct net *net)
 static inline void icmp_xmit_unlock(struct sock *sk)
 {
 	spin_unlock_bh(&sk->sk_lock.slock);
-	local_unlock(icmp_sk_lock);
 }
 
 int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
@@ -365,7 +359,6 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
 	struct sock *sk;
 	struct sk_buff *skb;
 
-	local_lock(icmp_sk_lock);
 	sk = icmp_sk(dev_net((*rt)->dst.dev));
 	if (ip_append_data(sk, fl4, icmp_glue_bits, icmp_param,
 			   icmp_param->data_len+icmp_param->head_len,
@@ -388,7 +381,6 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
 		skb->ip_summed = CHECKSUM_NONE;
 		ip_push_pending_frames(sk, fl4);
 	}
-	local_unlock(icmp_sk_lock);
 }
 
 /*
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index c5521d1..ad45050 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -62,7 +62,6 @@
 #include <linux/init.h>
 #include <linux/times.h>
 #include <linux/slab.h>
-#include <linux/locallock.h>
 
 #include <net/net_namespace.h>
 #include <net/icmp.h>
@@ -566,7 +565,6 @@ void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(tcp_v4_send_check);
 
-static DEFINE_LOCAL_IRQ_LOCK(tcp_sk_lock);
 /*
  *	This routine will send an RST to the other tcp.
  *
@@ -691,13 +689,10 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
 		     offsetof(struct inet_timewait_sock, tw_bound_dev_if));
 
 	arg.tos = ip_hdr(skb)->tos;
-
-	local_lock(tcp_sk_lock);
 	ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk),
 			      skb, &TCP_SKB_CB(skb)->header.h4.opt,
 			      ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
 			      &arg, arg.iov[0].iov_len);
-	local_unlock(tcp_sk_lock);
 
 	TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
 	TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
@@ -779,12 +774,10 @@ static void tcp_v4_send_ack(struct net *net,
 	if (oif)
 		arg.bound_dev_if = oif;
 	arg.tos = tos;
-	local_lock(tcp_sk_lock);
 	ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk),
 			      skb, &TCP_SKB_CB(skb)->header.h4.opt,
 			      ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
 			      &arg, arg.iov[0].iov_len);
-	local_unlock(tcp_sk_lock);
 
 	TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
 }
diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile
index 1b4e4b8..3fe1116 100644
--- a/samples/seccomp/Makefile
+++ b/samples/seccomp/Makefile
@@ -20,6 +20,7 @@ bpf-direct-objs := bpf-direct.o
 # Try to match the kernel target.
 ifndef CROSS_COMPILE
 ifndef CONFIG_64BIT
+ifndef CONFIG_ARM
 
 # s390 has -m31 flag to build 31 bit binaries
 ifndef CONFIG_S390
@@ -46,3 +47,4 @@ ifndef CONFIG_MIPS
 always := $(hostprogs-y)
 endif
 endif
+endif
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
index 0c03ac9..207a923 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -294,6 +294,30 @@ static void check_node_name_format(struct check *c, struct node *dt,
 }
 NODE_ERROR(node_name_format, NULL, &node_name_chars);
 
+static void check_unit_address_vs_reg(struct check *c, struct node *dt,
+			     struct node *node)
+{
+	const char *unitname = get_unitname(node);
+	struct property *prop = get_property(node, "reg");
+
+	if (!prop) {
+		prop = get_property(node, "ranges");
+		if (prop && !prop->val.len)
+			prop = NULL;
+	}
+
+	if (prop) {
+		if (!unitname[0])
+			FAIL(c, "Node %s has a reg or ranges property, but no unit name",
+			    node->fullpath);
+	} else {
+		if (unitname[0])
+			FAIL(c, "Node %s has a unit name, but no reg property",
+			    node->fullpath);
+	}
+}
+NODE_WARNING(unit_address_vs_reg, NULL);
+
 static void check_property_name_chars(struct check *c, struct node *dt,
 				      struct node *node, struct property *prop)
 {
@@ -458,6 +482,8 @@ static void fixup_phandle_references(struct check *c, struct node *dt,
 				     struct node *node, struct property *prop)
 {
 	struct marker *m = prop->val.markers;
+	struct fixup *f, **fp;
+	struct fixup_entry *fe, **fep;
 	struct node *refnode;
 	cell_t phandle;
 
@@ -466,14 +492,73 @@ static void fixup_phandle_references(struct check *c, struct node *dt,
 
 		refnode = get_node_by_ref(dt, m->ref);
 		if (! refnode) {
-			FAIL(c, "Reference to non-existent node or label \"%s\"\n",
-			     m->ref);
+			if (!dt->is_plugin) {
+				FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+					m->ref);
+				continue;
+			}
+
+			/* allocate fixup entry */
+			fe = xmalloc(sizeof(*fe));
+
+			fe->node = node;
+			fe->prop = prop;
+			fe->offset = m->offset;
+			fe->next = NULL;
+
+			/* search for an already existing fixup */
+			for_each_fixup(dt, f)
+				if (strcmp(f->ref, m->ref) == 0)
+					break;
+
+			/* no fixup found, add new */
+			if (f == NULL) {
+				f = xmalloc(sizeof(*f));
+				f->ref = m->ref;
+				f->entries = NULL;
+				f->next = NULL;
+
+				/* add it to the tree */
+				fp = &dt->fixups;
+				while (*fp)
+					fp = &(*fp)->next;
+				*fp = f;
+			}
+
+			/* and now append fixup entry */
+			fep = &f->entries;
+			while (*fep)
+				fep = &(*fep)->next;
+			*fep = fe;
+
+			/* mark the entry as unresolved */
+			*((cell_t *)(prop->val.val + m->offset)) =
+				cpu_to_fdt32(0xdeadbeef);
 			continue;
 		}
 
+		/* if it's a local reference, we need to record it */
+		if (symbol_fixup_support) {
+
+			/* allocate a new local fixup entry */
+			fe = xmalloc(sizeof(*fe));
+
+			fe->node = node;
+			fe->prop = prop;
+			fe->offset = m->offset;
+			fe->next = NULL;
+
+			/* append it to the local fixups */
+			fep = &dt->local_fixups;
+			while (*fep)
+				fep = &(*fep)->next;
+			*fep = fe;
+		}
+
 		phandle = get_node_phandle(dt, refnode);
 		*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
 	}
+
 }
 ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
       &duplicate_node_names, &explicit_phandles);
@@ -652,6 +737,45 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
 }
 TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
 
+static void check_auto_label_phandles(struct check *c, struct node *dt,
+				       struct node *node)
+{
+	struct label *l;
+	struct symbol *s, **sp;
+	int has_label;
+
+	if (!symbol_fixup_support)
+		return;
+
+	has_label = 0;
+	for_each_label(node->labels, l) {
+		has_label = 1;
+		break;
+	}
+
+	if (!has_label)
+		return;
+
+	/* force allocation of a phandle for this node */
+	(void)get_node_phandle(dt, node);
+
+	/* add the symbol */
+	for_each_label(node->labels, l) {
+
+		s = xmalloc(sizeof(*s));
+		s->label = l;
+		s->node = node;
+		s->next = NULL;
+
+		/* add it to the symbols list */
+		sp = &dt->symbols;
+		while (*sp)
+			sp = &((*sp)->next);
+		*sp = s;
+	}
+}
+NODE_WARNING(auto_label_phandles, NULL);
+
 static struct check *check_table[] = {
 	&duplicate_node_names, &duplicate_property_names,
 	&node_name_chars, &node_name_format, &property_name_chars,
@@ -667,9 +791,13 @@ static struct check *check_table[] = {
 
 	&addr_size_cells, &reg_format, &ranges_format,
 
+	&unit_address_vs_reg,
+
 	&avoid_default_addr_size,
 	&obsolete_chosen_interrupt_controller,
 
+	&auto_label_phandles,
+
 	&always_fail,
 };
 
diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
index 790fbf6..40bbc87 100644
--- a/scripts/dtc/dtc-lexer.l
+++ b/scripts/dtc/dtc-lexer.l
@@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...);
 			return DT_V1;
 		}
 
+<*>"/plugin/"	{
+			DPRINT("Keyword: /plugin/\n");
+			return DT_PLUGIN;
+		}
+
 <*>"/memreserve/"	{
 			DPRINT("Keyword: /memreserve/\n");
 			BEGIN_DEFAULT();
diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped
index ba525c2..d29e2a9 100644
--- a/scripts/dtc/dtc-lexer.lex.c_shipped
+++ b/scripts/dtc/dtc-lexer.lex.c_shipped
@@ -8,8 +8,8 @@
 
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 39
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 0
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
@@ -211,7 +211,7 @@ struct yy_buffer_state
 	/* Number of characters read into yy_ch_buf, not including EOB
 	 * characters.
 	 */
-	yy_size_t yy_n_chars;
+	int yy_n_chars;
 
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	 * and can realloc() it to grow it, and should free() it to
@@ -281,7 +281,7 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
 
 /* yy_hold_char holds the character lost when yytext is formed. */
 static char yy_hold_char;
-static yy_size_t yy_n_chars;		/* number of characters read into yy_ch_buf */
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
 yy_size_t yyleng;
 
 /* Points to current character in buffer. */
@@ -342,7 +342,7 @@ void yyfree (void *  );
 
 /* Begin user sect3 */
 
-#define yywrap() 1
+#define yywrap() (/*CONSTCOND*/1)
 #define YY_SKIP_YYWRAP
 
 typedef unsigned char YY_CHAR;
@@ -356,11 +356,17 @@ extern int yylineno;
 int yylineno = 1;
 
 extern char *yytext;
+#ifdef yytext_ptr
+#undef yytext_ptr
+#endif
 #define yytext_ptr yytext
 
 static yy_state_type yy_get_previous_state (void );
 static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
 static int yy_get_next_buffer (void );
+#if defined(__GNUC__) && __GNUC__ >= 3
+__attribute__((__noreturn__))
+#endif
 static void yy_fatal_error (yyconst char msg[]  );
 
 /* Done after the current pattern has been matched and before the
@@ -373,8 +379,8 @@ static void yy_fatal_error (yyconst char msg[]  );
 	*yy_cp = '\0'; \
 	(yy_c_buf_p) = yy_cp;
 
-#define YY_NUM_RULES 30
-#define YY_END_OF_BUFFER 31
+#define YY_NUM_RULES 31
+#define YY_END_OF_BUFFER 32
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -382,28 +388,29 @@ struct yy_trans_info
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[159] =
+static yyconst flex_int16_t yy_accept[166] =
     {   0,
-        0,    0,    0,    0,    0,    0,    0,    0,   31,   29,
-       18,   18,   29,   29,   29,   29,   29,   29,   29,   29,
-       29,   29,   29,   29,   29,   29,   15,   16,   16,   29,
-       16,   10,   10,   18,   26,    0,    3,    0,   27,   12,
-        0,    0,   11,    0,    0,    0,    0,    0,    0,    0,
-       21,   23,   25,   24,   22,    0,    9,   28,    0,    0,
-        0,   14,   14,   16,   16,   16,   10,   10,   10,    0,
-       12,    0,   11,    0,    0,    0,   20,    0,    0,    0,
-        0,    0,    0,    0,    0,   16,   10,   10,   10,    0,
-       13,   19,    0,    0,    0,    0,    0,    0,    0,    0,
-
-        0,   16,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,   16,    6,    0,    0,    0,    0,    0,    0,    2,
-        0,    0,    0,    0,    0,    0,    0,    0,    4,   17,
-        0,    0,    2,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    1,    0,    0,    0,    0,
-        5,    8,    0,    0,    0,    0,    7,    0
+        0,    0,    0,    0,    0,    0,    0,    0,   32,   30,
+       19,   19,   30,   30,   30,   30,   30,   30,   30,   30,
+       30,   30,   30,   30,   30,   30,   16,   17,   17,   30,
+       17,   11,   11,   19,   27,    0,    3,    0,   28,   13,
+        0,    0,   12,    0,    0,    0,    0,    0,    0,    0,
+        0,   22,   24,   26,   25,   23,    0,   10,   29,    0,
+        0,    0,   15,   15,   17,   17,   17,   11,   11,   11,
+        0,   13,    0,   12,    0,    0,    0,   21,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,   17,   11,   11,
+       11,    0,   14,   20,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,   17,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,   17,    7,    0,    0,    0,
+        0,    0,    0,    0,    2,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    4,   18,    0,    0,    5,    2,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    1,    0,    0,    0,    0,    6,    9,    0,
+        0,    0,    0,    8,    0
     } ;
 
-static yyconst flex_int32_t yy_ec[256] =
+static yyconst YY_CHAR yy_ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         4,    4,    4,    1,    1,    1,    1,    1,    1,    1,
@@ -416,9 +423,9 @@ static yyconst flex_int32_t yy_ec[256] =
        22,   22,   22,   22,   24,   22,   22,   25,   22,   22,
         1,   26,   27,    1,   22,    1,   21,   28,   29,   30,
 
-       31,   21,   22,   22,   32,   22,   22,   33,   34,   35,
-       36,   37,   22,   38,   39,   40,   41,   42,   22,   25,
-       43,   22,   44,   45,   46,    1,    1,    1,    1,    1,
+       31,   21,   32,   22,   33,   22,   22,   34,   35,   36,
+       37,   38,   22,   39,   40,   41,   42,   43,   22,   25,
+       44,   22,   45,   46,   47,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -435,163 +442,165 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[47] =
+static yyconst YY_CHAR yy_meta[48] =
     {   0,
         1,    1,    1,    1,    1,    1,    2,    3,    1,    2,
         2,    2,    4,    5,    5,    5,    6,    1,    1,    1,
         7,    8,    8,    8,    8,    1,    1,    7,    7,    7,
         7,    8,    8,    8,    8,    8,    8,    8,    8,    8,
-        8,    8,    8,    3,    1,    4
+        8,    8,    8,    8,    3,    1,    4
     } ;
 
-static yyconst flex_int16_t yy_base[173] =
+static yyconst flex_uint16_t yy_base[180] =
     {   0,
-        0,  383,   34,  382,   65,  381,   37,  105,  387,  391,
-       54,  111,  367,  110,  109,  109,  112,   41,  366,  104,
-      367,  338,  124,  117,    0,  144,  391,    0,  121,    0,
-      135,  155,  140,  179,  391,  160,  391,  379,  391,    0,
-      368,  141,  391,  167,  370,  376,  346,  103,  342,  345,
-      391,  391,  391,  391,  391,  358,  391,  391,  175,  342,
-      338,  391,  355,    0,  185,  339,  184,  347,  346,    0,
-        0,  322,  175,  357,  175,  363,  352,  324,  330,  323,
-      332,  326,  201,  324,  329,  322,  391,  333,  181,  309,
-      391,  341,  340,  313,  320,  338,  178,  311,  146,  317,
-
-      314,  315,  335,  331,  303,  300,  309,  299,  308,  188,
-      336,  335,  391,  305,  320,  281,  283,  271,  203,  288,
-      281,  271,  266,  264,  245,  242,  208,  104,  391,  391,
-      244,  218,  204,  219,  206,  224,  201,  212,  204,  229,
-      215,  208,  207,  200,  219,  391,  233,  221,  200,  181,
-      391,  391,  149,  122,   86,   41,  391,  391,  245,  251,
-      259,  263,  267,  273,  280,  284,  292,  300,  304,  310,
-      318,  326
+        0,  393,   35,  392,   66,  391,   38,  107,  397,  401,
+       55,  113,  377,  112,  111,  111,  114,   42,  376,  106,
+      377,  347,  126,  120,    0,  147,  401,    0,  124,    0,
+      137,  158,  170,  163,  401,  153,  401,  389,  401,    0,
+      378,  120,  401,  131,  380,  386,  355,  139,  351,  355,
+      351,  401,  401,  401,  401,  401,  367,  401,  401,  185,
+      350,  346,  401,  364,    0,  185,  347,  189,  356,  355,
+        0,    0,  330,  180,  366,  141,  372,  361,  332,  338,
+      331,  341,  334,  326,  205,  331,  337,  329,  401,  341,
+      167,  316,  401,  349,  348,  320,  328,  346,  180,  318,
+
+      324,  209,  324,  320,  322,  342,  338,  309,  306,  315,
+      305,  315,  312,  192,  342,  341,  401,  293,  306,  282,
+      268,  252,  255,  203,  285,  282,  272,  268,  252,  233,
+      232,  239,  208,  107,  401,  401,  238,  211,  401,  211,
+      212,  208,  228,  203,  215,  207,  233,  222,  212,  211,
+      203,  227,  401,  237,  225,  204,  185,  401,  401,  149,
+      128,   88,   42,  401,  401,  253,  259,  267,  271,  275,
+      281,  288,  292,  300,  308,  312,  318,  326,  334
     } ;
 
-static yyconst flex_int16_t yy_def[173] =
+static yyconst flex_int16_t yy_def[180] =
     {   0,
-      158,    1,    1,    3,  158,    5,    1,    1,  158,  158,
-      158,  158,  158,  159,  160,  161,  158,  158,  158,  158,
-      162,  158,  158,  158,  163,  162,  158,  164,  165,  164,
-      164,  158,  158,  158,  158,  159,  158,  159,  158,  166,
-      158,  161,  158,  161,  167,  168,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  162,  158,  158,  158,  158,
-      158,  158,  162,  164,  165,  164,  158,  158,  158,  169,
-      166,  170,  161,  167,  167,  168,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  164,  158,  158,  169,  170,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-
-      158,  164,  158,  158,  158,  158,  158,  158,  158,  171,
-      158,  164,  158,  158,  158,  158,  158,  158,  171,  158,
-      171,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      172,  158,  158,  158,  172,  158,  172,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,    0,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158
+      165,    1,    1,    3,  165,    5,    1,    1,  165,  165,
+      165,  165,  165,  166,  167,  168,  165,  165,  165,  165,
+      169,  165,  165,  165,  170,  169,  165,  171,  172,  171,
+      171,  165,  165,  165,  165,  166,  165,  166,  165,  173,
+      165,  168,  165,  168,  174,  175,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  169,  165,  165,  165,
+      165,  165,  165,  169,  171,  172,  171,  165,  165,  165,
+      176,  173,  177,  168,  174,  174,  175,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  171,  165,  165,
+      176,  177,  165,  165,  165,  165,  165,  165,  165,  165,
+
+      165,  165,  165,  165,  171,  165,  165,  165,  165,  165,
+      165,  165,  165,  178,  165,  171,  165,  165,  165,  165,
+      165,  165,  165,  178,  165,  178,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  179,  165,  165,
+      165,  179,  165,  179,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,    0,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165
     } ;
 
-static yyconst flex_int16_t yy_nxt[438] =
+static yyconst flex_uint16_t yy_nxt[449] =
     {   0,
        10,   11,   12,   11,   13,   14,   10,   15,   16,   10,
        10,   10,   17,   10,   10,   10,   10,   18,   19,   20,
        21,   21,   21,   21,   21,   10,   10,   21,   21,   21,
        21,   21,   21,   21,   21,   21,   21,   21,   21,   21,
-       21,   21,   21,   10,   22,   10,   24,   25,   25,   25,
-       32,   33,   33,  157,   26,   34,   34,   34,   51,   52,
-       27,   26,   26,   26,   26,   10,   11,   12,   11,   13,
-       14,   28,   15,   16,   28,   28,   28,   24,   28,   28,
-       28,   10,   18,   19,   20,   29,   29,   29,   29,   29,
-       30,   10,   29,   29,   29,   29,   29,   29,   29,   29,
-
-       29,   29,   29,   29,   29,   29,   29,   29,   10,   22,
-       10,   23,   34,   34,   34,   37,   39,   43,   32,   33,
-       33,   45,   54,   55,   46,   59,   45,   64,  156,   46,
-       64,   64,   64,   79,   44,   38,   59,   57,  134,   47,
-      135,   48,   80,   49,   47,   50,   48,   99,   61,   43,
-       50,  110,   41,   67,   67,   67,   60,   63,   63,   63,
-       57,  155,   68,   69,   63,   37,   44,   66,   67,   67,
-       67,   63,   63,   63,   63,   73,   59,   68,   69,   70,
-       34,   34,   34,   43,   75,   38,  154,   92,   83,   83,
-       83,   64,   44,  120,   64,   64,   64,   67,   67,   67,
-
-       44,   57,   99,   68,   69,  107,   68,   69,  120,  127,
-      108,  153,  152,  121,   83,   83,   83,  133,  133,  133,
-      146,  133,  133,  133,  146,  140,  140,  140,  121,  141,
-      140,  140,  140,  151,  141,  158,  150,  149,  148,  144,
-      147,  143,  142,  139,  147,   36,   36,   36,   36,   36,
-       36,   36,   36,   40,  138,  137,  136,   40,   40,   42,
-       42,   42,   42,   42,   42,   42,   42,   56,   56,   56,
-       56,   62,  132,   62,   64,  131,  130,   64,  129,   64,
-       64,   65,  128,  158,   65,   65,   65,   65,   71,  127,
-       71,   71,   74,   74,   74,   74,   74,   74,   74,   74,
-
-       76,   76,   76,   76,   76,   76,   76,   76,   89,  126,
-       89,   90,  125,   90,   90,  124,   90,   90,  119,  119,
-      119,  119,  119,  119,  119,  119,  145,  145,  145,  145,
-      145,  145,  145,  145,  123,  122,   59,   59,  118,  117,
-      116,  115,  114,  113,   45,  112,  108,  111,  109,  106,
-      105,  104,   46,  103,   91,   87,  102,  101,  100,   98,
-       97,   96,   95,   94,   93,   77,   75,   91,   88,   87,
-       86,   57,   85,   84,   57,   82,   81,   78,   77,   75,
-       72,  158,   58,   57,   53,   35,  158,   31,   23,   23,
-        9,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158
+       21,   21,   21,   21,   10,   22,   10,   24,   25,   25,
+       25,   32,   33,   33,  164,   26,   34,   34,   34,   52,
+       53,   27,   26,   26,   26,   26,   10,   11,   12,   11,
+       13,   14,   28,   15,   16,   28,   28,   28,   24,   28,
+       28,   28,   10,   18,   19,   20,   29,   29,   29,   29,
+       29,   30,   10,   29,   29,   29,   29,   29,   29,   29,
+
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       10,   22,   10,   23,   34,   34,   34,   37,   39,   43,
+       32,   33,   33,   45,   55,   56,   46,   60,   43,   45,
+       65,  163,   46,   65,   65,   65,   44,   38,   60,   74,
+       58,   47,  141,   48,  142,   44,   49,   47,   50,   48,
+       76,   51,   62,   94,   50,   41,   44,   51,   37,   61,
+       64,   64,   64,   58,   34,   34,   34,   64,  162,   80,
+       67,   68,   68,   68,   64,   64,   64,   64,   38,   81,
+       69,   70,   71,   68,   68,   68,   60,  161,   43,   69,
+       70,   65,   69,   70,   65,   65,   65,  125,   85,   85,
+
+       85,   58,   68,   68,   68,   44,  102,  110,  125,  133,
+      102,   69,   70,  111,  114,  160,  159,  126,   85,   85,
+       85,  140,  140,  140,  140,  140,  140,  153,  126,  147,
+      147,  147,  153,  148,  147,  147,  147,  158,  148,  165,
+      157,  156,  155,  151,  150,  149,  146,  154,  145,  144,
+      143,  139,  154,   36,   36,   36,   36,   36,   36,   36,
+       36,   40,  138,  137,  136,   40,   40,   42,   42,   42,
+       42,   42,   42,   42,   42,   57,   57,   57,   57,   63,
+      135,   63,   65,  134,  165,   65,  133,   65,   65,   66,
+      132,  131,   66,   66,   66,   66,   72,  130,   72,   72,
+
+       75,   75,   75,   75,   75,   75,   75,   75,   77,   77,
+       77,   77,   77,   77,   77,   77,   91,  129,   91,   92,
+      128,   92,   92,  127,   92,   92,  124,  124,  124,  124,
+      124,  124,  124,  124,  152,  152,  152,  152,  152,  152,
+      152,  152,   60,   60,  123,  122,  121,  120,  119,  118,
+      117,   45,  116,  111,  115,  113,  112,  109,  108,  107,
+       46,  106,   93,   89,  105,  104,  103,  101,  100,   99,
+       98,   97,   96,   95,   78,   76,   93,   90,   89,   88,
+       58,   87,   86,   58,   84,   83,   82,   79,   78,   76,
+       73,  165,   59,   58,   54,   35,  165,   31,   23,   23,
+
+        9,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165
     } ;
 
-static yyconst flex_int16_t yy_chk[438] =
+static yyconst flex_int16_t yy_chk[449] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    3,    3,    3,    3,
-        7,    7,    7,  156,    3,   11,   11,   11,   18,   18,
-        3,    3,    3,    3,    3,    5,    5,    5,    5,    5,
+        1,    1,    1,    1,    1,    1,    1,    3,    3,    3,
+        3,    7,    7,    7,  163,    3,   11,   11,   11,   18,
+       18,    3,    3,    3,    3,    3,    5,    5,    5,    5,
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
 
         5,    5,    5,    5,    5,    5,    5,    5,    5,    5,
-        5,    8,   12,   12,   12,   14,   15,   16,    8,    8,
-        8,   17,   20,   20,   17,   23,   24,   29,  155,   24,
-       29,   29,   29,   48,   16,   14,   31,   29,  128,   17,
-      128,   17,   48,   17,   24,   17,   24,   99,   24,   42,
-       24,   99,   15,   33,   33,   33,   23,   26,   26,   26,
-       26,  154,   33,   33,   26,   36,   42,   31,   32,   32,
-       32,   26,   26,   26,   26,   44,   59,   32,   32,   32,
-       34,   34,   34,   73,   75,   36,  153,   75,   59,   59,
-       59,   65,   44,  110,   65,   65,   65,   67,   67,   67,
-
-       73,   65,   83,   89,   89,   97,   67,   67,  119,  127,
-       97,  150,  149,  110,   83,   83,   83,  133,  133,  133,
-      141,  127,  127,  127,  145,  136,  136,  136,  119,  136,
-      140,  140,  140,  148,  140,  147,  144,  143,  142,  139,
-      141,  138,  137,  135,  145,  159,  159,  159,  159,  159,
-      159,  159,  159,  160,  134,  132,  131,  160,  160,  161,
-      161,  161,  161,  161,  161,  161,  161,  162,  162,  162,
-      162,  163,  126,  163,  164,  125,  124,  164,  123,  164,
-      164,  165,  122,  121,  165,  165,  165,  165,  166,  120,
-      166,  166,  167,  167,  167,  167,  167,  167,  167,  167,
-
-      168,  168,  168,  168,  168,  168,  168,  168,  169,  118,
-      169,  170,  117,  170,  170,  116,  170,  170,  171,  171,
-      171,  171,  171,  171,  171,  171,  172,  172,  172,  172,
-      172,  172,  172,  172,  115,  114,  112,  111,  109,  108,
-      107,  106,  105,  104,  103,  102,  101,  100,   98,   96,
-       95,   94,   93,   92,   90,   88,   86,   85,   84,   82,
-       81,   80,   79,   78,   77,   76,   74,   72,   69,   68,
-       66,   63,   61,   60,   56,   50,   49,   47,   46,   45,
+        5,    5,    5,    8,   12,   12,   12,   14,   15,   16,
+        8,    8,    8,   17,   20,   20,   17,   23,   42,   24,
+       29,  162,   24,   29,   29,   29,   16,   14,   31,   44,
+       29,   17,  134,   17,  134,   42,   17,   24,   17,   24,
+       76,   17,   24,   76,   24,   15,   44,   24,   36,   23,
+       26,   26,   26,   26,   34,   34,   34,   26,  161,   48,
+       31,   32,   32,   32,   26,   26,   26,   26,   36,   48,
+       32,   32,   32,   33,   33,   33,   60,  160,   74,   91,
+       91,   66,   33,   33,   66,   66,   66,  114,   60,   60,
+
+       60,   66,   68,   68,   68,   74,   85,   99,  124,  133,
+      102,   68,   68,   99,  102,  157,  156,  114,   85,   85,
+       85,  133,  133,  133,  140,  140,  140,  148,  124,  143,
+      143,  143,  152,  143,  147,  147,  147,  155,  147,  154,
+      151,  150,  149,  146,  145,  144,  142,  148,  141,  138,
+      137,  132,  152,  166,  166,  166,  166,  166,  166,  166,
+      166,  167,  131,  130,  129,  167,  167,  168,  168,  168,
+      168,  168,  168,  168,  168,  169,  169,  169,  169,  170,
+      128,  170,  171,  127,  126,  171,  125,  171,  171,  172,
+      123,  122,  172,  172,  172,  172,  173,  121,  173,  173,
+
+      174,  174,  174,  174,  174,  174,  174,  174,  175,  175,
+      175,  175,  175,  175,  175,  175,  176,  120,  176,  177,
+      119,  177,  177,  118,  177,  177,  178,  178,  178,  178,
+      178,  178,  178,  178,  179,  179,  179,  179,  179,  179,
+      179,  179,  116,  115,  113,  112,  111,  110,  109,  108,
+      107,  106,  105,  104,  103,  101,  100,   98,   97,   96,
+       95,   94,   92,   90,   88,   87,   86,   84,   83,   82,
+       81,   80,   79,   78,   77,   75,   73,   70,   69,   67,
+       64,   62,   61,   57,   51,   50,   49,   47,   46,   45,
        41,   38,   22,   21,   19,   13,    9,    6,    4,    2,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
 
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158,  158,  158,  158,
-      158,  158,  158,  158,  158,  158,  158
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
+      165,  165,  165,  165,  165,  165,  165,  165
     } ;
 
 static yy_state_type yy_last_accepting_state;
@@ -662,7 +671,7 @@ static int dts_version = 1;
 static void push_input_file(const char *filename);
 static bool pop_input_file(void);
 static void lexical_error(const char *fmt, ...);
-#line 666 "dtc-lexer.lex.c"
+#line 675 "dtc-lexer.lex.c"
 
 #define INITIAL 0
 #define BYTESTRING 1
@@ -698,11 +707,11 @@ void yyset_extra (YY_EXTRA_TYPE user_defined  );
 
 FILE *yyget_in (void );
 
-void yyset_in  (FILE * in_str  );
+void yyset_in  (FILE * _in_str  );
 
 FILE *yyget_out (void );
 
-void yyset_out  (FILE * out_str  );
+void yyset_out  (FILE * _out_str  );
 
 yy_size_t yyget_leng (void );
 
@@ -710,7 +719,7 @@ char *yyget_text (void );
 
 int yyget_lineno (void );
 
-void yyset_lineno (int line_number  );
+void yyset_lineno (int _line_number  );
 
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
@@ -724,6 +733,10 @@ extern int yywrap (void );
 #endif
 #endif
 
+#ifndef YY_NO_UNPUT
+
+#endif
+
 #ifndef yytext_ptr
 static void yy_flex_strncpy (char *,yyconst char *,int );
 #endif
@@ -836,7 +849,7 @@ extern int yylex (void);
 
 /* Code executed at the end of each rule. */
 #ifndef YY_BREAK
-#define YY_BREAK break;
+#define YY_BREAK /*LINTED*/break;
 #endif
 
 #define YY_RULE_SETUP \
@@ -849,9 +862,9 @@ extern int yylex (void);
  */
 YY_DECL
 {
-	register yy_state_type yy_current_state;
-	register char *yy_cp, *yy_bp;
-	register int yy_act;
+	yy_state_type yy_current_state;
+	char *yy_cp, *yy_bp;
+	int yy_act;
     
 	if ( !(yy_init) )
 		{
@@ -882,9 +895,9 @@ YY_DECL
 	{
 #line 68 "dtc-lexer.l"
 
-#line 886 "dtc-lexer.lex.c"
+#line 899 "dtc-lexer.lex.c"
 
-	while ( 1 )		/* loops until end-of-file is reached */
+	while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
 		{
 		yy_cp = (yy_c_buf_p);
 
@@ -901,7 +914,7 @@ YY_DECL
 yy_match:
 		do
 			{
-			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+			YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
 			if ( yy_accept[yy_current_state] )
 				{
 				(yy_last_accepting_state) = yy_current_state;
@@ -910,13 +923,13 @@ yy_match:
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 159 )
+				if ( yy_current_state >= 166 )
 					yy_c = yy_meta[(unsigned int) yy_c];
 				}
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 			++yy_cp;
 			}
-		while ( yy_current_state != 158 );
+		while ( yy_current_state != 165 );
 		yy_cp = (yy_last_accepting_cpos);
 		yy_current_state = (yy_last_accepting_state);
 
@@ -1015,23 +1028,31 @@ case 5:
 YY_RULE_SETUP
 #line 124 "dtc-lexer.l"
 {
+			DPRINT("Keyword: /plugin/\n");
+			return DT_PLUGIN;
+		}
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 129 "dtc-lexer.l"
+{
 			DPRINT("Keyword: /memreserve/\n");
 			BEGIN_DEFAULT();
 			return DT_MEMRESERVE;
 		}
 	YY_BREAK
-case 6:
+case 7:
 YY_RULE_SETUP
-#line 130 "dtc-lexer.l"
+#line 135 "dtc-lexer.l"
 {
 			DPRINT("Keyword: /bits/\n");
 			BEGIN_DEFAULT();
 			return DT_BITS;
 		}
 	YY_BREAK
-case 7:
+case 8:
 YY_RULE_SETUP
-#line 136 "dtc-lexer.l"
+#line 141 "dtc-lexer.l"
 {
 			DPRINT("Keyword: /delete-property/\n");
 			DPRINT("<PROPNODENAME>\n");
@@ -1039,9 +1060,9 @@ YY_RULE_SETUP
 			return DT_DEL_PROP;
 		}
 	YY_BREAK
-case 8:
+case 9:
 YY_RULE_SETUP
-#line 143 "dtc-lexer.l"
+#line 148 "dtc-lexer.l"
 {
 			DPRINT("Keyword: /delete-node/\n");
 			DPRINT("<PROPNODENAME>\n");
@@ -1049,9 +1070,9 @@ YY_RULE_SETUP
 			return DT_DEL_NODE;
 		}
 	YY_BREAK
-case 9:
+case 10:
 YY_RULE_SETUP
-#line 150 "dtc-lexer.l"
+#line 155 "dtc-lexer.l"
 {
 			DPRINT("Label: %s\n", yytext);
 			yylval.labelref = xstrdup(yytext);
@@ -1059,9 +1080,9 @@ YY_RULE_SETUP
 			return DT_LABEL;
 		}
 	YY_BREAK
-case 10:
+case 11:
 YY_RULE_SETUP
-#line 157 "dtc-lexer.l"
+#line 162 "dtc-lexer.l"
 {
 			char *e;
 			DPRINT("Integer Literal: '%s'\n", yytext);
@@ -1084,10 +1105,10 @@ YY_RULE_SETUP
 			return DT_LITERAL;
 		}
 	YY_BREAK
-case 11:
-/* rule 11 can match eol */
+case 12:
+/* rule 12 can match eol */
 YY_RULE_SETUP
-#line 179 "dtc-lexer.l"
+#line 184 "dtc-lexer.l"
 {
 			struct data d;
 			DPRINT("Character literal: %s\n", yytext);
@@ -1109,18 +1130,18 @@ YY_RULE_SETUP
 			return DT_CHAR_LITERAL;
 		}
 	YY_BREAK
-case 12:
+case 13:
 YY_RULE_SETUP
-#line 200 "dtc-lexer.l"
+#line 205 "dtc-lexer.l"
 {	/* label reference */
 			DPRINT("Ref: %s\n", yytext+1);
 			yylval.labelref = xstrdup(yytext+1);
 			return DT_REF;
 		}
 	YY_BREAK
-case 13:
+case 14:
 YY_RULE_SETUP
-#line 206 "dtc-lexer.l"
+#line 211 "dtc-lexer.l"
 {	/* new-style path reference */
 			yytext[yyleng-1] = '\0';
 			DPRINT("Ref: %s\n", yytext+2);
@@ -1128,27 +1149,27 @@ YY_RULE_SETUP
 			return DT_REF;
 		}
 	YY_BREAK
-case 14:
+case 15:
 YY_RULE_SETUP
-#line 213 "dtc-lexer.l"
+#line 218 "dtc-lexer.l"
 {
 			yylval.byte = strtol(yytext, NULL, 16);
 			DPRINT("Byte: %02x\n", (int)yylval.byte);
 			return DT_BYTE;
 		}
 	YY_BREAK
-case 15:
+case 16:
 YY_RULE_SETUP
-#line 219 "dtc-lexer.l"
+#line 224 "dtc-lexer.l"
 {
 			DPRINT("/BYTESTRING\n");
 			BEGIN_DEFAULT();
 			return ']';
 		}
 	YY_BREAK
-case 16:
+case 17:
 YY_RULE_SETUP
-#line 225 "dtc-lexer.l"
+#line 230 "dtc-lexer.l"
 {
 			DPRINT("PropNodeName: %s\n", yytext);
 			yylval.propnodename = xstrdup((yytext[0] == '\\') ?
@@ -1157,75 +1178,75 @@ YY_RULE_SETUP
 			return DT_PROPNODENAME;
 		}
 	YY_BREAK
-case 17:
+case 18:
 YY_RULE_SETUP
-#line 233 "dtc-lexer.l"
+#line 238 "dtc-lexer.l"
 {
 			DPRINT("Binary Include\n");
 			return DT_INCBIN;
 		}
 	YY_BREAK
-case 18:
-/* rule 18 can match eol */
-YY_RULE_SETUP
-#line 238 "dtc-lexer.l"
-/* eat whitespace */
-	YY_BREAK
 case 19:
 /* rule 19 can match eol */
 YY_RULE_SETUP
-#line 239 "dtc-lexer.l"
-/* eat C-style comments */
+#line 243 "dtc-lexer.l"
+/* eat whitespace */
 	YY_BREAK
 case 20:
 /* rule 20 can match eol */
 YY_RULE_SETUP
-#line 240 "dtc-lexer.l"
-/* eat C++-style comments */
+#line 244 "dtc-lexer.l"
+/* eat C-style comments */
 	YY_BREAK
 case 21:
+/* rule 21 can match eol */
 YY_RULE_SETUP
-#line 242 "dtc-lexer.l"
-{ return DT_LSHIFT; };
+#line 245 "dtc-lexer.l"
+/* eat C++-style comments */
 	YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 243 "dtc-lexer.l"
-{ return DT_RSHIFT; };
+#line 247 "dtc-lexer.l"
+{ return DT_LSHIFT; };
 	YY_BREAK
 case 23:
 YY_RULE_SETUP
-#line 244 "dtc-lexer.l"
-{ return DT_LE; };
+#line 248 "dtc-lexer.l"
+{ return DT_RSHIFT; };
 	YY_BREAK
 case 24:
 YY_RULE_SETUP
-#line 245 "dtc-lexer.l"
-{ return DT_GE; };
+#line 249 "dtc-lexer.l"
+{ return DT_LE; };
 	YY_BREAK
 case 25:
 YY_RULE_SETUP
-#line 246 "dtc-lexer.l"
-{ return DT_EQ; };
+#line 250 "dtc-lexer.l"
+{ return DT_GE; };
 	YY_BREAK
 case 26:
 YY_RULE_SETUP
-#line 247 "dtc-lexer.l"
-{ return DT_NE; };
+#line 251 "dtc-lexer.l"
+{ return DT_EQ; };
 	YY_BREAK
 case 27:
 YY_RULE_SETUP
-#line 248 "dtc-lexer.l"
-{ return DT_AND; };
+#line 252 "dtc-lexer.l"
+{ return DT_NE; };
 	YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 249 "dtc-lexer.l"
-{ return DT_OR; };
+#line 253 "dtc-lexer.l"
+{ return DT_AND; };
 	YY_BREAK
 case 29:
 YY_RULE_SETUP
-#line 251 "dtc-lexer.l"
+#line 254 "dtc-lexer.l"
+{ return DT_OR; };
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 256 "dtc-lexer.l"
 {
 			DPRINT("Char: %c (\\x%02x)\n", yytext[0],
 				(unsigned)yytext[0]);
@@ -1241,12 +1262,12 @@ YY_RULE_SETUP
 			return yytext[0];
 		}
 	YY_BREAK
-case 30:
+case 31:
 YY_RULE_SETUP
-#line 266 "dtc-lexer.l"
+#line 271 "dtc-lexer.l"
 ECHO;
 	YY_BREAK
-#line 1250 "dtc-lexer.lex.c"
+#line 1271 "dtc-lexer.lex.c"
 
 	case YY_END_OF_BUFFER:
 		{
@@ -1388,9 +1409,9 @@ ECHO;
  */
 static int yy_get_next_buffer (void)
 {
-    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
-	register char *source = (yytext_ptr);
-	register int number_to_move, i;
+	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	char *source = (yytext_ptr);
+	yy_size_t number_to_move, i;
 	int ret_val;
 
 	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
@@ -1419,7 +1440,7 @@ static int yy_get_next_buffer (void)
 	/* Try to read more data. */
 
 	/* First move last chars to start of buffer. */
-	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+	number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1;
 
 	for ( i = 0; i < number_to_move; ++i )
 		*(dest++) = *(source++);
@@ -1501,9 +1522,9 @@ static int yy_get_next_buffer (void)
 	else
 		ret_val = EOB_ACT_CONTINUE_SCAN;
 
-	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+	if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
 		/* Extend the array by 50%, plus the number we really need. */
-		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
 		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
 		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
 			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
@@ -1522,15 +1543,15 @@ static int yy_get_next_buffer (void)
 
     static yy_state_type yy_get_previous_state (void)
 {
-	register yy_state_type yy_current_state;
-	register char *yy_cp;
+	yy_state_type yy_current_state;
+	char *yy_cp;
     
 	yy_current_state = (yy_start);
 	yy_current_state += YY_AT_BOL();
 
 	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
 		{
-		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
 		if ( yy_accept[yy_current_state] )
 			{
 			(yy_last_accepting_state) = yy_current_state;
@@ -1539,7 +1560,7 @@ static int yy_get_next_buffer (void)
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 159 )
+			if ( yy_current_state >= 166 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1555,10 +1576,10 @@ static int yy_get_next_buffer (void)
  */
     static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
 {
-	register int yy_is_jam;
-    	register char *yy_cp = (yy_c_buf_p);
+	int yy_is_jam;
+	char *yy_cp = (yy_c_buf_p);
 
-	register YY_CHAR yy_c = 1;
+	YY_CHAR yy_c = 1;
 	if ( yy_accept[yy_current_state] )
 		{
 		(yy_last_accepting_state) = yy_current_state;
@@ -1567,15 +1588,19 @@ static int yy_get_next_buffer (void)
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 159 )
+		if ( yy_current_state >= 166 )
 			yy_c = yy_meta[(unsigned int) yy_c];
 		}
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 158);
+	yy_is_jam = (yy_current_state == 165);
 
 		return yy_is_jam ? 0 : yy_current_state;
 }
 
+#ifndef YY_NO_UNPUT
+
+#endif
+
 #ifndef YY_NO_INPUT
 #ifdef __cplusplus
     static int yyinput (void)
@@ -1727,7 +1752,7 @@ static void yy_load_buffer_state  (void)
 	if ( ! b )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
-	b->yy_buf_size = size;
+	b->yy_buf_size = (yy_size_t)size;
 
 	/* yy_ch_buf has to be 2 characters longer than the size given because
 	 * we need to put in 2 end-of-buffer characters.
@@ -1882,7 +1907,7 @@ static void yyensure_buffer_stack (void)
 		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
 		 * immediate realloc on the next call.
          */
-		num_to_alloc = 1;
+		num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
 		(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
 								(num_to_alloc * sizeof(struct yy_buffer_state*)
 								);
@@ -1899,7 +1924,7 @@ static void yyensure_buffer_stack (void)
 	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
 
 		/* Increase the buffer to prepare for a possible push. */
-		int grow_size = 8 /* arbitrary grow size */;
+		yy_size_t grow_size = 8 /* arbitrary grow size */;
 
 		num_to_alloc = (yy_buffer_stack_max) + grow_size;
 		(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
@@ -2007,7 +2032,7 @@ YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len
 
 static void yy_fatal_error (yyconst char* msg )
 {
-    	(void) fprintf( stderr, "%s\n", msg );
+			(void) fprintf( stderr, "%s\n", msg );
 	exit( YY_EXIT_FAILURE );
 }
 
@@ -2073,29 +2098,29 @@ char *yyget_text  (void)
 }
 
 /** Set the current line number.
- * @param line_number
+ * @param _line_number line number
  * 
  */
-void yyset_lineno (int  line_number )
+void yyset_lineno (int  _line_number )
 {
     
-    yylineno = line_number;
+    yylineno = _line_number;
 }
 
 /** Set the input stream. This does not discard the current
  * input buffer.
- * @param in_str A readable stream.
+ * @param _in_str A readable stream.
  * 
  * @see yy_switch_to_buffer
  */
-void yyset_in (FILE *  in_str )
+void yyset_in (FILE *  _in_str )
 {
-        yyin = in_str ;
+        yyin = _in_str ;
 }
 
-void yyset_out (FILE *  out_str )
+void yyset_out (FILE *  _out_str )
 {
-        yyout = out_str ;
+        yyout = _out_str ;
 }
 
 int yyget_debug  (void)
@@ -2103,9 +2128,9 @@ int yyget_debug  (void)
         return yy_flex_debug;
 }
 
-void yyset_debug (int  bdebug )
+void yyset_debug (int  _bdebug )
 {
-        yy_flex_debug = bdebug ;
+        yy_flex_debug = _bdebug ;
 }
 
 static int yy_init_globals (void)
@@ -2165,7 +2190,8 @@ int yylex_destroy  (void)
 #ifndef yytext_ptr
 static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
 {
-	register int i;
+
+	int i;
 	for ( i = 0; i < n; ++i )
 		s1[i] = s2[i];
 }
@@ -2174,7 +2200,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
 #ifdef YY_NEED_STRLEN
 static int yy_flex_strlen (yyconst char * s )
 {
-	register int n;
+	int n;
 	for ( n = 0; s[n]; ++n )
 		;
 
@@ -2184,11 +2210,12 @@ static int yy_flex_strlen (yyconst char * s )
 
 void *yyalloc (yy_size_t  size )
 {
-	return (void *) malloc( size );
+			return (void *) malloc( size );
 }
 
 void *yyrealloc  (void * ptr, yy_size_t  size )
 {
+
 	/* The cast to (char *) in the following accommodates both
 	 * implementations that use char* generic pointers, and those
 	 * that use void* generic pointers.  It works with the latter
@@ -2201,12 +2228,12 @@ void *yyrealloc  (void * ptr, yy_size_t  size )
 
 void yyfree (void * ptr )
 {
-	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
+			free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
 }
 
 #define YYTABLES_NAME "yytables"
 
-#line 265 "dtc-lexer.l"
+#line 271 "dtc-lexer.l"
 
 
 
diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped
index 31cec50..ce71569 100644
--- a/scripts/dtc/dtc-parser.tab.c_shipped
+++ b/scripts/dtc/dtc-parser.tab.c_shipped
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.0.2.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
 
    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
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "3.0.2"
+#define YYBISON_VERSION "3.0.4"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -65,6 +65,7 @@
 #line 20 "dtc-parser.y" /* yacc.c:339  */
 
 #include <stdio.h>
+#include <inttypes.h>
 
 #include "dtc.h"
 #include "srcpos.h"
@@ -80,7 +81,7 @@ extern void yyerror(char const *s);
 extern struct boot_info *the_boot_info;
 extern bool treesource_error;
 
-#line 84 "dtc-parser.tab.c" /* yacc.c:339  */
+#line 85 "dtc-parser.tab.c" /* yacc.c:339  */
 
 # ifndef YY_NULLPTR
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -116,35 +117,36 @@ extern int yydebug;
   enum yytokentype
   {
     DT_V1 = 258,
-    DT_MEMRESERVE = 259,
-    DT_LSHIFT = 260,
-    DT_RSHIFT = 261,
-    DT_LE = 262,
-    DT_GE = 263,
-    DT_EQ = 264,
-    DT_NE = 265,
-    DT_AND = 266,
-    DT_OR = 267,
-    DT_BITS = 268,
-    DT_DEL_PROP = 269,
-    DT_DEL_NODE = 270,
-    DT_PROPNODENAME = 271,
-    DT_LITERAL = 272,
-    DT_CHAR_LITERAL = 273,
-    DT_BYTE = 274,
-    DT_STRING = 275,
-    DT_LABEL = 276,
-    DT_REF = 277,
-    DT_INCBIN = 278
+    DT_PLUGIN = 259,
+    DT_MEMRESERVE = 260,
+    DT_LSHIFT = 261,
+    DT_RSHIFT = 262,
+    DT_LE = 263,
+    DT_GE = 264,
+    DT_EQ = 265,
+    DT_NE = 266,
+    DT_AND = 267,
+    DT_OR = 268,
+    DT_BITS = 269,
+    DT_DEL_PROP = 270,
+    DT_DEL_NODE = 271,
+    DT_PROPNODENAME = 272,
+    DT_LITERAL = 273,
+    DT_CHAR_LITERAL = 274,
+    DT_BYTE = 275,
+    DT_STRING = 276,
+    DT_LABEL = 277,
+    DT_REF = 278,
+    DT_INCBIN = 279
   };
 #endif
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE YYSTYPE;
+
 union YYSTYPE
 {
-#line 38 "dtc-parser.y" /* yacc.c:355  */
+#line 39 "dtc-parser.y" /* yacc.c:355  */
 
 	char *propnodename;
 	char *labelref;
@@ -162,9 +164,12 @@ union YYSTYPE
 	struct node *nodelist;
 	struct reserve_info *re;
 	uint64_t integer;
+	bool is_plugin;
 
-#line 167 "dtc-parser.tab.c" /* yacc.c:355  */
+#line 170 "dtc-parser.tab.c" /* yacc.c:355  */
 };
+
+typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
 #endif
@@ -192,7 +197,7 @@ int yyparse (void);
 
 /* Copy the second part of user declarations.  */
 
-#line 196 "dtc-parser.tab.c" /* yacc.c:358  */
+#line 201 "dtc-parser.tab.c" /* yacc.c:358  */
 
 #ifdef short
 # undef short
@@ -439,18 +444,18 @@ union yyalloc
 #define YYLAST   136
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  47
+#define YYNTOKENS  48
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  28
+#define YYNNTS  29
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  80
+#define YYNRULES  82
 /* YYNSTATES -- Number of states.  */
-#define YYNSTATES  144
+#define YYNSTATES  147
 
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   278
+#define YYMAXUTOK   279
 
 #define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -462,16 +467,16 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    46,     2,     2,     2,    44,    40,     2,
-      32,    34,    43,    41,    33,    42,     2,    25,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    37,    24,
-      35,    28,    29,    36,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    47,     2,     2,     2,    45,    41,     2,
+      33,    35,    44,    42,    34,    43,     2,    26,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    38,    25,
+      36,    29,    30,    37,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    30,     2,    31,    39,     2,     2,     2,     2,     2,
+       2,    31,     2,    32,    40,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    26,    38,    27,    45,     2,     2,     2,
+       2,     2,     2,    27,    39,    28,    46,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -486,22 +491,22 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
        5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24
 };
 
 #if YYDEBUG
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   104,   104,   113,   116,   123,   127,   135,   139,   144,
-     155,   165,   180,   188,   191,   198,   202,   206,   210,   218,
-     222,   226,   230,   234,   250,   260,   268,   271,   275,   282,
-     298,   303,   322,   336,   343,   344,   345,   352,   356,   357,
-     361,   362,   366,   367,   371,   372,   376,   377,   381,   382,
-     386,   387,   388,   392,   393,   394,   395,   396,   400,   401,
-     402,   406,   407,   408,   412,   413,   422,   431,   435,   436,
-     437,   438,   443,   446,   450,   458,   461,   465,   473,   477,
-     481
+       0,   108,   108,   118,   121,   129,   132,   139,   143,   151,
+     155,   160,   171,   181,   196,   204,   207,   214,   218,   222,
+     226,   234,   238,   242,   246,   250,   266,   276,   284,   287,
+     291,   298,   314,   319,   338,   352,   359,   360,   361,   368,
+     372,   373,   377,   378,   382,   383,   387,   388,   392,   393,
+     397,   398,   402,   403,   404,   408,   409,   410,   411,   412,
+     416,   417,   418,   422,   423,   424,   428,   429,   438,   447,
+     451,   452,   453,   454,   459,   462,   466,   474,   477,   481,
+     489,   493,   497
 };
 #endif
 
@@ -510,19 +515,19 @@ static const yytype_uint16 yyrline[] =
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT",
-  "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR",
-  "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL",
-  "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF",
-  "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'",
-  "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'",
-  "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
-  "memreserves", "memreserve", "devicetree", "nodedef", "proplist",
-  "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim",
-  "integer_expr", "integer_trinary", "integer_or", "integer_and",
-  "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq",
-  "integer_rela", "integer_shift", "integer_add", "integer_mul",
-  "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR
+  "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE",
+  "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND",
+  "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME",
+  "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL",
+  "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['",
+  "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'",
+  "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile",
+  "plugindecl", "memreserves", "memreserve", "devicetree", "nodedef",
+  "proplist", "propdef", "propdata", "propdataprefix", "arrayprefix",
+  "integer_prim", "integer_expr", "integer_trinary", "integer_or",
+  "integer_and", "integer_bitor", "integer_bitxor", "integer_bitand",
+  "integer_eq", "integer_rela", "integer_shift", "integer_add",
+  "integer_mul", "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR
 };
 #endif
 
@@ -533,16 +538,16 @@ static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,   277,   278,    59,    47,   123,   125,    61,    62,
-      91,    93,    40,    44,    41,    60,    63,    58,   124,    94,
-      38,    43,    45,    42,    37,   126,    33
+     275,   276,   277,   278,   279,    59,    47,   123,   125,    61,
+      62,    91,    93,    40,    44,    41,    60,    63,    58,   124,
+      94,    38,    43,    45,    42,    37,   126,    33
 };
 # endif
 
-#define YYPACT_NINF -81
+#define YYPACT_NINF -84
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-81)))
+  (!!((Yystate) == (-84)))
 
 #define YYTABLE_NINF -1
 
@@ -553,21 +558,21 @@ static const yytype_uint16 yytoknum[] =
      STATE-NUM.  */
 static const yytype_int8 yypact[] =
 {
-      16,   -11,    21,    10,   -81,    25,    10,    19,    10,   -81,
-     -81,    -9,    25,   -81,     2,    51,   -81,    -9,    -9,    -9,
-     -81,     1,   -81,    -6,    50,    14,    28,    29,    36,     3,
-      58,    44,    -3,   -81,    47,   -81,   -81,    65,    68,     2,
-       2,   -81,   -81,   -81,   -81,    -9,    -9,    -9,    -9,    -9,
-      -9,    -9,    -9,    -9,    -9,    -9,    -9,    -9,    -9,    -9,
-      -9,    -9,    -9,    -9,   -81,    63,    69,     2,   -81,   -81,
-      50,    57,    14,    28,    29,    36,     3,     3,    58,    58,
-      58,    58,    44,    44,    -3,    -3,   -81,   -81,   -81,    79,
-      80,    -8,    63,   -81,    72,    63,   -81,   -81,    -9,    76,
-      77,   -81,   -81,   -81,   -81,   -81,    78,   -81,   -81,   -81,
-     -81,   -81,    35,     4,   -81,   -81,   -81,   -81,    86,   -81,
-     -81,   -81,    73,   -81,   -81,    33,    71,    84,    39,   -81,
-     -81,   -81,   -81,   -81,    41,   -81,   -81,   -81,    25,   -81,
-      74,    25,    75,   -81
+      15,   -12,    35,    42,   -84,    27,     9,   -84,    24,     9,
+      43,     9,   -84,   -84,   -10,    24,   -84,    60,    44,   -84,
+     -10,   -10,   -10,   -84,    55,   -84,    -7,    52,    53,    51,
+      54,    10,     2,    38,    37,    -4,   -84,    68,   -84,   -84,
+      71,    73,    60,    60,   -84,   -84,   -84,   -84,   -10,   -10,
+     -10,   -10,   -10,   -10,   -10,   -10,   -10,   -10,   -10,   -10,
+     -10,   -10,   -10,   -10,   -10,   -10,   -10,   -84,    56,    72,
+      60,   -84,   -84,    52,    61,    53,    51,    54,    10,     2,
+       2,    38,    38,    38,    38,    37,    37,    -4,    -4,   -84,
+     -84,   -84,    81,    83,    34,    56,   -84,    74,    56,   -84,
+     -84,   -10,    76,    78,   -84,   -84,   -84,   -84,   -84,    79,
+     -84,   -84,   -84,   -84,   -84,    -6,     3,   -84,   -84,   -84,
+     -84,    87,   -84,   -84,   -84,    75,   -84,   -84,    32,    70,
+      86,    36,   -84,   -84,   -84,   -84,   -84,    47,   -84,   -84,
+     -84,    24,   -84,    77,    24,    80,   -84
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -575,37 +580,37 @@ static const yytype_int8 yypact[] =
      means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     0,     0,     3,     1,     0,     0,     0,     3,    34,
-      35,     0,     0,     6,     0,     2,     4,     0,     0,     0,
-      68,     0,    37,    38,    40,    42,    44,    46,    48,    50,
-      53,    60,    63,    67,     0,    13,     7,     0,     0,     0,
-       0,    69,    70,    71,    36,     0,     0,     0,     0,     0,
+       0,     0,     0,     3,     1,     0,     5,     4,     0,     0,
+       0,     5,    36,    37,     0,     0,     8,     0,     2,     6,
+       0,     0,     0,    70,     0,    39,    40,    42,    44,    46,
+      48,    50,    52,    55,    62,    65,    69,     0,    15,     9,
+       0,     0,     0,     0,    71,    72,    73,    38,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     5,    75,     0,     0,    10,     8,
-      41,     0,    43,    45,    47,    49,    51,    52,    56,    57,
-      55,    54,    58,    59,    61,    62,    65,    64,    66,     0,
-       0,     0,     0,    14,     0,    75,    11,     9,     0,     0,
-       0,    16,    26,    78,    18,    80,     0,    77,    76,    39,
-      17,    79,     0,     0,    12,    25,    15,    27,     0,    19,
-      28,    22,     0,    72,    30,     0,     0,     0,     0,    33,
-      32,    20,    31,    29,     0,    73,    74,    21,     0,    24,
-       0,     0,     0,    23
+       0,     0,     0,     0,     0,     0,     0,     7,    77,     0,
+       0,    12,    10,    43,     0,    45,    47,    49,    51,    53,
+      54,    58,    59,    57,    56,    60,    61,    63,    64,    67,
+      66,    68,     0,     0,     0,     0,    16,     0,    77,    13,
+      11,     0,     0,     0,    18,    28,    80,    20,    82,     0,
+      79,    78,    41,    19,    81,     0,     0,    14,    27,    17,
+      29,     0,    21,    30,    24,     0,    74,    32,     0,     0,
+       0,     0,    35,    34,    22,    33,    31,     0,    75,    76,
+      23,     0,    26,     0,     0,     0,    25
 };
 
   /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -81,   -81,   100,   104,   -81,   -38,   -81,   -80,   -81,   -81,
-     -81,    -5,    66,    13,   -81,    70,    67,    81,    64,    82,
-      37,    27,    34,    38,   -14,   -81,    22,    24
+     -84,   -84,   -84,    98,   101,   -84,   -41,   -84,   -83,   -84,
+     -84,   -84,    -8,    63,    12,   -84,    66,    67,    65,    69,
+      82,    29,    18,    25,    26,   -17,   -84,    20,    28
 };
 
   /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     2,     7,     8,    15,    36,    65,    93,   112,   113,
-     125,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-      29,    30,    31,    32,    33,   128,    94,    95
+      -1,     2,     6,    10,    11,    18,    39,    68,    96,   115,
+     116,   128,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    36,   131,    97,    98
 };
 
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
@@ -613,87 +618,87 @@ static const yytype_int16 yydefgoto[] =
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_uint8 yytable[] =
 {
-      12,    68,    69,    41,    42,    43,    45,    34,     9,    10,
-      53,    54,   104,     3,     5,   107,   101,   118,    35,     1,
-     102,     4,    61,    11,   119,   120,   121,   122,    35,    97,
-      46,     6,    55,    17,   123,    44,    18,    19,    56,   124,
-      62,    63,     9,    10,    14,    51,    52,    86,    87,    88,
-       9,    10,    48,   103,   129,   130,   115,    11,   135,   116,
-     136,    47,   131,    57,    58,    11,    37,    49,   117,    50,
-     137,    64,    38,    39,   138,   139,    40,    89,    90,    91,
-      78,    79,    80,    81,    92,    59,    60,    66,    76,    77,
-      67,    82,    83,    96,    98,    99,   100,    84,    85,   106,
-     110,   111,   114,   126,   134,   127,   133,   141,    16,   143,
-      13,   109,    71,    74,    72,    70,   105,   108,     0,     0,
-     132,     0,     0,     0,     0,     0,     0,     0,     0,    73,
-       0,     0,    75,   140,     0,     0,   142
+      15,    71,    72,    44,    45,    46,    48,    37,    12,    13,
+      56,    57,   107,     3,     8,   110,   118,   121,     1,   119,
+      54,    55,    64,    14,   122,   123,   124,   125,   120,   100,
+      49,     9,    58,    20,   126,     4,    21,    22,    59,   127,
+      65,    66,    12,    13,    60,    61,     5,    89,    90,    91,
+      12,    13,     7,   106,   132,   133,   138,    14,   139,   104,
+      40,    38,   134,   105,    50,    14,    41,    42,   140,    17,
+      43,    92,    93,    94,    81,    82,    83,    84,    95,    62,
+      63,   141,   142,    79,    80,    85,    86,    38,    87,    88,
+      47,    52,    51,    67,    69,    53,    70,    99,   102,   101,
+     103,   113,   109,   114,   117,   129,   136,   137,   130,    19,
+      16,   144,    74,   112,    73,   146,    76,    75,   111,     0,
+     135,    77,     0,   108,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   143,     0,    78,   145
 };
 
 static const yytype_int16 yycheck[] =
 {
-       5,    39,    40,    17,    18,    19,    12,    12,    17,    18,
-       7,     8,    92,    24,     4,    95,    24,    13,    26,     3,
-      28,     0,    25,    32,    20,    21,    22,    23,    26,    67,
-      36,    21,    29,    42,    30,    34,    45,    46,    35,    35,
-      43,    44,    17,    18,    25,     9,    10,    61,    62,    63,
-      17,    18,    38,    91,    21,    22,    21,    32,    19,    24,
-      21,    11,    29,     5,     6,    32,    15,    39,    33,    40,
-      31,    24,    21,    22,    33,    34,    25,    14,    15,    16,
-      53,    54,    55,    56,    21,    41,    42,    22,    51,    52,
-      22,    57,    58,    24,    37,    16,    16,    59,    60,    27,
-      24,    24,    24,    17,    20,    32,    35,    33,     8,    34,
-       6,    98,    46,    49,    47,    45,    92,    95,    -1,    -1,
-     125,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    48,
-      -1,    -1,    50,   138,    -1,    -1,   141
+       8,    42,    43,    20,    21,    22,    13,    15,    18,    19,
+       8,     9,    95,    25,     5,    98,    22,    14,     3,    25,
+      10,    11,    26,    33,    21,    22,    23,    24,    34,    70,
+      37,    22,    30,    43,    31,     0,    46,    47,    36,    36,
+      44,    45,    18,    19,     6,     7,     4,    64,    65,    66,
+      18,    19,    25,    94,    22,    23,    20,    33,    22,    25,
+      16,    27,    30,    29,    12,    33,    22,    23,    32,    26,
+      26,    15,    16,    17,    56,    57,    58,    59,    22,    42,
+      43,    34,    35,    54,    55,    60,    61,    27,    62,    63,
+      35,    40,    39,    25,    23,    41,    23,    25,    17,    38,
+      17,    25,    28,    25,    25,    18,    36,    21,    33,    11,
+       9,    34,    49,   101,    48,    35,    51,    50,    98,    -1,
+     128,    52,    -1,    95,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   141,    -1,    53,   144
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,     3,    48,    24,     0,     4,    21,    49,    50,    17,
-      18,    32,    58,    50,    25,    51,    49,    42,    45,    46,
-      58,    59,    60,    61,    62,    63,    64,    65,    66,    67,
-      68,    69,    70,    71,    58,    26,    52,    15,    21,    22,
-      25,    71,    71,    71,    34,    12,    36,    11,    38,    39,
-      40,     9,    10,     7,     8,    29,    35,     5,     6,    41,
-      42,    25,    43,    44,    24,    53,    22,    22,    52,    52,
-      62,    59,    63,    64,    65,    66,    67,    67,    68,    68,
-      68,    68,    69,    69,    70,    70,    71,    71,    71,    14,
-      15,    16,    21,    54,    73,    74,    24,    52,    37,    16,
-      16,    24,    28,    52,    54,    74,    27,    54,    73,    60,
-      24,    24,    55,    56,    24,    21,    24,    33,    13,    20,
-      21,    22,    23,    30,    35,    57,    17,    32,    72,    21,
-      22,    29,    58,    35,    20,    19,    21,    31,    33,    34,
-      58,    33,    58,    34
+       0,     3,    49,    25,     0,     4,    50,    25,     5,    22,
+      51,    52,    18,    19,    33,    60,    52,    26,    53,    51,
+      43,    46,    47,    60,    61,    62,    63,    64,    65,    66,
+      67,    68,    69,    70,    71,    72,    73,    60,    27,    54,
+      16,    22,    23,    26,    73,    73,    73,    35,    13,    37,
+      12,    39,    40,    41,    10,    11,     8,     9,    30,    36,
+       6,     7,    42,    43,    26,    44,    45,    25,    55,    23,
+      23,    54,    54,    64,    61,    65,    66,    67,    68,    69,
+      69,    70,    70,    70,    70,    71,    71,    72,    72,    73,
+      73,    73,    15,    16,    17,    22,    56,    75,    76,    25,
+      54,    38,    17,    17,    25,    29,    54,    56,    76,    28,
+      56,    75,    62,    25,    25,    57,    58,    25,    22,    25,
+      34,    14,    21,    22,    23,    24,    31,    36,    59,    18,
+      33,    74,    22,    23,    30,    60,    36,    21,    20,    22,
+      32,    34,    35,    60,    34,    60,    35
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    47,    48,    49,    49,    50,    50,    51,    51,    51,
-      51,    51,    52,    53,    53,    54,    54,    54,    54,    55,
-      55,    55,    55,    55,    55,    55,    56,    56,    56,    57,
-      57,    57,    57,    57,    58,    58,    58,    59,    60,    60,
-      61,    61,    62,    62,    63,    63,    64,    64,    65,    65,
-      66,    66,    66,    67,    67,    67,    67,    67,    68,    68,
-      68,    69,    69,    69,    70,    70,    70,    70,    71,    71,
-      71,    71,    72,    72,    72,    73,    73,    73,    74,    74,
-      74
+       0,    48,    49,    50,    50,    51,    51,    52,    52,    53,
+      53,    53,    53,    53,    54,    55,    55,    56,    56,    56,
+      56,    57,    57,    57,    57,    57,    57,    57,    58,    58,
+      58,    59,    59,    59,    59,    59,    60,    60,    60,    61,
+      62,    62,    63,    63,    64,    64,    65,    65,    66,    66,
+      67,    67,    68,    68,    68,    69,    69,    69,    69,    69,
+      70,    70,    70,    71,    71,    71,    72,    72,    72,    72,
+      73,    73,    73,    73,    74,    74,    74,    75,    75,    75,
+      76,    76,    76
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     4,     0,     2,     4,     2,     2,     3,     4,
-       3,     4,     5,     0,     2,     4,     2,     3,     2,     2,
-       3,     4,     2,     9,     5,     2,     0,     2,     2,     3,
-       1,     2,     2,     2,     1,     1,     3,     1,     1,     5,
-       1,     3,     1,     3,     1,     3,     1,     3,     1,     3,
-       1,     3,     3,     1,     3,     3,     3,     3,     3,     3,
-       1,     3,     3,     1,     3,     3,     3,     1,     1,     2,
-       2,     2,     0,     2,     2,     0,     2,     2,     2,     3,
-       2
+       0,     2,     5,     0,     2,     0,     2,     4,     2,     2,
+       3,     4,     3,     4,     5,     0,     2,     4,     2,     3,
+       2,     2,     3,     4,     2,     9,     5,     2,     0,     2,
+       2,     3,     1,     2,     2,     2,     1,     1,     3,     1,
+       1,     5,     1,     3,     1,     3,     1,     3,     1,     3,
+       1,     3,     1,     3,     3,     1,     3,     3,     3,     3,
+       3,     3,     1,     3,     3,     1,     3,     3,     3,     1,
+       1,     2,     2,     2,     0,     2,     2,     0,     2,     2,
+       2,     3,     2
 };
 
 
@@ -1463,65 +1468,82 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-#line 105 "dtc-parser.y" /* yacc.c:1646  */
+#line 109 "dtc-parser.y" /* yacc.c:1646  */
     {
+			(yyvsp[0].node)->is_plugin = (yyvsp[-2].is_plugin);
 			the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node),
 							guess_boot_cpuid((yyvsp[0].node)));
 		}
-#line 1472 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1478 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
   case 3:
-#line 113 "dtc-parser.y" /* yacc.c:1646  */
+#line 118 "dtc-parser.y" /* yacc.c:1646  */
     {
-			(yyval.re) = NULL;
+			(yyval.is_plugin) = false;
 		}
-#line 1480 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1486 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
   case 4:
-#line 117 "dtc-parser.y" /* yacc.c:1646  */
+#line 122 "dtc-parser.y" /* yacc.c:1646  */
     {
-			(yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re));
+			(yyval.is_plugin) = true;
 		}
-#line 1488 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1494 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
   case 5:
-#line 124 "dtc-parser.y" /* yacc.c:1646  */
+#line 129 "dtc-parser.y" /* yacc.c:1646  */
     {
-			(yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer));
+			(yyval.re) = NULL;
 		}
-#line 1496 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1502 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
   case 6:
-#line 128 "dtc-parser.y" /* yacc.c:1646  */
+#line 133 "dtc-parser.y" /* yacc.c:1646  */
+    {
+			(yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re));
+		}
+#line 1510 "dtc-parser.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 7:
+#line 140 "dtc-parser.y" /* yacc.c:1646  */
+    {
+			(yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer));
+		}
+#line 1518 "dtc-parser.tab.c" /* yacc.c:1646  */
+    break;
+
+  case 8:
+#line 144 "dtc-parser.y" /* yacc.c:1646  */
     {
 			add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref));
 			(yyval.re) = (yyvsp[0].re);
 		}
-#line 1505 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1527 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 7:
-#line 136 "dtc-parser.y" /* yacc.c:1646  */
+  case 9:
+#line 152 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.node) = name_node((yyvsp[0].node), "");
 		}
-#line 1513 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1535 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 8:
-#line 140 "dtc-parser.y" /* yacc.c:1646  */
+  case 10:
+#line 156 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node));
 		}
-#line 1521 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1543 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 9:
-#line 145 "dtc-parser.y" /* yacc.c:1646  */
+  case 11:
+#line 161 "dtc-parser.y" /* yacc.c:1646  */
     {
 			struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
 
@@ -1532,11 +1554,11 @@ yyreduce:
 				ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
 			(yyval.node) = (yyvsp[-3].node);
 		}
-#line 1536 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1558 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 10:
-#line 156 "dtc-parser.y" /* yacc.c:1646  */
+  case 12:
+#line 172 "dtc-parser.y" /* yacc.c:1646  */
     {
 			struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref));
 
@@ -1546,11 +1568,11 @@ yyreduce:
 				ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
 			(yyval.node) = (yyvsp[-2].node);
 		}
-#line 1550 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1572 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 11:
-#line 166 "dtc-parser.y" /* yacc.c:1646  */
+  case 13:
+#line 182 "dtc-parser.y" /* yacc.c:1646  */
     {
 			struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
 
@@ -1562,100 +1584,100 @@ yyreduce:
 
 			(yyval.node) = (yyvsp[-3].node);
 		}
-#line 1566 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1588 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 12:
-#line 181 "dtc-parser.y" /* yacc.c:1646  */
+  case 14:
+#line 197 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist));
 		}
-#line 1574 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1596 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 13:
-#line 188 "dtc-parser.y" /* yacc.c:1646  */
+  case 15:
+#line 204 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.proplist) = NULL;
 		}
-#line 1582 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1604 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 14:
-#line 192 "dtc-parser.y" /* yacc.c:1646  */
+  case 16:
+#line 208 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist));
 		}
-#line 1590 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1612 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 15:
-#line 199 "dtc-parser.y" /* yacc.c:1646  */
+  case 17:
+#line 215 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data));
 		}
-#line 1598 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1620 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 16:
-#line 203 "dtc-parser.y" /* yacc.c:1646  */
+  case 18:
+#line 219 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data);
 		}
-#line 1606 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1628 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 17:
-#line 207 "dtc-parser.y" /* yacc.c:1646  */
+  case 19:
+#line 223 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.prop) = build_property_delete((yyvsp[-1].propnodename));
 		}
-#line 1614 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1636 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 18:
-#line 211 "dtc-parser.y" /* yacc.c:1646  */
+  case 20:
+#line 227 "dtc-parser.y" /* yacc.c:1646  */
     {
 			add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref));
 			(yyval.prop) = (yyvsp[0].prop);
 		}
-#line 1623 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1645 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 19:
-#line 219 "dtc-parser.y" /* yacc.c:1646  */
+  case 21:
+#line 235 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data));
 		}
-#line 1631 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1653 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 20:
-#line 223 "dtc-parser.y" /* yacc.c:1646  */
+  case 22:
+#line 239 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data);
 		}
-#line 1639 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1661 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 21:
-#line 227 "dtc-parser.y" /* yacc.c:1646  */
+  case 23:
+#line 243 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data));
 		}
-#line 1647 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1669 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 22:
-#line 231 "dtc-parser.y" /* yacc.c:1646  */
+  case 24:
+#line 247 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref));
 		}
-#line 1655 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1677 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 23:
-#line 235 "dtc-parser.y" /* yacc.c:1646  */
+  case 25:
+#line 251 "dtc-parser.y" /* yacc.c:1646  */
     {
 			FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL);
 			struct data d;
@@ -1671,11 +1693,11 @@ yyreduce:
 			(yyval.data) = data_merge((yyvsp[-8].data), d);
 			fclose(f);
 		}
-#line 1675 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1697 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 24:
-#line 251 "dtc-parser.y" /* yacc.c:1646  */
+  case 26:
+#line 267 "dtc-parser.y" /* yacc.c:1646  */
     {
 			FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL);
 			struct data d = empty_data;
@@ -1685,43 +1707,43 @@ yyreduce:
 			(yyval.data) = data_merge((yyvsp[-4].data), d);
 			fclose(f);
 		}
-#line 1689 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1711 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 25:
-#line 261 "dtc-parser.y" /* yacc.c:1646  */
+  case 27:
+#line 277 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
 		}
-#line 1697 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1719 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 26:
-#line 268 "dtc-parser.y" /* yacc.c:1646  */
+  case 28:
+#line 284 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = empty_data;
 		}
-#line 1705 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1727 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 27:
-#line 272 "dtc-parser.y" /* yacc.c:1646  */
+  case 29:
+#line 288 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = (yyvsp[-1].data);
 		}
-#line 1713 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1735 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 28:
-#line 276 "dtc-parser.y" /* yacc.c:1646  */
+  case 30:
+#line 292 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
 		}
-#line 1721 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1743 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 29:
-#line 283 "dtc-parser.y" /* yacc.c:1646  */
+  case 31:
+#line 299 "dtc-parser.y" /* yacc.c:1646  */
     {
 			unsigned long long bits;
 
@@ -1737,20 +1759,20 @@ yyreduce:
 			(yyval.array).data = empty_data;
 			(yyval.array).bits = bits;
 		}
-#line 1741 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1763 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 30:
-#line 299 "dtc-parser.y" /* yacc.c:1646  */
+  case 32:
+#line 315 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.array).data = empty_data;
 			(yyval.array).bits = 32;
 		}
-#line 1750 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1772 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 31:
-#line 304 "dtc-parser.y" /* yacc.c:1646  */
+  case 33:
+#line 320 "dtc-parser.y" /* yacc.c:1646  */
     {
 			if ((yyvsp[-1].array).bits < 64) {
 				uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1;
@@ -1769,11 +1791,11 @@ yyreduce:
 
 			(yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits);
 		}
-#line 1773 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1795 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 32:
-#line 323 "dtc-parser.y" /* yacc.c:1646  */
+  case 34:
+#line 339 "dtc-parser.y" /* yacc.c:1646  */
     {
 			uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits);
 
@@ -1787,129 +1809,129 @@ yyreduce:
 
 			(yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits);
 		}
-#line 1791 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1813 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 33:
-#line 337 "dtc-parser.y" /* yacc.c:1646  */
+  case 35:
+#line 353 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref));
 		}
-#line 1799 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1821 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 36:
-#line 346 "dtc-parser.y" /* yacc.c:1646  */
+  case 38:
+#line 362 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.integer) = (yyvsp[-1].integer);
 		}
-#line 1807 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1829 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 39:
-#line 357 "dtc-parser.y" /* yacc.c:1646  */
+  case 41:
+#line 373 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); }
-#line 1813 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1835 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 41:
-#line 362 "dtc-parser.y" /* yacc.c:1646  */
+  case 43:
+#line 378 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); }
-#line 1819 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1841 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 43:
-#line 367 "dtc-parser.y" /* yacc.c:1646  */
+  case 45:
+#line 383 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); }
-#line 1825 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1847 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 45:
-#line 372 "dtc-parser.y" /* yacc.c:1646  */
+  case 47:
+#line 388 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); }
-#line 1831 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1853 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 47:
-#line 377 "dtc-parser.y" /* yacc.c:1646  */
+  case 49:
+#line 393 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); }
-#line 1837 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1859 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 49:
-#line 382 "dtc-parser.y" /* yacc.c:1646  */
+  case 51:
+#line 398 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); }
-#line 1843 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1865 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 51:
-#line 387 "dtc-parser.y" /* yacc.c:1646  */
+  case 53:
+#line 403 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); }
-#line 1849 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1871 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 52:
-#line 388 "dtc-parser.y" /* yacc.c:1646  */
+  case 54:
+#line 404 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); }
-#line 1855 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1877 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 54:
-#line 393 "dtc-parser.y" /* yacc.c:1646  */
+  case 56:
+#line 409 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); }
-#line 1861 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1883 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 55:
-#line 394 "dtc-parser.y" /* yacc.c:1646  */
+  case 57:
+#line 410 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); }
-#line 1867 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1889 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 56:
-#line 395 "dtc-parser.y" /* yacc.c:1646  */
+  case 58:
+#line 411 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); }
-#line 1873 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1895 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 57:
-#line 396 "dtc-parser.y" /* yacc.c:1646  */
+  case 59:
+#line 412 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); }
-#line 1879 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1901 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 58:
-#line 400 "dtc-parser.y" /* yacc.c:1646  */
+  case 60:
+#line 416 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); }
-#line 1885 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1907 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 59:
-#line 401 "dtc-parser.y" /* yacc.c:1646  */
+  case 61:
+#line 417 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); }
-#line 1891 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1913 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 61:
-#line 406 "dtc-parser.y" /* yacc.c:1646  */
+  case 63:
+#line 422 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); }
-#line 1897 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1919 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 62:
-#line 407 "dtc-parser.y" /* yacc.c:1646  */
+  case 64:
+#line 423 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); }
-#line 1903 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1925 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 64:
-#line 412 "dtc-parser.y" /* yacc.c:1646  */
+  case 66:
+#line 428 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); }
-#line 1909 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1931 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 65:
-#line 414 "dtc-parser.y" /* yacc.c:1646  */
+  case 67:
+#line 430 "dtc-parser.y" /* yacc.c:1646  */
     {
 			if ((yyvsp[0].integer) != 0) {
 				(yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer);
@@ -1918,11 +1940,11 @@ yyreduce:
 				(yyval.integer) = 0;
 			}
 		}
-#line 1922 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1944 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 66:
-#line 423 "dtc-parser.y" /* yacc.c:1646  */
+  case 68:
+#line 439 "dtc-parser.y" /* yacc.c:1646  */
     {
 			if ((yyvsp[0].integer) != 0) {
 				(yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer);
@@ -1931,103 +1953,103 @@ yyreduce:
 				(yyval.integer) = 0;
 			}
 		}
-#line 1935 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1957 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 69:
-#line 436 "dtc-parser.y" /* yacc.c:1646  */
+  case 71:
+#line 452 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = -(yyvsp[0].integer); }
-#line 1941 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1963 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 70:
-#line 437 "dtc-parser.y" /* yacc.c:1646  */
+  case 72:
+#line 453 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = ~(yyvsp[0].integer); }
-#line 1947 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1969 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 71:
-#line 438 "dtc-parser.y" /* yacc.c:1646  */
+  case 73:
+#line 454 "dtc-parser.y" /* yacc.c:1646  */
     { (yyval.integer) = !(yyvsp[0].integer); }
-#line 1953 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1975 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 72:
-#line 443 "dtc-parser.y" /* yacc.c:1646  */
+  case 74:
+#line 459 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = empty_data;
 		}
-#line 1961 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1983 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 73:
-#line 447 "dtc-parser.y" /* yacc.c:1646  */
+  case 75:
+#line 463 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte));
 		}
-#line 1969 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1991 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 74:
-#line 451 "dtc-parser.y" /* yacc.c:1646  */
+  case 76:
+#line 467 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
 		}
-#line 1977 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 1999 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 75:
-#line 458 "dtc-parser.y" /* yacc.c:1646  */
+  case 77:
+#line 474 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.nodelist) = NULL;
 		}
-#line 1985 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2007 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 76:
-#line 462 "dtc-parser.y" /* yacc.c:1646  */
+  case 78:
+#line 478 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist));
 		}
-#line 1993 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2015 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 77:
-#line 466 "dtc-parser.y" /* yacc.c:1646  */
+  case 79:
+#line 482 "dtc-parser.y" /* yacc.c:1646  */
     {
 			ERROR(&(yylsp[0]), "Properties must precede subnodes");
 			YYERROR;
 		}
-#line 2002 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2024 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 78:
-#line 474 "dtc-parser.y" /* yacc.c:1646  */
+  case 80:
+#line 490 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename));
 		}
-#line 2010 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2032 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 79:
-#line 478 "dtc-parser.y" /* yacc.c:1646  */
+  case 81:
+#line 494 "dtc-parser.y" /* yacc.c:1646  */
     {
 			(yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename));
 		}
-#line 2018 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2040 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
-  case 80:
-#line 482 "dtc-parser.y" /* yacc.c:1646  */
+  case 82:
+#line 498 "dtc-parser.y" /* yacc.c:1646  */
     {
 			add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref));
 			(yyval.node) = (yyvsp[0].node);
 		}
-#line 2027 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2049 "dtc-parser.tab.c" /* yacc.c:1646  */
     break;
 
 
-#line 2031 "dtc-parser.tab.c" /* yacc.c:1646  */
+#line 2053 "dtc-parser.tab.c" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -2262,7 +2284,7 @@ yyreturn:
 #endif
   return yyresult;
 }
-#line 488 "dtc-parser.y" /* yacc.c:1906  */
+#line 504 "dtc-parser.y" /* yacc.c:1906  */
 
 
 void yyerror(char const *s)
diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped
index 30867c6..c2a4246 100644
--- a/scripts/dtc/dtc-parser.tab.h_shipped
+++ b/scripts/dtc/dtc-parser.tab.h_shipped
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.0.2.  */
+/* A Bison parser, made by GNU Bison 3.0.4.  */
 
 /* Bison interface for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
 
    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
@@ -46,35 +46,36 @@ extern int yydebug;
   enum yytokentype
   {
     DT_V1 = 258,
-    DT_MEMRESERVE = 259,
-    DT_LSHIFT = 260,
-    DT_RSHIFT = 261,
-    DT_LE = 262,
-    DT_GE = 263,
-    DT_EQ = 264,
-    DT_NE = 265,
-    DT_AND = 266,
-    DT_OR = 267,
-    DT_BITS = 268,
-    DT_DEL_PROP = 269,
-    DT_DEL_NODE = 270,
-    DT_PROPNODENAME = 271,
-    DT_LITERAL = 272,
-    DT_CHAR_LITERAL = 273,
-    DT_BYTE = 274,
-    DT_STRING = 275,
-    DT_LABEL = 276,
-    DT_REF = 277,
-    DT_INCBIN = 278
+    DT_PLUGIN = 259,
+    DT_MEMRESERVE = 260,
+    DT_LSHIFT = 261,
+    DT_RSHIFT = 262,
+    DT_LE = 263,
+    DT_GE = 264,
+    DT_EQ = 265,
+    DT_NE = 266,
+    DT_AND = 267,
+    DT_OR = 268,
+    DT_BITS = 269,
+    DT_DEL_PROP = 270,
+    DT_DEL_NODE = 271,
+    DT_PROPNODENAME = 272,
+    DT_LITERAL = 273,
+    DT_CHAR_LITERAL = 274,
+    DT_BYTE = 275,
+    DT_STRING = 276,
+    DT_LABEL = 277,
+    DT_REF = 278,
+    DT_INCBIN = 279
   };
 #endif
 
 /* Value type.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE YYSTYPE;
+
 union YYSTYPE
 {
-#line 38 "dtc-parser.y" /* yacc.c:1909  */
+#line 39 "dtc-parser.y" /* yacc.c:1909  */
 
 	char *propnodename;
 	char *labelref;
@@ -92,9 +93,12 @@ union YYSTYPE
 	struct node *nodelist;
 	struct reserve_info *re;
 	uint64_t integer;
+	bool is_plugin;
 
-#line 97 "dtc-parser.tab.h" /* yacc.c:1909  */
+#line 99 "dtc-parser.tab.h" /* yacc.c:1909  */
 };
+
+typedef union YYSTYPE YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1
 #endif
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
index 000873f..bd67bac 100644
--- a/scripts/dtc/dtc-parser.y
+++ b/scripts/dtc/dtc-parser.y
@@ -19,6 +19,7 @@
  */
 %{
 #include <stdio.h>
+#include <inttypes.h>
 
 #include "dtc.h"
 #include "srcpos.h"
@@ -52,9 +53,11 @@ extern bool treesource_error;
 	struct node *nodelist;
 	struct reserve_info *re;
 	uint64_t integer;
+	bool is_plugin;
 }
 
 %token DT_V1
+%token DT_PLUGIN
 %token DT_MEMRESERVE
 %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
 %token DT_BITS
@@ -71,6 +74,7 @@ extern bool treesource_error;
 
 %type <data> propdata
 %type <data> propdataprefix
+%type <is_plugin> plugindecl
 %type <re> memreserve
 %type <re> memreserves
 %type <array> arrayprefix
@@ -101,10 +105,22 @@ extern bool treesource_error;
 %%
 
 sourcefile:
-	  DT_V1 ';' memreserves devicetree
+	  DT_V1 ';' plugindecl memreserves devicetree
 		{
-			the_boot_info = build_boot_info($3, $4,
-							guess_boot_cpuid($4));
+			$5->is_plugin = $3;
+			the_boot_info = build_boot_info($4, $5,
+							guess_boot_cpuid($5));
+		}
+	;
+
+plugindecl:
+	/* empty */
+		{
+			$$ = false;
+		}
+	| DT_PLUGIN ';'
+		{
+			$$ = true;
 		}
 	;
 
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index 5fa23c4..1f8c285 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -31,6 +31,7 @@ int reservenum;		/* Number of memory reservation slots */
 int minsize;		/* Minimum blob size */
 int padsize;		/* Additional padding to blob */
 int phandle_format = PHANDLE_BOTH;	/* Use linux,phandle or phandle properties */
+int symbol_fixup_support = 0;
 
 static void fill_fullpaths(struct node *tree, const char *prefix)
 {
@@ -53,7 +54,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
 #define FDT_VERSION(version)	_FDT_VERSION(version)
 #define _FDT_VERSION(version)	#version
 static const char usage_synopsis[] = "dtc [options] <input file>";
-static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
+static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:@hv";
 static struct option const usage_long_opts[] = {
 	{"quiet",            no_argument, NULL, 'q'},
 	{"in-format",         a_argument, NULL, 'I'},
@@ -71,6 +72,7 @@ static struct option const usage_long_opts[] = {
 	{"phandle",           a_argument, NULL, 'H'},
 	{"warning",           a_argument, NULL, 'W'},
 	{"error",             a_argument, NULL, 'E'},
+	{"symbols",	     no_argument, NULL, '@'},
 	{"help",             no_argument, NULL, 'h'},
 	{"version",          no_argument, NULL, 'v'},
 	{NULL,               no_argument, NULL, 0x0},
@@ -101,6 +103,7 @@ static const char * const usage_opts_help[] = {
 	 "\t\tboth   - Both \"linux,phandle\" and \"phandle\" properties",
 	"\n\tEnable/disable warnings (prefix with \"no-\")",
 	"\n\tEnable/disable errors (prefix with \"no-\")",
+	"\n\tEnable symbols/fixup support",
 	"\n\tPrint this help and exit",
 	"\n\tPrint version and exit",
 	NULL,
@@ -233,7 +236,9 @@ int main(int argc, char *argv[])
 		case 'E':
 			parse_checks_option(false, true, optarg);
 			break;
-
+		case '@':
+			symbol_fixup_support = 1;
+			break;
 		case 'h':
 			usage(NULL);
 		default:
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 56212c8..f163b22 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -54,6 +54,7 @@ extern int reservenum;		/* Number of memory reservation slots */
 extern int minsize;		/* Minimum blob size */
 extern int padsize;		/* Additional padding to blob */
 extern int phandle_format;	/* Use linux,phandle or phandle properties */
+extern int symbol_fixup_support;/* enable symbols & fixup support */
 
 #define PHANDLE_LEGACY	0x1
 #define PHANDLE_EPAPR	0x2
@@ -132,6 +133,26 @@ struct label {
 	struct label *next;
 };
 
+struct fixup_entry {
+	int offset;
+	struct node *node;
+	struct property *prop;
+	struct fixup_entry *next;
+	bool local_fixup_generated;
+};
+
+struct fixup {
+	char *ref;
+	struct fixup_entry *entries;
+	struct fixup *next;
+};
+
+struct symbol {
+	struct label *label;
+	struct node *node;
+	struct symbol *next;
+};
+
 struct property {
 	bool deleted;
 	char *name;
@@ -158,6 +179,13 @@ struct node {
 	int addr_cells, size_cells;
 
 	struct label *labels;
+
+	struct symbol *symbols;
+	struct fixup_entry *local_fixups;
+	bool emit_local_fixup_node;
+
+	bool is_plugin;
+	struct fixup *fixups;
 };
 
 #define for_each_label_withdel(l0, l) \
@@ -181,6 +209,18 @@ struct node {
 	for_each_child_withdel(n, c) \
 		if (!(c)->deleted)
 
+#define for_each_fixup(n, f) \
+	for ((f) = (n)->fixups; (f); (f) = (f)->next)
+
+#define for_each_fixup_entry(f, fe) \
+	for ((fe) = (f)->entries; (fe); (fe) = (fe)->next)
+
+#define for_each_symbol(n, s) \
+	for ((s) = (n)->symbols; (s); (s) = (s)->next)
+
+#define for_each_local_fixup_entry(n, fe) \
+	for ((fe) = (n)->local_fixups; (fe); (fe) = (fe)->next)
+
 void add_label(struct label **labels, char *label);
 void delete_labels(struct label **labels);
 
diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
index bd99fa2..f8f1e34 100644
--- a/scripts/dtc/flattree.c
+++ b/scripts/dtc/flattree.c
@@ -255,6 +255,204 @@ static int stringtable_insert(struct data *d, const char *str)
 	return i;
 }
 
+static void emit_local_fixups(struct node *tree, struct emitter *emit,
+		void *etarget, struct data *strbuf, struct version_info *vi,
+		struct node *node)
+{
+	struct fixup_entry *fe, *fen;
+	struct node *child;
+	int nameoff, count;
+	cell_t *buf;
+	struct data d;
+
+	if (node->emit_local_fixup_node) {
+
+		/* emit the external fixups (do not emit /) */
+		if (node != tree) {
+			emit->beginnode(etarget, NULL);
+			emit->string(etarget, node->name, 0);
+			emit->align(etarget, sizeof(cell_t));
+		}
+
+		for_each_local_fixup_entry(tree, fe) {
+			if (fe->node != node || fe->local_fixup_generated)
+				continue;
+
+			/* count the number of fixup entries */
+			count = 0;
+			for_each_local_fixup_entry(tree, fen) {
+				if (fen->prop != fe->prop)
+					continue;
+				fen->local_fixup_generated = true;
+				count++;
+			}
+
+			/* allocate buffer */
+			buf = xmalloc(count * sizeof(cell_t));
+
+			/* collect all the offsets in buffer */
+			count = 0;
+			for_each_local_fixup_entry(tree, fen) {
+				if (fen->prop != fe->prop)
+					continue;
+				fen->local_fixup_generated = true;
+				buf[count++] = cpu_to_fdt32(fen->offset);
+			}
+			d = empty_data;
+			d.len = count * sizeof(cell_t);
+			d.val = (char *)buf;
+
+			nameoff = stringtable_insert(strbuf, fe->prop->name);
+			emit->property(etarget, fe->prop->labels);
+			emit->cell(etarget, count * sizeof(cell_t));
+			emit->cell(etarget, nameoff);
+
+			if ((vi->flags & FTF_VARALIGN) &&
+					(count * sizeof(cell_t)) >= 8)
+				emit->align(etarget, 8);
+
+			emit->data(etarget, d);
+			emit->align(etarget, sizeof(cell_t));
+
+			free(buf);
+		}
+	}
+
+	for_each_child(node, child)
+		emit_local_fixups(tree, emit, etarget, strbuf, vi, child);
+
+	if (node->emit_local_fixup_node && node != tree)
+		emit->endnode(etarget, tree->labels);
+}
+
+static void emit_symbols_node(struct node *tree, struct emitter *emit,
+			      void *etarget, struct data *strbuf,
+			      struct version_info *vi)
+{
+	struct symbol *sym;
+	int nameoff, vallen;
+
+	/* do nothing if no symbols */
+	if (!tree->symbols)
+		return;
+
+	emit->beginnode(etarget, NULL);
+	emit->string(etarget, "__symbols__", 0);
+	emit->align(etarget, sizeof(cell_t));
+
+	for_each_symbol(tree, sym) {
+
+		vallen = strlen(sym->node->fullpath);
+
+		nameoff = stringtable_insert(strbuf, sym->label->label);
+
+		emit->property(etarget, NULL);
+		emit->cell(etarget, vallen + 1);
+		emit->cell(etarget, nameoff);
+
+		if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
+			emit->align(etarget, 8);
+
+		emit->string(etarget, sym->node->fullpath,
+				strlen(sym->node->fullpath));
+		emit->align(etarget, sizeof(cell_t));
+	}
+
+	emit->endnode(etarget, NULL);
+}
+
+static void emit_local_fixups_node(struct node *tree, struct emitter *emit,
+				   void *etarget, struct data *strbuf,
+				   struct version_info *vi)
+{
+	struct fixup_entry *fe;
+	struct node *node;
+
+	/* do nothing if no local fixups */
+	if (!tree->local_fixups)
+		return;
+
+	/* mark all nodes that need a local fixup generated (and parents) */
+	for_each_local_fixup_entry(tree, fe) {
+		node = fe->node;
+		while (node != NULL && !node->emit_local_fixup_node) {
+			node->emit_local_fixup_node = true;
+			node = node->parent;
+		}
+	}
+
+	/* emit the local fixups node now */
+	emit->beginnode(etarget, NULL);
+	emit->string(etarget, "__local_fixups__", 0);
+	emit->align(etarget, sizeof(cell_t));
+
+	emit_local_fixups(tree, emit, etarget, strbuf, vi, tree);
+
+	emit->endnode(etarget, tree->labels);
+}
+
+static void emit_fixups_node(struct node *tree, struct emitter *emit,
+			     void *etarget, struct data *strbuf,
+			     struct version_info *vi)
+{
+	struct fixup *f;
+	struct fixup_entry *fe;
+	char *name, *s;
+	const char *fullpath;
+	int namesz, nameoff, vallen;
+
+	/* do nothing if no fixups */
+	if (!tree->fixups)
+		return;
+
+	/* emit the external fixups */
+	emit->beginnode(etarget, NULL);
+	emit->string(etarget, "__fixups__", 0);
+	emit->align(etarget, sizeof(cell_t));
+
+	for_each_fixup(tree, f) {
+
+		namesz = 0;
+		for_each_fixup_entry(f, fe) {
+			fullpath = fe->node->fullpath;
+			if (fullpath[0] == '\0')
+				fullpath = "/";
+			namesz += strlen(fullpath) + 1;
+			namesz += strlen(fe->prop->name) + 1;
+			namesz += 32;	/* space for :<number> + '\0' */
+		}
+
+		name = xmalloc(namesz);
+
+		s = name;
+		for_each_fixup_entry(f, fe) {
+			fullpath = fe->node->fullpath;
+			if (fullpath[0] == '\0')
+				fullpath = "/";
+			snprintf(s, name + namesz - s, "%s:%s:%d", fullpath,
+					fe->prop->name, fe->offset);
+			s += strlen(s) + 1;
+		}
+
+		nameoff = stringtable_insert(strbuf, f->ref);
+		vallen = s - name - 1;
+
+		emit->property(etarget, NULL);
+		emit->cell(etarget, vallen + 1);
+		emit->cell(etarget, nameoff);
+
+		if ((vi->flags & FTF_VARALIGN) && vallen >= 8)
+			emit->align(etarget, 8);
+
+		emit->string(etarget, name, vallen);
+		emit->align(etarget, sizeof(cell_t));
+
+		free(name);
+	}
+
+	emit->endnode(etarget, tree->labels);
+}
+
 static void flatten_tree(struct node *tree, struct emitter *emit,
 			 void *etarget, struct data *strbuf,
 			 struct version_info *vi)
@@ -310,6 +508,10 @@ static void flatten_tree(struct node *tree, struct emitter *emit,
 		flatten_tree(child, emit, etarget, strbuf, vi);
 	}
 
+	emit_symbols_node(tree, emit, etarget, strbuf, vi);
+	emit_local_fixups_node(tree, emit, etarget, strbuf, vi);
+	emit_fixups_node(tree, emit, etarget, strbuf, vi);
+
 	emit->endnode(etarget, tree->labels);
 }
 
@@ -889,7 +1091,7 @@ struct boot_info *dt_from_blob(const char *fname)
 
 	if (version >= 3) {
 		uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
-		if (off_str+size_str > totalsize)
+		if ((off_str+size_str < off_str) || (off_str+size_str > totalsize))
 			die("String table extends past total size\n");
 		inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
 	} else {
@@ -898,7 +1100,7 @@ struct boot_info *dt_from_blob(const char *fname)
 
 	if (version >= 17) {
 		size_dt = fdt32_to_cpu(fdt->size_dt_struct);
-		if (off_dt+size_dt > totalsize)
+		if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize))
 			die("Structure block extends past total size\n");
 	}
 
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index e5b3136..50cce86 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -647,10 +647,8 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
 	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
 	if (!prop)
 		return len;
-	if (fdt_stringlist_contains(prop, len, compatible))
-		return 0;
-	else
-		return 1;
+
+	return !fdt_stringlist_contains(prop, len, compatible);
 }
 
 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
index 59ca339..f7e3989 100644
--- a/scripts/dtc/libfdt/libfdt.h
+++ b/scripts/dtc/libfdt/libfdt.h
@@ -174,21 +174,21 @@ int fdt_next_subnode(const void *fdt, int offset);
 
 #define fdt_get_header(fdt, field) \
 	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
-#define fdt_magic(fdt) 			(fdt_get_header(fdt, magic))
+#define fdt_magic(fdt)			(fdt_get_header(fdt, magic))
 #define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))
 #define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))
 #define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings))
 #define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap))
 #define fdt_version(fdt)		(fdt_get_header(fdt, version))
-#define fdt_last_comp_version(fdt) 	(fdt_get_header(fdt, last_comp_version))
-#define fdt_boot_cpuid_phys(fdt) 	(fdt_get_header(fdt, boot_cpuid_phys))
-#define fdt_size_dt_strings(fdt) 	(fdt_get_header(fdt, size_dt_strings))
+#define fdt_last_comp_version(fdt)	(fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt)	(fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt)	(fdt_get_header(fdt, size_dt_strings))
 #define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
 
 #define __fdt_set_hdr(name) \
 	static inline void fdt_set_##name(void *fdt, uint32_t val) \
 	{ \
-		struct fdt_header *fdth = (struct fdt_header*)fdt; \
+		struct fdt_header *fdth = (struct fdt_header *)fdt; \
 		fdth->name = cpu_to_fdt32(val); \
 	}
 __fdt_set_hdr(magic);
@@ -318,8 +318,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
  * returns:
  *	structure block offset of the requested subnode (>=0), on success
  *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
- *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
- *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ *		tag
+ *	-FDT_ERR_BADMAGIC,
  *	-FDT_ERR_BADVERSION,
  *	-FDT_ERR_BADSTATE,
  *	-FDT_ERR_BADSTRUCTURE,
@@ -351,7 +352,8 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
  * address).
  *
  * returns:
- *	structure block offset of the node with the requested path (>=0), on success
+ *	structure block offset of the node with the requested path (>=0), on
+ *		success
  *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
  *	-FDT_ERR_NOTFOUND, if the requested node does not exist
  *      -FDT_ERR_BADMAGIC,
@@ -375,10 +377,12 @@ int fdt_path_offset(const void *fdt, const char *path);
  *
  * returns:
  *	pointer to the node's name, on success
- *		If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ *		If lenp is non-NULL, *lenp contains the length of that name
+ *			(>=0)
  *	NULL, on error
  *		if lenp is non-NULL *lenp contains an error code (<0):
- *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *			tag
  *		-FDT_ERR_BADMAGIC,
  *		-FDT_ERR_BADVERSION,
  *		-FDT_ERR_BADSTATE, standard meanings
@@ -490,7 +494,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
  *	NULL, on error
  *		if lenp is non-NULL, *lenp contains an error code (<0):
  *		-FDT_ERR_NOTFOUND, node does not have named property
- *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *			tag
  *		-FDT_ERR_BADMAGIC,
  *		-FDT_ERR_BADVERSION,
  *		-FDT_ERR_BADSTATE,
@@ -575,7 +580,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
  *	NULL, on error
  *		if lenp is non-NULL, *lenp contains an error code (<0):
  *		-FDT_ERR_NOTFOUND, node does not have named property
- *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *			tag
  *		-FDT_ERR_BADMAGIC,
  *		-FDT_ERR_BADVERSION,
  *		-FDT_ERR_BADSTATE,
@@ -647,7 +653,7 @@ const char *fdt_get_alias(const void *fdt, const char *name);
  *	0, on success
  *		buf contains the absolute path of the node at
  *		nodeoffset, as a NUL-terminated string.
- * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
  *		characters and will not fit in the given buffer.
  *	-FDT_ERR_BADMAGIC,
@@ -677,11 +683,11 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
  * structure from the start to nodeoffset.
  *
  * returns:
-
  *	structure block offset of the node at node offset's ancestor
  *		of depth supernodedepth (>=0), on success
- * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
-*	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
+ *		nodeoffset
  *	-FDT_ERR_BADMAGIC,
  *	-FDT_ERR_BADVERSION,
  *	-FDT_ERR_BADSTATE,
@@ -703,7 +709,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
  *
  * returns:
  *	depth of the node at nodeoffset (>=0), on success
- * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *	-FDT_ERR_BADMAGIC,
  *	-FDT_ERR_BADVERSION,
  *	-FDT_ERR_BADSTATE,
@@ -726,7 +732,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset);
  * returns:
  *	structure block offset of the parent of the node at nodeoffset
  *		(>=0), on success
- * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *	-FDT_ERR_BADMAGIC,
  *	-FDT_ERR_BADVERSION,
  *	-FDT_ERR_BADSTATE,
@@ -766,7 +772,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset);
  *		 on success
  *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
  *		tree after startoffset
- * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *	-FDT_ERR_BADMAGIC,
  *	-FDT_ERR_BADVERSION,
  *	-FDT_ERR_BADSTATE,
@@ -813,7 +819,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
  *	1, if the node has a 'compatible' property, but it does not list
  *		the given string
  *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
- * 	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
  *	-FDT_ERR_BADMAGIC,
  *	-FDT_ERR_BADVERSION,
  *	-FDT_ERR_BADSTATE,
@@ -850,7 +856,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
  *		 on success
  *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
  *		tree after startoffset
- * 	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
  *	-FDT_ERR_BADMAGIC,
  *	-FDT_ERR_BADVERSION,
  *	-FDT_ERR_BADSTATE,
@@ -960,7 +966,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
  * returns:
  *	0 <= n < FDT_MAX_NCELLS, on success
  *      2, if the node has no #address-cells property
- *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *		#address-cells property
  *	-FDT_ERR_BADMAGIC,
  *	-FDT_ERR_BADVERSION,
  *	-FDT_ERR_BADSTATE,
@@ -980,7 +987,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
  * returns:
  *	0 <= n < FDT_MAX_NCELLS, on success
  *      2, if the node has no #address-cells property
- *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *		#size-cells property
  *	-FDT_ERR_BADMAGIC,
  *	-FDT_ERR_BADVERSION,
  *	-FDT_ERR_BADSTATE,
@@ -1604,9 +1612,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
  * change the offsets of some existing nodes.
 
  * returns:
- *	structure block offset of the created nodeequested subnode (>=0), on success
+ *	structure block offset of the created nodeequested subnode (>=0), on
+ *		success
  *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
- *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ *		tag
  *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
  *		the given name
  *	-FDT_ERR_NOSPACE, if there is insufficient free space in the
diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
index 11d93e6..d2c2bd3 100644
--- a/scripts/dtc/version_gen.h
+++ b/scripts/dtc/version_gen.h
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.4.1-gb06e55c8"
+#define DTC_VERSION "DTC 1.4.1-g640cd742"
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 6c3b038..ffae0f7 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -26,6 +26,8 @@ create_package() {
 	# Fix ownership and permissions
 	chown -R root:root "$pdir"
 	chmod -R go-w "$pdir"
+	# in case we are in a restrictive umask environment like 0077
+	chmod -R a+rX "$pdir"
 
 	# Create the package
 	dpkg-gencontrol $forcearch -Vkernel:debarch="${debarch}" -p$pname -P"$pdir"
@@ -149,9 +151,18 @@ else
 fi
 
 if grep -q "^CONFIG_OF=y" $KCONFIG_CONFIG ; then
+	mkdir -p "$tmpdir/boot/dtbs/$version"
 	# Only some architectures with OF support have this target
 	if grep -q dtbs_install "${srctree}/arch/$SRCARCH/Makefile"; then
-		$MAKE KBUILD_SRC= INSTALL_DTBS_PATH="$tmpdir/usr/lib/$packagename" dtbs_install
+		$MAKE KBUILD_SRC= INSTALL_DTBS_PATH="$tmpdir/boot/dtbs/$version" dtbs_install
+	else
+		$MAKE KBUILD_SRC= dtbs
+		find arch/arm/boot/ -iname "*.dtb" -exec cp -v '{}' "$tmpdir/boot/dtbs/$version" \;
+	fi
+
+	#make dtbs_install seems to add an .old directory
+	if [ -d "$tmpdir/boot/dtbs/$version.old" ] ; then
+		rm -rf "$tmpdir/boot/dtbs/$version.old"
 	fi
 fi
 
@@ -238,7 +249,8 @@ maintainer="$name <$email>"
 # Try to determine distribution
 if [ -n "$KDEB_CHANGELOG_DIST" ]; then
         distribution=$KDEB_CHANGELOG_DIST
-elif distribution=$(lsb_release -cs 2>/dev/null) && [ -n "$distribution" ]; then
+# In some cases lsb_release returns the codename as n/a, which breaks dpkg-parsechangelog
+elif distribution=$(lsb_release -cs 2>/dev/null) && [ -n "$distribution" ] && [ "$distribution" != "n/a" ]; then
         : # nothing to do in this case
 else
         distribution="unstable"
@@ -322,10 +334,14 @@ fi
 
 # Build kernel header package
 (cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles"
-(cd $srctree; find arch/$SRCARCH/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles"
+(cd $srctree; find arch/*/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles"
 (cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles"
 (cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles"
+if grep -q '^CONFIG_STACK_VALIDATION=y' $KCONFIG_CONFIG ; then
+	(cd $objtree; find tools/objtool -type f -executable) >> "$objtree/debian/hdrobjfiles"
+fi
 (cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f) >> "$objtree/debian/hdrobjfiles"
+#(cd $objtree; find scripts/gcc-plugins -name \*.so -o -name gcc-common.h) >> "$objtree/debian/hdrobjfiles"
 destdir=$kernel_headers_dir/usr/src/linux-headers-$version
 mkdir -p "$destdir"
 (cd $srctree; tar -c -f - -T -) < "$objtree/debian/hdrsrcfiles" | (cd $destdir; tar -xf -)