summary refs log tree commit diff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-03 12:16:25 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-03 12:16:25 -0700
commitd26f552ebbfb0f2c7fe712f457a038d60ed73daa (patch)
tree8d13c7344cabc99e738e0db7262b713708026fa0 /drivers
parente897f267c51812bfecec45771a2d835c1a2bdacf (diff)
parentab6241ae07c3c698543b565e4ea41995a29a3f62 (diff)
downloadlinux-d26f552ebbfb0f2c7fe712f457a038d60ed73daa.tar.gz
Merge tag 'mfd-next-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
 "New Drivers:
   - Freescale MXS Low Resolution ADC
   - Freescale i.MX23/i.MX28 LRADC touchscreen
   - Motorola CPCAP Power Button
   - TI LMU (Lighting Management Unit)
   - Atmel SMC (Static Memory Controller)

  New Device Support:
   - Add support for X-Powers AXP803 to axp20x
   - Add support for Dialog Semi DA9061 to da9062-core
   - Add support for Intel Cougar Mountain to lpc_ich
   - Add support for Intel Gemini Lake to lpc_ich

  New Functionality:
   - Add Device Tree support; wm831x-*, axp20x, ti-lmu, da9062, sun4i-gpadc
   - Add IRQ sense support; motorola-cpcap
   - Add ACPI support; cros_ec
   - Add Reset support; altera-a10sr
   - Add ADC support; axp20x
   - Add AC Power support; axp20x
   - Add Runtime PM support; atmel-ebi, exynos-lpass
   - Add Battery Power Supply support; axp20x
   - Add Clock support; exynos-lpass, hi655x-pmic

  Fix-ups:
   - Implicitly specify required headers; motorola-cpcap, intel_soc_pmic_bxtwc
   - Add .remove() method; stm32-timers, exynos-lpass
   - Remove unused code; intel_soc_pmic_core, intel-lpss-acpi, ipaq-micro, atmel-smc, menelaus
   - Rename variables for clarity; axp20x
   - Convert pr_warning() to pr_warn(); db8500-prcmu, sta2x11-mfd, twl4030-power
   - Improve formatting; arizona-core, axp20x
   - Use raw_spinlock_*() variants; asic3, t7l66xb, tc6393xb
   - Simplify/refactor code; arizona-core, atmel-ebi
   - Improve error checking; intel_soc_pmic_core

  Bug Fixes:
   - Ensure OMAP3630/3730 boards can successfully reboot; twl4030-power
   - Correct max-register value; stm32-timers
   - Extend timeout to account for clock stretching; cros_ec_spi
   - Use correct IRQ trigger type; motorola-cpcap
   - Fix bad use of IRQ sense register; motorola-cpcap
   - Logic error "||" should be "&&"; mxs-lradc-ts"

* tag 'mfd-next-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (79 commits)
  input: touchscreen: mxs-lradc: || vs && typos
  dt-bindings: Add AXP803's regulator info
  mfd: axp20x: Support AXP803 variant
  dt-bindings: Add device tree binding for X-Powers AXP803 PMIC
  dt-bindings: Make AXP20X compatible strings one per line
  mfd: intel_soc_pmic_core: Fix unchecked return value
  mfd: menelaus: Remove obsolete local_irq_disable() and local_irq_enable()
  mfd: omap-usb-tll: Configure ULPIAUTOIDLE
  mfd: omap-usb-tll: Fix inverted bit use for USB TLL mode
  mfd: palmas: Fixed spelling mistake in error message
  mfd: lpc_ich: Add support for Intel Gemini Lake SoC
  mfd: hi655x: Add the clock cell to provide WiFi and Bluetooth
  mfd: intel_soc_pmic: Fix a mess with compilation units
  mfd: exynos-lpass: Add runtime PM support
  mfd: exynos-lpass: Add missing remove() function
  mfd: exynos-lpass: Add support for clocks
  mfd: exynos-lpass: Remove pad retention control
  iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
  mfd: cpcap: Fix bad use of IRQ sense register
  mfd: cpcap: Use ack_invert interrupts
  ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/gpio/Kconfig2
-rw-r--r--drivers/gpio/gpio-wm831x.c5
-rw-r--r--drivers/iio/adc/Kconfig37
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/axp20x_adc.c617
-rw-r--r--drivers/iio/adc/mxs-lradc-adc.c843
-rw-r--r--drivers/iio/adc/mxs-lradc.c1750
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/cpcap-pwrbutton.c117
-rw-r--r--drivers/input/touchscreen/Kconfig10
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/mxs-lradc-ts.c714
-rw-r--r--drivers/memory/Kconfig1
-rw-r--r--drivers/memory/atmel-ebi.c584
-rw-r--r--drivers/mfd/Kconfig53
-rw-r--r--drivers/mfd/Makefile10
-rw-r--r--drivers/mfd/altera-a10sr.c4
-rw-r--r--drivers/mfd/arizona-core.c44
-rw-r--r--drivers/mfd/asic3.c56
-rw-r--r--drivers/mfd/atmel-smc.c314
-rw-r--r--drivers/mfd/axp20x-rsb.c1
-rw-r--r--drivers/mfd/axp20x.c129
-rw-r--r--drivers/mfd/cros_ec.c15
-rw-r--r--drivers/mfd/cros_ec_acpi_gpe.c103
-rw-r--r--drivers/mfd/cros_ec_spi.c9
-rw-r--r--drivers/mfd/da9062-core.c427
-rw-r--r--drivers/mfd/db8500-prcmu.c2
-rw-r--r--drivers/mfd/exynos-lpass.c50
-rw-r--r--drivers/mfd/hi655x-pmic.c3
-rw-r--r--drivers/mfd/intel-lpss-acpi.c4
-rw-r--r--drivers/mfd/intel_soc_pmic_bxtwc.c25
-rw-r--r--drivers/mfd/intel_soc_pmic_core.c27
-rw-r--r--drivers/mfd/ipaq-micro.c3
-rw-r--r--drivers/mfd/lpc_ich.c12
-rw-r--r--drivers/mfd/menelaus.c4
-rw-r--r--drivers/mfd/motorola-cpcap.c34
-rw-r--r--drivers/mfd/mt6397-core.c3
-rw-r--r--drivers/mfd/mxs-lradc.c267
-rw-r--r--drivers/mfd/omap-usb-tll.c7
-rw-r--r--drivers/mfd/palmas.c16
-rw-r--r--drivers/mfd/rtsx_pcr.c2
-rw-r--r--drivers/mfd/sta2x11-mfd.c4
-rw-r--r--drivers/mfd/stm32-timers.c10
-rw-r--r--drivers/mfd/stmpe.c2
-rw-r--r--drivers/mfd/t7l66xb.c20
-rw-r--r--drivers/mfd/tc6393xb.c52
-rw-r--r--drivers/mfd/ti-lmu.c259
-rw-r--r--drivers/mfd/tps65912-spi.c4
-rw-r--r--drivers/mfd/twl4030-power.c8
-rw-r--r--drivers/mfd/wm831x-core.c29
-rw-r--r--drivers/mfd/wm831x-i2c.c19
-rw-r--r--drivers/mfd/wm831x-irq.c6
-rw-r--r--drivers/mfd/wm831x-spi.c18
-rw-r--r--drivers/platform/x86/Kconfig2
-rw-r--r--drivers/thermal/Kconfig2
57 files changed, 4373 insertions, 2383 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 18f3036fcb82..1ce52f84dc23 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -511,7 +511,7 @@ config XPOWER_PMIC_OPREGION
 
 config BXT_WC_PMIC_OPREGION
 	bool "ACPI operation region support for BXT WhiskeyCove PMIC"
-	depends on INTEL_SOC_PMIC
+	depends on INTEL_SOC_PMIC_BXTWC
 	help
 	  This config adds ACPI operation region support for BXT WhiskeyCove PMIC.
 
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 05043071fc98..9b1bcb4d0df7 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1054,7 +1054,7 @@ config GPIO_UCB1400
 
 config GPIO_WHISKEY_COVE
 	tristate "GPIO support for Whiskey Cove PMIC"
-	depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC
+	depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC_BXTWC
 	select GPIOLIB_IRQCHIP
 	help
 	  Support for GPIO pins on Whiskey Cove PMIC.
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index 00e3839b3f96..938bbe3f831c 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -263,7 +263,7 @@ static const struct gpio_chip template_chip = {
 static int wm831x_gpio_probe(struct platform_device *pdev)
 {
 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
+	struct wm831x_pdata *pdata = &wm831x->pdata;
 	struct wm831x_gpio *wm831x_gpio;
 	int ret;
 
@@ -280,6 +280,9 @@ static int wm831x_gpio_probe(struct platform_device *pdev)
 		wm831x_gpio->gpio_chip.base = pdata->gpio_base;
 	else
 		wm831x_gpio->gpio_chip.base = -1;
+#ifdef CONFIG_OF_GPIO
+	wm831x_gpio->gpio_chip.of_node = wm831x->dev->of_node;
+#endif
 
 	ret = devm_gpiochip_add_data(&pdev->dev, &wm831x_gpio->gpio_chip,
 				     wm831x_gpio);
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index dedae7adbce9..ff5ad3be55b4 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -154,6 +154,16 @@ config AT91_SAMA5D2_ADC
 	  To compile this driver as a module, choose M here: the module will be
 	  called at91-sama5d2_adc.
 
+config AXP20X_ADC
+	tristate "X-Powers AXP20X and AXP22X ADC driver"
+	depends on MFD_AXP20X
+	help
+	  Say yes here to have support for X-Powers power management IC (PMIC)
+	  AXP20X and AXP22X ADC devices.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called axp20x_adc.
+
 config AXP288_ADC
 	tristate "X-Powers AXP288 ADC driver"
 	depends on MFD_AXP20X
@@ -229,6 +239,19 @@ config EXYNOS_ADC
 	  To compile this driver as a module, choose M here: the module will be
 	  called exynos_adc.
 
+config MXS_LRADC_ADC
+	tristate "Freescale i.MX23/i.MX28 LRADC ADC"
+	depends on MFD_MXS_LRADC
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for the ADC functions of the
+	  i.MX23/i.MX28 LRADC. This includes general-purpose ADC readings,
+	  battery voltage measurement, and die temperature measurement.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called mxs-lradc-adc.
+
 config FSL_MX25_ADC
 	tristate "Freescale MX25 ADC driver"
 	depends on MFD_MX25_TSADC
@@ -411,20 +434,6 @@ config MESON_SARADC
 	  To compile this driver as a module, choose M here: the
 	  module will be called meson_saradc.
 
-config MXS_LRADC
-        tristate "Freescale i.MX23/i.MX28 LRADC"
-        depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
-        depends on INPUT
-        select STMP_DEVICE
-        select IIO_BUFFER
-        select IIO_TRIGGERED_BUFFER
-        help
-          Say yes here to build support for i.MX23/i.MX28 LRADC convertor
-          built into these chips.
-
-          To compile this driver as a module, choose M here: the
-          module will be called mxs-lradc.
-
 config NAU7802
 	tristate "Nuvoton NAU7802 ADC driver"
 	depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index d0012620cd1c..a01de757f42c 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
 obj-$(CONFIG_AD799X) += ad799x.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
 obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
+obj-$(CONFIG_AXP20X_ADC) += axp20x_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
@@ -39,7 +40,7 @@ obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
-obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
+obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
 obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
new file mode 100644
index 000000000000..11e177180ea0
--- /dev/null
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -0,0 +1,617 @@
+/* ADC driver for AXP20X and AXP22X PMICs
+ *
+ * Copyright (c) 2016 Free Electrons NextThing Co.
+ *	Quentin Schulz <quentin.schulz@free-electrons.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/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/thermal.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/machine.h>
+#include <linux/mfd/axp20x.h>
+
+#define AXP20X_ADC_EN1_MASK			GENMASK(7, 0)
+
+#define AXP20X_ADC_EN2_MASK			(GENMASK(3, 2) | BIT(7))
+#define AXP22X_ADC_EN1_MASK			(GENMASK(7, 5) | BIT(0))
+
+#define AXP20X_GPIO10_IN_RANGE_GPIO0		BIT(0)
+#define AXP20X_GPIO10_IN_RANGE_GPIO1		BIT(1)
+#define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x)	((x) & BIT(0))
+#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x)	(((x) & BIT(0)) << 1)
+
+#define AXP20X_ADC_RATE_MASK			GENMASK(7, 6)
+#define AXP20X_ADC_RATE_HZ(x)			((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK)
+#define AXP22X_ADC_RATE_HZ(x)			((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK)
+
+#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg)	\
+	{							\
+		.type = _type,					\
+		.indexed = 1,					\
+		.channel = _channel,				\
+		.address = _reg,				\
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
+				      BIT(IIO_CHAN_INFO_SCALE),	\
+		.datasheet_name = _name,			\
+	}
+
+#define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
+	{							\
+		.type = _type,					\
+		.indexed = 1,					\
+		.channel = _channel,				\
+		.address = _reg,				\
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
+				      BIT(IIO_CHAN_INFO_SCALE) |\
+				      BIT(IIO_CHAN_INFO_OFFSET),\
+		.datasheet_name = _name,			\
+	}
+
+struct axp_data;
+
+struct axp20x_adc_iio {
+	struct regmap		*regmap;
+	struct axp_data		*data;
+};
+
+enum axp20x_adc_channel_v {
+	AXP20X_ACIN_V = 0,
+	AXP20X_VBUS_V,
+	AXP20X_TS_IN,
+	AXP20X_GPIO0_V,
+	AXP20X_GPIO1_V,
+	AXP20X_IPSOUT_V,
+	AXP20X_BATT_V,
+};
+
+enum axp20x_adc_channel_i {
+	AXP20X_ACIN_I = 0,
+	AXP20X_VBUS_I,
+	AXP20X_BATT_CHRG_I,
+	AXP20X_BATT_DISCHRG_I,
+};
+
+enum axp22x_adc_channel_v {
+	AXP22X_TS_IN = 0,
+	AXP22X_BATT_V,
+};
+
+enum axp22x_adc_channel_i {
+	AXP22X_BATT_CHRG_I = 1,
+	AXP22X_BATT_DISCHRG_I,
+};
+
+static struct iio_map axp20x_maps[] = {
+	{
+		.consumer_dev_name = "axp20x-usb-power-supply",
+		.consumer_channel = "vbus_v",
+		.adc_channel_label = "vbus_v",
+	}, {
+		.consumer_dev_name = "axp20x-usb-power-supply",
+		.consumer_channel = "vbus_i",
+		.adc_channel_label = "vbus_i",
+	}, {
+		.consumer_dev_name = "axp20x-ac-power-supply",
+		.consumer_channel = "acin_v",
+		.adc_channel_label = "acin_v",
+	}, {
+		.consumer_dev_name = "axp20x-ac-power-supply",
+		.consumer_channel = "acin_i",
+		.adc_channel_label = "acin_i",
+	}, {
+		.consumer_dev_name = "axp20x-battery-power-supply",
+		.consumer_channel = "batt_v",
+		.adc_channel_label = "batt_v",
+	}, {
+		.consumer_dev_name = "axp20x-battery-power-supply",
+		.consumer_channel = "batt_chrg_i",
+		.adc_channel_label = "batt_chrg_i",
+	}, {
+		.consumer_dev_name = "axp20x-battery-power-supply",
+		.consumer_channel = "batt_dischrg_i",
+		.adc_channel_label = "batt_dischrg_i",
+	}, { /* sentinel */ }
+};
+
+static struct iio_map axp22x_maps[] = {
+	{
+		.consumer_dev_name = "axp20x-battery-power-supply",
+		.consumer_channel = "batt_v",
+		.adc_channel_label = "batt_v",
+	}, {
+		.consumer_dev_name = "axp20x-battery-power-supply",
+		.consumer_channel = "batt_chrg_i",
+		.adc_channel_label = "batt_chrg_i",
+	}, {
+		.consumer_dev_name = "axp20x-battery-power-supply",
+		.consumer_channel = "batt_dischrg_i",
+		.adc_channel_label = "batt_dischrg_i",
+	}, { /* sentinel */ }
+};
+
+/*
+ * Channels are mapped by physical system. Their channels share the same index.
+ * i.e. acin_i is in_current0_raw and acin_v is in_voltage0_raw.
+ * The only exception is for the battery. batt_v will be in_voltage6_raw and
+ * charge current in_current6_raw and discharge current will be in_current7_raw.
+ */
+static const struct iio_chan_spec axp20x_adc_channels[] = {
+	AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
+			   AXP20X_ACIN_V_ADC_H),
+	AXP20X_ADC_CHANNEL(AXP20X_ACIN_I, "acin_i", IIO_CURRENT,
+			   AXP20X_ACIN_I_ADC_H),
+	AXP20X_ADC_CHANNEL(AXP20X_VBUS_V, "vbus_v", IIO_VOLTAGE,
+			   AXP20X_VBUS_V_ADC_H),
+	AXP20X_ADC_CHANNEL(AXP20X_VBUS_I, "vbus_i", IIO_CURRENT,
+			   AXP20X_VBUS_I_ADC_H),
+	{
+		.type = IIO_TEMP,
+		.address = AXP20X_TEMP_ADC_H,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_OFFSET),
+		.datasheet_name = "pmic_temp",
+	},
+	AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
+				  AXP20X_GPIO0_V_ADC_H),
+	AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
+				  AXP20X_GPIO1_V_ADC_H),
+	AXP20X_ADC_CHANNEL(AXP20X_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
+			   AXP20X_IPSOUT_V_HIGH_H),
+	AXP20X_ADC_CHANNEL(AXP20X_BATT_V, "batt_v", IIO_VOLTAGE,
+			   AXP20X_BATT_V_H),
+	AXP20X_ADC_CHANNEL(AXP20X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
+			   AXP20X_BATT_CHRG_I_H),
+	AXP20X_ADC_CHANNEL(AXP20X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
+			   AXP20X_BATT_DISCHRG_I_H),
+};
+
+static const struct iio_chan_spec axp22x_adc_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.address = AXP22X_PMIC_TEMP_H,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_OFFSET),
+		.datasheet_name = "pmic_temp",
+	},
+	AXP20X_ADC_CHANNEL(AXP22X_BATT_V, "batt_v", IIO_VOLTAGE,
+			   AXP20X_BATT_V_H),
+	AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
+			   AXP20X_BATT_CHRG_I_H),
+	AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
+			   AXP20X_BATT_DISCHRG_I_H),
+};
+
+static int axp20x_adc_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan, int *val)
+{
+	struct axp20x_adc_iio *info = iio_priv(indio_dev);
+	int size = 12;
+
+	/*
+	 * N.B.:  Unlike the Chinese datasheets tell, the charging current is
+	 * stored on 12 bits, not 13 bits. Only discharging current is on 13
+	 * bits.
+	 */
+	if (chan->type == IIO_CURRENT && chan->channel == AXP20X_BATT_DISCHRG_I)
+		size = 13;
+	else
+		size = 12;
+
+	*val = axp20x_read_variable_width(info->regmap, chan->address, size);
+	if (*val < 0)
+		return *val;
+
+	return IIO_VAL_INT;
+}
+
+static int axp22x_adc_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan, int *val)
+{
+	struct axp20x_adc_iio *info = iio_priv(indio_dev);
+	int size;
+
+	/*
+	 * N.B.: Unlike the Chinese datasheets tell, the charging current is
+	 * stored on 12 bits, not 13 bits. Only discharging current is on 13
+	 * bits.
+	 */
+	if (chan->type == IIO_CURRENT && chan->channel == AXP22X_BATT_DISCHRG_I)
+		size = 13;
+	else
+		size = 12;
+
+	*val = axp20x_read_variable_width(info->regmap, chan->address, size);
+	if (*val < 0)
+		return *val;
+
+	return IIO_VAL_INT;
+}
+
+static int axp20x_adc_scale_voltage(int channel, int *val, int *val2)
+{
+	switch (channel) {
+	case AXP20X_ACIN_V:
+	case AXP20X_VBUS_V:
+		*val = 1;
+		*val2 = 700000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	case AXP20X_GPIO0_V:
+	case AXP20X_GPIO1_V:
+		*val = 0;
+		*val2 = 500000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	case AXP20X_BATT_V:
+		*val = 1;
+		*val2 = 100000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	case AXP20X_IPSOUT_V:
+		*val = 1;
+		*val2 = 400000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int axp20x_adc_scale_current(int channel, int *val, int *val2)
+{
+	switch (channel) {
+	case AXP20X_ACIN_I:
+		*val = 0;
+		*val2 = 625000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	case AXP20X_VBUS_I:
+		*val = 0;
+		*val2 = 375000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	case AXP20X_BATT_DISCHRG_I:
+	case AXP20X_BATT_CHRG_I:
+		*val = 0;
+		*val2 = 500000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int axp20x_adc_scale(struct iio_chan_spec const *chan, int *val,
+			    int *val2)
+{
+	switch (chan->type) {
+	case IIO_VOLTAGE:
+		return axp20x_adc_scale_voltage(chan->channel, val, val2);
+
+	case IIO_CURRENT:
+		return axp20x_adc_scale_current(chan->channel, val, val2);
+
+	case IIO_TEMP:
+		*val = 100;
+		return IIO_VAL_INT;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val,
+			    int *val2)
+{
+	switch (chan->type) {
+	case IIO_VOLTAGE:
+		if (chan->channel != AXP22X_BATT_V)
+			return -EINVAL;
+
+		*val = 1;
+		*val2 = 100000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	case IIO_CURRENT:
+		*val = 0;
+		*val2 = 500000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	case IIO_TEMP:
+		*val = 100;
+		return IIO_VAL_INT;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel,
+				     int *val)
+{
+	struct axp20x_adc_iio *info = iio_priv(indio_dev);
+	int ret;
+
+	ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, val);
+	if (ret < 0)
+		return ret;
+
+	switch (channel) {
+	case AXP20X_GPIO0_V:
+		*val &= AXP20X_GPIO10_IN_RANGE_GPIO0;
+		break;
+
+	case AXP20X_GPIO1_V:
+		*val &= AXP20X_GPIO10_IN_RANGE_GPIO1;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	*val = !!(*val) * 700000;
+
+	return IIO_VAL_INT;
+}
+
+static int axp20x_adc_offset(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan, int *val)
+{
+	switch (chan->type) {
+	case IIO_VOLTAGE:
+		return axp20x_adc_offset_voltage(indio_dev, chan->channel, val);
+
+	case IIO_TEMP:
+		*val = -1447;
+		return IIO_VAL_INT;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int axp20x_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan, int *val,
+			   int *val2, long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_OFFSET:
+		return axp20x_adc_offset(indio_dev, chan, val);
+
+	case IIO_CHAN_INFO_SCALE:
+		return axp20x_adc_scale(chan, val, val2);
+
+	case IIO_CHAN_INFO_RAW:
+		return axp20x_adc_raw(indio_dev, chan, val);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int axp22x_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan, int *val,
+			   int *val2, long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_OFFSET:
+		*val = -2677;
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		return axp22x_adc_scale(chan, val, val2);
+
+	case IIO_CHAN_INFO_RAW:
+		return axp22x_adc_raw(indio_dev, chan, val);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int axp20x_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan, int val, int val2,
+			    long mask)
+{
+	struct axp20x_adc_iio *info = iio_priv(indio_dev);
+	unsigned int reg, regval;
+
+	/*
+	 * The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets
+	 * for (independently) GPIO0 and GPIO1 when in ADC mode.
+	 */
+	if (mask != IIO_CHAN_INFO_OFFSET)
+		return -EINVAL;
+
+	if (val != 0 && val != 700000)
+		return -EINVAL;
+
+	switch (chan->channel) {
+	case AXP20X_GPIO0_V:
+		reg = AXP20X_GPIO10_IN_RANGE_GPIO0;
+		regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(!!val);
+		break;
+
+	case AXP20X_GPIO1_V:
+		reg = AXP20X_GPIO10_IN_RANGE_GPIO1;
+		regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(!!val);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE, reg,
+				  regval);
+}
+
+static const struct iio_info axp20x_adc_iio_info = {
+	.read_raw = axp20x_read_raw,
+	.write_raw = axp20x_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_info axp22x_adc_iio_info = {
+	.read_raw = axp22x_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int axp20x_adc_rate(int rate)
+{
+	return AXP20X_ADC_RATE_HZ(rate);
+}
+
+static int axp22x_adc_rate(int rate)
+{
+	return AXP22X_ADC_RATE_HZ(rate);
+}
+
+struct axp_data {
+	const struct iio_info		*iio_info;
+	int				num_channels;
+	struct iio_chan_spec const	*channels;
+	unsigned long			adc_en1_mask;
+	int				(*adc_rate)(int rate);
+	bool				adc_en2;
+	struct iio_map			*maps;
+};
+
+static const struct axp_data axp20x_data = {
+	.iio_info = &axp20x_adc_iio_info,
+	.num_channels = ARRAY_SIZE(axp20x_adc_channels),
+	.channels = axp20x_adc_channels,
+	.adc_en1_mask = AXP20X_ADC_EN1_MASK,
+	.adc_rate = axp20x_adc_rate,
+	.adc_en2 = true,
+	.maps = axp20x_maps,
+};
+
+static const struct axp_data axp22x_data = {
+	.iio_info = &axp22x_adc_iio_info,
+	.num_channels = ARRAY_SIZE(axp22x_adc_channels),
+	.channels = axp22x_adc_channels,
+	.adc_en1_mask = AXP22X_ADC_EN1_MASK,
+	.adc_rate = axp22x_adc_rate,
+	.adc_en2 = false,
+	.maps = axp22x_maps,
+};
+
+static const struct platform_device_id axp20x_adc_id_match[] = {
+	{ .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, },
+	{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
+
+static int axp20x_probe(struct platform_device *pdev)
+{
+	struct axp20x_adc_iio *info;
+	struct iio_dev *indio_dev;
+	struct axp20x_dev *axp20x_dev;
+	int ret;
+
+	axp20x_dev = dev_get_drvdata(pdev->dev.parent);
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	info = iio_priv(indio_dev);
+	platform_set_drvdata(pdev, indio_dev);
+
+	info->regmap = axp20x_dev->regmap;
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->dev.of_node = pdev->dev.of_node;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	info->data = (struct axp_data *)platform_get_device_id(pdev)->driver_data;
+
+	indio_dev->name = platform_get_device_id(pdev)->name;
+	indio_dev->info = info->data->iio_info;
+	indio_dev->num_channels = info->data->num_channels;
+	indio_dev->channels = info->data->channels;
+
+	/* Enable the ADCs on IP */
+	regmap_write(info->regmap, AXP20X_ADC_EN1, info->data->adc_en1_mask);
+
+	if (info->data->adc_en2)
+		/* Enable GPIO0/1 and internal temperature ADCs */
+		regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
+				   AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
+
+	/* Configure ADCs rate */
+	regmap_update_bits(info->regmap, AXP20X_ADC_RATE, AXP20X_ADC_RATE_MASK,
+			   info->data->adc_rate(100));
+
+	ret = iio_map_array_register(indio_dev, info->data->maps);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register IIO maps: %d\n", ret);
+		goto fail_map;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "could not register the device\n");
+		goto fail_register;
+	}
+
+	return 0;
+
+fail_register:
+	iio_map_array_unregister(indio_dev);
+
+fail_map:
+	regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
+
+	if (info->data->adc_en2)
+		regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
+
+	return ret;
+}
+
+static int axp20x_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct axp20x_adc_iio *info = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	iio_map_array_unregister(indio_dev);
+
+	regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
+
+	if (info->data->adc_en2)
+		regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
+
+	return 0;
+}
+
+static struct platform_driver axp20x_adc_driver = {
+	.driver = {
+		.name = "axp20x-adc",
+	},
+	.id_table = axp20x_adc_id_match,
+	.probe = axp20x_probe,
+	.remove = axp20x_remove,
+};
+
+module_platform_driver(axp20x_adc_driver);
+
+MODULE_DESCRIPTION("ADC driver for AXP20X and AXP22X PMICs");
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c
new file mode 100644
index 000000000000..b0c7d8ee5cb8
--- /dev/null
+++ b/drivers/iio/adc/mxs-lradc-adc.c
@@ -0,0 +1,843 @@
+/*
+ * Freescale MXS LRADC ADC driver
+ *
+ * Copyright (c) 2012 DENX Software Engineering, GmbH.
+ * Copyright (c) 2017 Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
+ *
+ * Authors:
+ *  Marek Vasut <marex@denx.de>
+ *  Ksenija Stanojevic <ksenija.stanojevic@gmail.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/completion.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mxs-lradc.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/sysfs.h>
+
+/*
+ * Make this runtime configurable if necessary. Currently, if the buffered mode
+ * is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before
+ * triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000)
+ * seconds. The result is that the samples arrive every 500mS.
+ */
+#define LRADC_DELAY_TIMER_PER	200
+#define LRADC_DELAY_TIMER_LOOP	5
+
+#define VREF_MV_BASE 1850
+
+const char *mx23_lradc_adc_irq_names[] = {
+	"mxs-lradc-channel0",
+	"mxs-lradc-channel1",
+	"mxs-lradc-channel2",
+	"mxs-lradc-channel3",
+	"mxs-lradc-channel4",
+	"mxs-lradc-channel5",
+};
+
+const char *mx28_lradc_adc_irq_names[] = {
+	"mxs-lradc-thresh0",
+	"mxs-lradc-thresh1",
+	"mxs-lradc-channel0",
+	"mxs-lradc-channel1",
+	"mxs-lradc-channel2",
+	"mxs-lradc-channel3",
+	"mxs-lradc-channel4",
+	"mxs-lradc-channel5",
+	"mxs-lradc-button0",
+	"mxs-lradc-button1",
+};
+
+static const u32 mxs_lradc_adc_vref_mv[][LRADC_MAX_TOTAL_CHANS] = {
+	[IMX23_LRADC] = {
+		VREF_MV_BASE,		/* CH0 */
+		VREF_MV_BASE,		/* CH1 */
+		VREF_MV_BASE,		/* CH2 */
+		VREF_MV_BASE,		/* CH3 */
+		VREF_MV_BASE,		/* CH4 */
+		VREF_MV_BASE,		/* CH5 */
+		VREF_MV_BASE * 2,	/* CH6 VDDIO */
+		VREF_MV_BASE * 4,	/* CH7 VBATT */
+		VREF_MV_BASE,		/* CH8 Temp sense 0 */
+		VREF_MV_BASE,		/* CH9 Temp sense 1 */
+		VREF_MV_BASE,		/* CH10 */
+		VREF_MV_BASE,		/* CH11 */
+		VREF_MV_BASE,		/* CH12 USB_DP */
+		VREF_MV_BASE,		/* CH13 USB_DN */
+		VREF_MV_BASE,		/* CH14 VBG */
+		VREF_MV_BASE * 4,	/* CH15 VDD5V */
+	},
+	[IMX28_LRADC] = {
+		VREF_MV_BASE,		/* CH0 */
+		VREF_MV_BASE,		/* CH1 */
+		VREF_MV_BASE,		/* CH2 */
+		VREF_MV_BASE,		/* CH3 */
+		VREF_MV_BASE,		/* CH4 */
+		VREF_MV_BASE,		/* CH5 */
+		VREF_MV_BASE,		/* CH6 */
+		VREF_MV_BASE * 4,	/* CH7 VBATT */
+		VREF_MV_BASE,		/* CH8 Temp sense 0 */
+		VREF_MV_BASE,		/* CH9 Temp sense 1 */
+		VREF_MV_BASE * 2,	/* CH10 VDDIO */
+		VREF_MV_BASE,		/* CH11 VTH */
+		VREF_MV_BASE * 2,	/* CH12 VDDA */
+		VREF_MV_BASE,		/* CH13 VDDD */
+		VREF_MV_BASE,		/* CH14 VBG */
+		VREF_MV_BASE * 4,	/* CH15 VDD5V */
+	},
+};
+
+enum mxs_lradc_divbytwo {
+	MXS_LRADC_DIV_DISABLED = 0,
+	MXS_LRADC_DIV_ENABLED,
+};
+
+struct mxs_lradc_scale {
+	unsigned int		integer;
+	unsigned int		nano;
+};
+
+struct mxs_lradc_adc {
+	struct mxs_lradc	*lradc;
+	struct device		*dev;
+
+	void __iomem		*base;
+	u32			buffer[10];
+	struct iio_trigger	*trig;
+	struct completion	completion;
+	spinlock_t		lock;
+
+	const u32		*vref_mv;
+	struct mxs_lradc_scale	scale_avail[LRADC_MAX_TOTAL_CHANS][2];
+	unsigned long		is_divided;
+};
+
+
+/* Raw I/O operations */
+static int mxs_lradc_adc_read_single(struct iio_dev *iio_dev, int chan,
+				     int *val)
+{
+	struct mxs_lradc_adc *adc = iio_priv(iio_dev);
+	struct mxs_lradc *lradc = adc->lradc;
+	int ret;
+
+	/*
+	 * See if there is no buffered operation in progress. If there is simply
+	 * bail out. This can be improved to support both buffered and raw IO at
+	 * the same time, yet the code becomes horribly complicated. Therefore I
+	 * applied KISS principle here.
+	 */
+	ret = iio_device_claim_direct_mode(iio_dev);
+	if (ret)
+		return ret;
+
+	reinit_completion(&adc->completion);
+
+	/*
+	 * No buffered operation in progress, map the channel and trigger it.
+	 * Virtual channel 0 is always used here as the others are always not
+	 * used if doing raw sampling.
+	 */
+	if (lradc->soc == IMX28_LRADC)
+		writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
+		       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+	writel(0x1, adc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+	/* Enable / disable the divider per requirement */
+	if (test_bit(chan, &adc->is_divided))
+		writel(1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
+		       adc->base + LRADC_CTRL2 + STMP_OFFSET_REG_SET);
+	else
+		writel(1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
+		       adc->base + LRADC_CTRL2 + STMP_OFFSET_REG_CLR);
+
+	/* Clean the slot's previous content, then set new one. */
+	writel(LRADC_CTRL4_LRADCSELECT_MASK(0),
+	       adc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR);
+	writel(chan, adc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET);
+
+	writel(0, adc->base + LRADC_CH(0));
+
+	/* Enable the IRQ and start sampling the channel. */
+	writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
+	       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+	writel(BIT(0), adc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+	/* Wait for completion on the channel, 1 second max. */
+	ret = wait_for_completion_killable_timeout(&adc->completion, HZ);
+	if (!ret)
+		ret = -ETIMEDOUT;
+	if (ret < 0)
+		goto err;
+
+	/* Read the data. */
+	*val = readl(adc->base + LRADC_CH(0)) & LRADC_CH_VALUE_MASK;
+	ret = IIO_VAL_INT;
+
+err:
+	writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
+	       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	iio_device_release_direct_mode(iio_dev);
+
+	return ret;
+}
+
+static int mxs_lradc_adc_read_temp(struct iio_dev *iio_dev, int *val)
+{
+	int ret, min, max;
+
+	ret = mxs_lradc_adc_read_single(iio_dev, 8, &min);
+	if (ret != IIO_VAL_INT)
+		return ret;
+
+	ret = mxs_lradc_adc_read_single(iio_dev, 9, &max);
+	if (ret != IIO_VAL_INT)
+		return ret;
+
+	*val = max - min;
+
+	return IIO_VAL_INT;
+}
+
+static int mxs_lradc_adc_read_raw(struct iio_dev *iio_dev,
+			      const struct iio_chan_spec *chan,
+			      int *val, int *val2, long m)
+{
+	struct mxs_lradc_adc *adc = iio_priv(iio_dev);
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		if (chan->type == IIO_TEMP)
+			return mxs_lradc_adc_read_temp(iio_dev, val);
+
+		return mxs_lradc_adc_read_single(iio_dev, chan->channel, val);
+
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_TEMP) {
+			/*
+			 * From the datasheet, we have to multiply by 1.012 and
+			 * divide by 4
+			 */
+			*val = 0;
+			*val2 = 253000;
+			return IIO_VAL_INT_PLUS_MICRO;
+		}
+
+		*val = adc->vref_mv[chan->channel];
+		*val2 = chan->scan_type.realbits -
+			test_bit(chan->channel, &adc->is_divided);
+		return IIO_VAL_FRACTIONAL_LOG2;
+
+	case IIO_CHAN_INFO_OFFSET:
+		if (chan->type == IIO_TEMP) {
+			/*
+			 * The calculated value from the ADC is in Kelvin, we
+			 * want Celsius for hwmon so the offset is -273.15
+			 * The offset is applied before scaling so it is
+			 * actually -213.15 * 4 / 1.012 = -1079.644268
+			 */
+			*val = -1079;
+			*val2 = 644268;
+
+			return IIO_VAL_INT_PLUS_MICRO;
+		}
+
+		return -EINVAL;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int mxs_lradc_adc_write_raw(struct iio_dev *iio_dev,
+				   const struct iio_chan_spec *chan,
+				   int val, int val2, long m)
+{
+	struct mxs_lradc_adc *adc = iio_priv(iio_dev);
+	struct mxs_lradc_scale *scale_avail =
+			adc->scale_avail[chan->channel];
+	int ret;
+
+	ret = iio_device_claim_direct_mode(iio_dev);
+	if (ret)
+		return ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_SCALE:
+		ret = -EINVAL;
+		if (val == scale_avail[MXS_LRADC_DIV_DISABLED].integer &&
+		    val2 == scale_avail[MXS_LRADC_DIV_DISABLED].nano) {
+			/* divider by two disabled */
+			clear_bit(chan->channel, &adc->is_divided);
+			ret = 0;
+		} else if (val == scale_avail[MXS_LRADC_DIV_ENABLED].integer &&
+			   val2 == scale_avail[MXS_LRADC_DIV_ENABLED].nano) {
+			/* divider by two enabled */
+			set_bit(chan->channel, &adc->is_divided);
+			ret = 0;
+		}
+
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	iio_device_release_direct_mode(iio_dev);
+
+	return ret;
+}
+
+static int mxs_lradc_adc_write_raw_get_fmt(struct iio_dev *iio_dev,
+					   const struct iio_chan_spec *chan,
+					   long m)
+{
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static ssize_t mxs_lradc_adc_show_scale_avail(struct device *dev,
+						 struct device_attribute *attr,
+						 char *buf)
+{
+	struct iio_dev *iio = dev_to_iio_dev(dev);
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+	struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr);
+	int i, ch, len = 0;
+
+	ch = iio_attr->address;
+	for (i = 0; i < ARRAY_SIZE(adc->scale_avail[ch]); i++)
+		len += sprintf(buf + len, "%u.%09u ",
+			       adc->scale_avail[ch][i].integer,
+			       adc->scale_avail[ch][i].nano);
+
+	len += sprintf(buf + len, "\n");
+
+	return len;
+}
+
+#define SHOW_SCALE_AVAILABLE_ATTR(ch)\
+	IIO_DEVICE_ATTR(in_voltage##ch##_scale_available, 0444,\
+			mxs_lradc_adc_show_scale_avail, NULL, ch)
+
+SHOW_SCALE_AVAILABLE_ATTR(0);
+SHOW_SCALE_AVAILABLE_ATTR(1);
+SHOW_SCALE_AVAILABLE_ATTR(2);
+SHOW_SCALE_AVAILABLE_ATTR(3);
+SHOW_SCALE_AVAILABLE_ATTR(4);
+SHOW_SCALE_AVAILABLE_ATTR(5);
+SHOW_SCALE_AVAILABLE_ATTR(6);
+SHOW_SCALE_AVAILABLE_ATTR(7);
+SHOW_SCALE_AVAILABLE_ATTR(10);
+SHOW_SCALE_AVAILABLE_ATTR(11);
+SHOW_SCALE_AVAILABLE_ATTR(12);
+SHOW_SCALE_AVAILABLE_ATTR(13);
+SHOW_SCALE_AVAILABLE_ATTR(14);
+SHOW_SCALE_AVAILABLE_ATTR(15);
+
+static struct attribute *mxs_lradc_adc_attributes[] = {
+	&iio_dev_attr_in_voltage0_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage1_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage2_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage3_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage4_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage5_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage6_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage7_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage10_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage11_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage12_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage13_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage14_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage15_scale_available.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group mxs_lradc_adc_attribute_group = {
+	.attrs = mxs_lradc_adc_attributes,
+};
+
+static const struct iio_info mxs_lradc_adc_iio_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= mxs_lradc_adc_read_raw,
+	.write_raw		= mxs_lradc_adc_write_raw,
+	.write_raw_get_fmt	= mxs_lradc_adc_write_raw_get_fmt,
+	.attrs			= &mxs_lradc_adc_attribute_group,
+};
+
+/* IRQ Handling */
+static irqreturn_t mxs_lradc_adc_handle_irq(int irq, void *data)
+{
+	struct iio_dev *iio = data;
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+	struct mxs_lradc *lradc = adc->lradc;
+	unsigned long reg = readl(adc->base + LRADC_CTRL1);
+	unsigned long flags;
+
+	if (!(reg & mxs_lradc_irq_mask(lradc)))
+		return IRQ_NONE;
+
+	if (iio_buffer_enabled(iio)) {
+		if (reg & lradc->buffer_vchans) {
+			spin_lock_irqsave(&adc->lock, flags);
+			iio_trigger_poll(iio->trig);
+			spin_unlock_irqrestore(&adc->lock, flags);
+		}
+	} else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) {
+		complete(&adc->completion);
+	}
+
+	writel(reg & mxs_lradc_irq_mask(lradc),
+	       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	return IRQ_HANDLED;
+}
+
+
+/* Trigger handling */
+static irqreturn_t mxs_lradc_adc_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *iio = pf->indio_dev;
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+	const u32 chan_value = LRADC_CH_ACCUMULATE |
+		((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
+	unsigned int i, j = 0;
+
+	for_each_set_bit(i, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
+		adc->buffer[j] = readl(adc->base + LRADC_CH(j));
+		writel(chan_value, adc->base + LRADC_CH(j));
+		adc->buffer[j] &= LRADC_CH_VALUE_MASK;
+		adc->buffer[j] /= LRADC_DELAY_TIMER_LOOP;
+		j++;
+	}
+
+	iio_push_to_buffers_with_timestamp(iio, adc->buffer, pf->timestamp);
+
+	iio_trigger_notify_done(iio->trig);
+
+	return IRQ_HANDLED;
+}
+
+static int mxs_lradc_adc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *iio = iio_trigger_get_drvdata(trig);
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+	const u32 st = state ? STMP_OFFSET_REG_SET : STMP_OFFSET_REG_CLR;
+
+	writel(LRADC_DELAY_KICK, adc->base + (LRADC_DELAY(0) + st));
+
+	return 0;
+}
+
+static const struct iio_trigger_ops mxs_lradc_adc_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &mxs_lradc_adc_configure_trigger,
+};
+
+static int mxs_lradc_adc_trigger_init(struct iio_dev *iio)
+{
+	int ret;
+	struct iio_trigger *trig;
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+
+	trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name,
+				      iio->id);
+
+	trig->dev.parent = adc->dev;
+	iio_trigger_set_drvdata(trig, iio);
+	trig->ops = &mxs_lradc_adc_trigger_ops;
+
+	ret = iio_trigger_register(trig);
+	if (ret)
+		return ret;
+
+	adc->trig = trig;
+
+	return 0;
+}
+
+static void mxs_lradc_adc_trigger_remove(struct iio_dev *iio)
+{
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+
+	iio_trigger_unregister(adc->trig);
+}
+
+static int mxs_lradc_adc_buffer_preenable(struct iio_dev *iio)
+{
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+	struct mxs_lradc *lradc = adc->lradc;
+	int chan, ofs = 0;
+	unsigned long enable = 0;
+	u32 ctrl4_set = 0;
+	u32 ctrl4_clr = 0;
+	u32 ctrl1_irq = 0;
+	const u32 chan_value = LRADC_CH_ACCUMULATE |
+		((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
+
+	if (lradc->soc == IMX28_LRADC)
+		writel(lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+		       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+	writel(lradc->buffer_vchans,
+	       adc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+	for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
+		ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
+		ctrl4_clr |= LRADC_CTRL4_LRADCSELECT_MASK(ofs);
+		ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs);
+		writel(chan_value, adc->base + LRADC_CH(ofs));
+		bitmap_set(&enable, ofs, 1);
+		ofs++;
+	}
+
+	writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK,
+	       adc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR);
+	writel(ctrl4_clr, adc->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR);
+	writel(ctrl4_set, adc->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET);
+	writel(ctrl1_irq, adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+	writel(enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET,
+	       adc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_SET);
+
+	return 0;
+}
+
+static int mxs_lradc_adc_buffer_postdisable(struct iio_dev *iio)
+{
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+	struct mxs_lradc *lradc = adc->lradc;
+
+	writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK,
+	       adc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR);
+
+	writel(lradc->buffer_vchans,
+	       adc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+	if (lradc->soc == IMX28_LRADC)
+		writel(lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+		       adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	return 0;
+}
+
+static bool mxs_lradc_adc_validate_scan_mask(struct iio_dev *iio,
+					     const unsigned long *mask)
+{
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+	struct mxs_lradc *lradc = adc->lradc;
+	const int map_chans = bitmap_weight(mask, LRADC_MAX_TOTAL_CHANS);
+	int rsvd_chans = 0;
+	unsigned long rsvd_mask = 0;
+
+	if (lradc->use_touchbutton)
+		rsvd_mask |= CHAN_MASK_TOUCHBUTTON;
+	if (lradc->touchscreen_wire == MXS_LRADC_TOUCHSCREEN_4WIRE)
+		rsvd_mask |= CHAN_MASK_TOUCHSCREEN_4WIRE;
+	if (lradc->touchscreen_wire == MXS_LRADC_TOUCHSCREEN_5WIRE)
+		rsvd_mask |= CHAN_MASK_TOUCHSCREEN_5WIRE;
+
+	if (lradc->use_touchbutton)
+		rsvd_chans++;
+	if (lradc->touchscreen_wire)
+		rsvd_chans += 2;
+
+	/* Test for attempts to map channels with special mode of operation. */
+	if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS))
+		return false;
+
+	/* Test for attempts to map more channels then available slots. */
+	if (map_chans + rsvd_chans > LRADC_MAX_MAPPED_CHANS)
+		return false;
+
+	return true;
+}
+
+static const struct iio_buffer_setup_ops mxs_lradc_adc_buffer_ops = {
+	.preenable = &mxs_lradc_adc_buffer_preenable,
+	.postenable = &iio_triggered_buffer_postenable,
+	.predisable = &iio_triggered_buffer_predisable,
+	.postdisable = &mxs_lradc_adc_buffer_postdisable,
+	.validate_scan_mask = &mxs_lradc_adc_validate_scan_mask,
+};
+
+/* Driver initialization */
+#define MXS_ADC_CHAN(idx, chan_type, name) {			\
+	.type = (chan_type),					\
+	.indexed = 1,						\
+	.scan_index = (idx),					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
+			      BIT(IIO_CHAN_INFO_SCALE),		\
+	.channel = (idx),					\
+	.address = (idx),					\
+	.scan_type = {						\
+		.sign = 'u',					\
+		.realbits = LRADC_RESOLUTION,			\
+		.storagebits = 32,				\
+	},							\
+	.datasheet_name = (name),				\
+}
+
+static const struct iio_chan_spec mx23_lradc_chan_spec[] = {
+	MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
+	MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
+	MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
+	MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
+	MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
+	MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
+	MXS_ADC_CHAN(6, IIO_VOLTAGE, "VDDIO"),
+	MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
+	/* Combined Temperature sensors */
+	{
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.scan_index = 8,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_OFFSET) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+		.channel = 8,
+		.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
+		.datasheet_name = "TEMP_DIE",
+	},
+	/* Hidden channel to keep indexes */
+	{
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.scan_index = -1,
+		.channel = 9,
+	},
+	MXS_ADC_CHAN(10, IIO_VOLTAGE, NULL),
+	MXS_ADC_CHAN(11, IIO_VOLTAGE, NULL),
+	MXS_ADC_CHAN(12, IIO_VOLTAGE, "USB_DP"),
+	MXS_ADC_CHAN(13, IIO_VOLTAGE, "USB_DN"),
+	MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
+	MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
+};
+
+static const struct iio_chan_spec mx28_lradc_chan_spec[] = {
+	MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
+	MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
+	MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
+	MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
+	MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
+	MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
+	MXS_ADC_CHAN(6, IIO_VOLTAGE, "LRADC6"),
+	MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
+	/* Combined Temperature sensors */
+	{
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.scan_index = 8,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_OFFSET) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+		.channel = 8,
+		.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
+		.datasheet_name = "TEMP_DIE",
+	},
+	/* Hidden channel to keep indexes */
+	{
+		.type = IIO_TEMP,
+		.indexed = 1,
+		.scan_index = -1,
+		.channel = 9,
+	},
+	MXS_ADC_CHAN(10, IIO_VOLTAGE, "VDDIO"),
+	MXS_ADC_CHAN(11, IIO_VOLTAGE, "VTH"),
+	MXS_ADC_CHAN(12, IIO_VOLTAGE, "VDDA"),
+	MXS_ADC_CHAN(13, IIO_VOLTAGE, "VDDD"),
+	MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
+	MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
+};
+
+static void mxs_lradc_adc_hw_init(struct mxs_lradc_adc *adc)
+{
+	/* 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);
+
+	/* Configure DELAY CHANNEL 0 for generic ADC sampling. */
+	writel(adc_cfg, adc->base + LRADC_DELAY(0));
+
+	/*
+	 * Start internal temperature sensing by clearing bit
+	 * HW_LRADC_CTRL2_TEMPSENSE_PWD. This bit can be left cleared
+	 * after power up.
+	 */
+	writel(0, adc->base + LRADC_CTRL2);
+}
+
+static void mxs_lradc_adc_hw_stop(struct mxs_lradc_adc *adc)
+{
+	writel(0, adc->base + LRADC_DELAY(0));
+}
+
+static int mxs_lradc_adc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mxs_lradc *lradc = dev_get_drvdata(dev->parent);
+	struct mxs_lradc_adc *adc;
+	struct iio_dev *iio;
+	struct resource *iores;
+	int ret, irq, virq, i, s, n;
+	u64 scale_uv;
+	const char **irq_name;
+
+	/* Allocate the IIO device. */
+	iio = devm_iio_device_alloc(dev, sizeof(*adc));
+	if (!iio) {
+		dev_err(dev, "Failed to allocate IIO device\n");
+		return -ENOMEM;
+	}
+
+	adc = iio_priv(iio);
+	adc->lradc = lradc;
+	adc->dev = dev;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	adc->base = devm_ioremap(dev, iores->start, resource_size(iores));
+	if (IS_ERR(adc->base))
+		return PTR_ERR(adc->base);
+
+	init_completion(&adc->completion);
+	spin_lock_init(&adc->lock);
+
+	platform_set_drvdata(pdev, iio);
+
+	iio->name = pdev->name;
+	iio->dev.parent = dev;
+	iio->dev.of_node = dev->parent->of_node;
+	iio->info = &mxs_lradc_adc_iio_info;
+	iio->modes = INDIO_DIRECT_MODE;
+	iio->masklength = LRADC_MAX_TOTAL_CHANS;
+
+	if (lradc->soc == IMX23_LRADC) {
+		iio->channels = mx23_lradc_chan_spec;
+		iio->num_channels = ARRAY_SIZE(mx23_lradc_chan_spec);
+		irq_name = mx23_lradc_adc_irq_names;
+		n = ARRAY_SIZE(mx23_lradc_adc_irq_names);
+	} else {
+		iio->channels = mx28_lradc_chan_spec;
+		iio->num_channels = ARRAY_SIZE(mx28_lradc_chan_spec);
+		irq_name = mx28_lradc_adc_irq_names;
+		n = ARRAY_SIZE(mx28_lradc_adc_irq_names);
+	}
+
+	ret = stmp_reset_block(adc->base);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < n; i++) {
+		irq = platform_get_irq_byname(pdev, irq_name[i]);
+		if (irq < 0)
+			return irq;
+
+		virq = irq_of_parse_and_map(dev->parent->of_node, irq);
+
+		ret = devm_request_irq(dev, virq, mxs_lradc_adc_handle_irq,
+				       0, irq_name[i], iio);
+		if (ret)
+			return ret;
+	}
+
+	ret = mxs_lradc_adc_trigger_init(iio);
+	if (ret)
+		goto err_trig;
+
+	ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time,
+					 &mxs_lradc_adc_trigger_handler,
+					 &mxs_lradc_adc_buffer_ops);
+	if (ret)
+		return ret;
+
+	adc->vref_mv = mxs_lradc_adc_vref_mv[lradc->soc];
+
+	/* Populate available ADC input ranges */
+	for (i = 0; i < LRADC_MAX_TOTAL_CHANS; i++) {
+		for (s = 0; s < ARRAY_SIZE(adc->scale_avail[i]); s++) {
+			/*
+			 * [s=0] = optional divider by two disabled (default)
+			 * [s=1] = optional divider by two enabled
+			 *
+			 * The scale is calculated by doing:
+			 *   Vref >> (realbits - s)
+			 * which multiplies by two on the second component
+			 * of the array.
+			 */
+			scale_uv = ((u64)adc->vref_mv[i] * 100000000) >>
+				   (LRADC_RESOLUTION - s);
+			adc->scale_avail[i][s].nano =
+					do_div(scale_uv, 100000000) * 10;
+			adc->scale_avail[i][s].integer = scale_uv;
+		}
+	}
+
+	/* Configure the hardware. */
+	mxs_lradc_adc_hw_init(adc);
+
+	/* Register IIO device. */
+	ret = iio_device_register(iio);
+	if (ret) {
+		dev_err(dev, "Failed to register IIO device\n");
+		goto err_dev;
+	}
+
+	return 0;
+
+err_dev:
+	mxs_lradc_adc_hw_stop(adc);
+	mxs_lradc_adc_trigger_remove(iio);
+err_trig:
+	iio_triggered_buffer_cleanup(iio);
+	return ret;
+}
+
+static int mxs_lradc_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *iio = platform_get_drvdata(pdev);
+	struct mxs_lradc_adc *adc = iio_priv(iio);
+
+	iio_device_unregister(iio);
+	mxs_lradc_adc_hw_stop(adc);
+	mxs_lradc_adc_trigger_remove(iio);
+	iio_triggered_buffer_cleanup(iio);
+
+	return 0;
+}
+
+static struct platform_driver mxs_lradc_adc_driver = {
+	.driver = {
+		.name	= "mxs-lradc-adc",
+	},
+	.probe	= mxs_lradc_adc_probe,
+	.remove = mxs_lradc_adc_remove,
+};
+module_platform_driver(mxs_lradc_adc_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Freescale MXS LRADC driver general purpose ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxs-lradc-adc");
diff --git a/drivers/iio/adc/mxs-lradc.c b/drivers/iio/adc/mxs-lradc.c
deleted file mode 100644
index b84d37c80a94..000000000000
--- a/drivers/iio/adc/mxs-lradc.c
+++ /dev/null
@@ -1,1750 +0,0 @@
-/*
- * Freescale MXS LRADC driver
- *
- * Copyright (c) 2012 DENX Software Engineering, GmbH.
- * Marek Vasut <marex@denx.de>
- *
- * 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/bitops.h>
-#include <linux/clk.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.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/slab.h>
-#include <linux/stmp_device.h>
-#include <linux/sysfs.h>
-
-#include <linux/iio/buffer.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/trigger.h>
-#include <linux/iio/trigger_consumer.h>
-#include <linux/iio/triggered_buffer.h>
-#include <linux/iio/sysfs.h>
-
-#define DRIVER_NAME		"mxs-lradc"
-
-#define LRADC_MAX_DELAY_CHANS	4
-#define LRADC_MAX_MAPPED_CHANS	8
-#define LRADC_MAX_TOTAL_CHANS	16
-
-#define LRADC_DELAY_TIMER_HZ	2000
-
-/*
- * Make this runtime configurable if necessary. Currently, if the buffered mode
- * is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before
- * triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000)
- * seconds. The result is that the samples arrive every 500mS.
- */
-#define LRADC_DELAY_TIMER_PER	200
-#define LRADC_DELAY_TIMER_LOOP	5
-
-/*
- * Once the pen touches the touchscreen, the touchscreen switches from
- * IRQ-driven mode to polling mode to prevent interrupt storm. The polling
- * is realized by worker thread, which is called every 20 or so milliseconds.
- * This gives the touchscreen enough fluency and does not strain the system
- * too much.
- */
-#define LRADC_TS_SAMPLE_DELAY_MS	5
-
-/*
- * The LRADC reads the following amount of samples from each touchscreen
- * channel and the driver then computes average of these.
- */
-#define LRADC_TS_SAMPLE_AMOUNT		4
-
-enum mxs_lradc_id {
-	IMX23_LRADC,
-	IMX28_LRADC,
-};
-
-static const char * const mx23_lradc_irq_names[] = {
-	"mxs-lradc-touchscreen",
-	"mxs-lradc-channel0",
-	"mxs-lradc-channel1",
-	"mxs-lradc-channel2",
-	"mxs-lradc-channel3",
-	"mxs-lradc-channel4",
-	"mxs-lradc-channel5",
-	"mxs-lradc-channel6",
-	"mxs-lradc-channel7",
-};
-
-static const char * const mx28_lradc_irq_names[] = {
-	"mxs-lradc-touchscreen",
-	"mxs-lradc-thresh0",
-	"mxs-lradc-thresh1",
-	"mxs-lradc-channel0",
-	"mxs-lradc-channel1",
-	"mxs-lradc-channel2",
-	"mxs-lradc-channel3",
-	"mxs-lradc-channel4",
-	"mxs-lradc-channel5",
-	"mxs-lradc-channel6",
-	"mxs-lradc-channel7",
-	"mxs-lradc-button0",
-	"mxs-lradc-button1",
-};
-
-struct mxs_lradc_of_config {
-	const int		irq_count;
-	const char * const	*irq_name;
-	const u32		*vref_mv;
-};
-
-#define VREF_MV_BASE 1850
-
-static const u32 mx23_vref_mv[LRADC_MAX_TOTAL_CHANS] = {
-	VREF_MV_BASE,		/* CH0 */
-	VREF_MV_BASE,		/* CH1 */
-	VREF_MV_BASE,		/* CH2 */
-	VREF_MV_BASE,		/* CH3 */
-	VREF_MV_BASE,		/* CH4 */
-	VREF_MV_BASE,		/* CH5 */
-	VREF_MV_BASE * 2,	/* CH6 VDDIO */
-	VREF_MV_BASE * 4,	/* CH7 VBATT */
-	VREF_MV_BASE,		/* CH8 Temp sense 0 */
-	VREF_MV_BASE,		/* CH9 Temp sense 1 */
-	VREF_MV_BASE,		/* CH10 */
-	VREF_MV_BASE,		/* CH11 */
-	VREF_MV_BASE,		/* CH12 USB_DP */
-	VREF_MV_BASE,		/* CH13 USB_DN */
-	VREF_MV_BASE,		/* CH14 VBG */
-	VREF_MV_BASE * 4,	/* CH15 VDD5V */
-};
-
-static const u32 mx28_vref_mv[LRADC_MAX_TOTAL_CHANS] = {
-	VREF_MV_BASE,		/* CH0 */
-	VREF_MV_BASE,		/* CH1 */
-	VREF_MV_BASE,		/* CH2 */
-	VREF_MV_BASE,		/* CH3 */
-	VREF_MV_BASE,		/* CH4 */
-	VREF_MV_BASE,		/* CH5 */
-	VREF_MV_BASE,		/* CH6 */
-	VREF_MV_BASE * 4,	/* CH7 VBATT */
-	VREF_MV_BASE,		/* CH8 Temp sense 0 */
-	VREF_MV_BASE,		/* CH9 Temp sense 1 */
-	VREF_MV_BASE * 2,	/* CH10 VDDIO */
-	VREF_MV_BASE,		/* CH11 VTH */
-	VREF_MV_BASE * 2,	/* CH12 VDDA */
-	VREF_MV_BASE,		/* CH13 VDDD */
-	VREF_MV_BASE,		/* CH14 VBG */
-	VREF_MV_BASE * 4,	/* CH15 VDD5V */
-};
-
-static const struct mxs_lradc_of_config mxs_lradc_of_config[] = {
-	[IMX23_LRADC] = {
-		.irq_count	= ARRAY_SIZE(mx23_lradc_irq_names),
-		.irq_name	= mx23_lradc_irq_names,
-		.vref_mv	= mx23_vref_mv,
-	},
-	[IMX28_LRADC] = {
-		.irq_count	= ARRAY_SIZE(mx28_lradc_irq_names),
-		.irq_name	= mx28_lradc_irq_names,
-		.vref_mv	= mx28_vref_mv,
-	},
-};
-
-enum mxs_lradc_ts {
-	MXS_LRADC_TOUCHSCREEN_NONE = 0,
-	MXS_LRADC_TOUCHSCREEN_4WIRE,
-	MXS_LRADC_TOUCHSCREEN_5WIRE,
-};
-
-/*
- * Touchscreen handling
- */
-enum lradc_ts_plate {
-	LRADC_TOUCH = 0,
-	LRADC_SAMPLE_X,
-	LRADC_SAMPLE_Y,
-	LRADC_SAMPLE_PRESSURE,
-	LRADC_SAMPLE_VALID,
-};
-
-enum mxs_lradc_divbytwo {
-	MXS_LRADC_DIV_DISABLED = 0,
-	MXS_LRADC_DIV_ENABLED,
-};
-
-struct mxs_lradc_scale {
-	unsigned int		integer;
-	unsigned int		nano;
-};
-
-struct mxs_lradc {
-	struct device		*dev;
-	void __iomem		*base;
-	int			irq[13];
-
-	struct clk		*clk;
-
-	u32			*buffer;
-	struct iio_trigger	*trig;
-
-	struct mutex		lock;
-
-	struct completion	completion;
-
-	const u32		*vref_mv;
-	struct mxs_lradc_scale	scale_avail[LRADC_MAX_TOTAL_CHANS][2];
-	unsigned long		is_divided;
-
-	/*
-	 * When the touchscreen is enabled, we give it two private virtual
-	 * channels: #6 and #7. This means that only 6 virtual channels (instead
-	 * of 8) will be available for buffered capture.
-	 */
-#define TOUCHSCREEN_VCHANNEL1		7
-#define TOUCHSCREEN_VCHANNEL2		6
-#define BUFFER_VCHANS_LIMITED		0x3f
-#define BUFFER_VCHANS_ALL		0xff
-	u8			buffer_vchans;
-
-	/*
-	 * Furthermore, certain LRADC channels are shared between touchscreen
-	 * and/or touch-buttons and generic LRADC block. Therefore when using
-	 * either of these, these channels are not available for the regular
-	 * sampling. The shared channels are as follows:
-	 *
-	 * CH0 -- Touch button #0
-	 * CH1 -- Touch button #1
-	 * CH2 -- Touch screen XPUL
-	 * CH3 -- Touch screen YPLL
-	 * CH4 -- Touch screen XNUL
-	 * CH5 -- Touch screen YNLR
-	 * CH6 -- Touch screen WIPER (5-wire only)
-	 *
-	 * The bit fields below represents which parts of the LRADC block are
-	 * switched into special mode of operation. These channels can not
-	 * be sampled as regular LRADC channels. The driver will refuse any
-	 * attempt to sample these channels.
-	 */
-#define CHAN_MASK_TOUCHBUTTON		(BIT(1) | BIT(0))
-#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 2)
-#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 2)
-	enum mxs_lradc_ts	use_touchscreen;
-	bool			use_touchbutton;
-
-	struct input_dev	*ts_input;
-
-	enum mxs_lradc_id	soc;
-	enum lradc_ts_plate	cur_plate; /* state machine */
-	bool			ts_valid;
-	unsigned		ts_x_pos;
-	unsigned		ts_y_pos;
-	unsigned		ts_pressure;
-
-	/* handle touchscreen's physical behaviour */
-	/* samples per coordinate */
-	unsigned		over_sample_cnt;
-	/* time clocks between samples */
-	unsigned		over_sample_delay;
-	/* time in clocks to wait after the plates where switched */
-	unsigned		settling_delay;
-};
-
-#define	LRADC_CTRL0				0x00
-# define LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE	BIT(23)
-# define LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE	BIT(22)
-# define LRADC_CTRL0_MX28_YNNSW	/* YM */	BIT(21)
-# define LRADC_CTRL0_MX28_YPNSW	/* YP */	BIT(20)
-# define LRADC_CTRL0_MX28_YPPSW	/* YP */	BIT(19)
-# define LRADC_CTRL0_MX28_XNNSW	/* XM */	BIT(18)
-# define LRADC_CTRL0_MX28_XNPSW	/* XM */	BIT(17)
-# define LRADC_CTRL0_MX28_XPPSW	/* XP */	BIT(16)
-
-# define LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE	BIT(20)
-# define LRADC_CTRL0_MX23_YM			BIT(19)
-# define LRADC_CTRL0_MX23_XM			BIT(18)
-# define LRADC_CTRL0_MX23_YP			BIT(17)
-# define LRADC_CTRL0_MX23_XP			BIT(16)
-
-# define LRADC_CTRL0_MX28_PLATE_MASK \
-		(LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE | \
-		LRADC_CTRL0_MX28_YNNSW | LRADC_CTRL0_MX28_YPNSW | \
-		LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_XNNSW | \
-		LRADC_CTRL0_MX28_XNPSW | LRADC_CTRL0_MX28_XPPSW)
-
-# define LRADC_CTRL0_MX23_PLATE_MASK \
-		(LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE | \
-		LRADC_CTRL0_MX23_YM | LRADC_CTRL0_MX23_XM | \
-		LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_XP)
-
-#define	LRADC_CTRL1				0x10
-#define	LRADC_CTRL1_TOUCH_DETECT_IRQ_EN		BIT(24)
-#define	LRADC_CTRL1_LRADC_IRQ_EN(n)		(1 << ((n) + 16))
-#define	LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK	(0x1fff << 16)
-#define	LRADC_CTRL1_MX23_LRADC_IRQ_EN_MASK	(0x01ff << 16)
-#define	LRADC_CTRL1_LRADC_IRQ_EN_OFFSET		16
-#define	LRADC_CTRL1_TOUCH_DETECT_IRQ		BIT(8)
-#define	LRADC_CTRL1_LRADC_IRQ(n)		(1 << (n))
-#define	LRADC_CTRL1_MX28_LRADC_IRQ_MASK		0x1fff
-#define	LRADC_CTRL1_MX23_LRADC_IRQ_MASK		0x01ff
-#define	LRADC_CTRL1_LRADC_IRQ_OFFSET		0
-
-#define	LRADC_CTRL2				0x20
-#define	LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET	24
-#define	LRADC_CTRL2_TEMPSENSE_PWD		BIT(15)
-
-#define	LRADC_STATUS				0x40
-#define	LRADC_STATUS_TOUCH_DETECT_RAW		BIT(0)
-
-#define	LRADC_CH(n)				(0x50 + (0x10 * (n)))
-#define	LRADC_CH_ACCUMULATE			BIT(29)
-#define	LRADC_CH_NUM_SAMPLES_MASK		(0x1f << 24)
-#define	LRADC_CH_NUM_SAMPLES_OFFSET		24
-#define	LRADC_CH_NUM_SAMPLES(x) \
-				((x) << LRADC_CH_NUM_SAMPLES_OFFSET)
-#define	LRADC_CH_VALUE_MASK			0x3ffff
-#define	LRADC_CH_VALUE_OFFSET			0
-
-#define	LRADC_DELAY(n)				(0xd0 + (0x10 * (n)))
-#define	LRADC_DELAY_TRIGGER_LRADCS_MASK		(0xffUL << 24)
-#define	LRADC_DELAY_TRIGGER_LRADCS_OFFSET	24
-#define	LRADC_DELAY_TRIGGER(x) \
-				(((x) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) & \
-				LRADC_DELAY_TRIGGER_LRADCS_MASK)
-#define	LRADC_DELAY_KICK			BIT(20)
-#define	LRADC_DELAY_TRIGGER_DELAYS_MASK		(0xf << 16)
-#define	LRADC_DELAY_TRIGGER_DELAYS_OFFSET	16
-#define	LRADC_DELAY_TRIGGER_DELAYS(x) \
-				(((x) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) & \
-				LRADC_DELAY_TRIGGER_DELAYS_MASK)
-#define	LRADC_DELAY_LOOP_COUNT_MASK		(0x1f << 11)
-#define	LRADC_DELAY_LOOP_COUNT_OFFSET		11
-#define	LRADC_DELAY_LOOP(x) \
-				(((x) << LRADC_DELAY_LOOP_COUNT_OFFSET) & \
-				LRADC_DELAY_LOOP_COUNT_MASK)
-#define	LRADC_DELAY_DELAY_MASK			0x7ff
-#define	LRADC_DELAY_DELAY_OFFSET		0
-#define	LRADC_DELAY_DELAY(x) \
-				(((x) << LRADC_DELAY_DELAY_OFFSET) & \
-				LRADC_DELAY_DELAY_MASK)
-
-#define	LRADC_CTRL4				0x140
-#define	LRADC_CTRL4_LRADCSELECT_MASK(n)		(0xf << ((n) * 4))
-#define	LRADC_CTRL4_LRADCSELECT_OFFSET(n)	((n) * 4)
-#define	LRADC_CTRL4_LRADCSELECT(n, x) \
-				(((x) << LRADC_CTRL4_LRADCSELECT_OFFSET(n)) & \
-				LRADC_CTRL4_LRADCSELECT_MASK(n))
-
-#define LRADC_RESOLUTION			12
-#define LRADC_SINGLE_SAMPLE_MASK		((1 << LRADC_RESOLUTION) - 1)
-
-static void mxs_lradc_reg_set(struct mxs_lradc *lradc, u32 val, u32 reg)
-{
-	writel(val, lradc->base + reg + STMP_OFFSET_REG_SET);
-}
-
-static void mxs_lradc_reg_clear(struct mxs_lradc *lradc, u32 val, u32 reg)
-{
-	writel(val, lradc->base + reg + STMP_OFFSET_REG_CLR);
-}
-
-static void mxs_lradc_reg_wrt(struct mxs_lradc *lradc, u32 val, u32 reg)
-{
-	writel(val, lradc->base + reg);
-}
-
-static u32 mxs_lradc_plate_mask(struct mxs_lradc *lradc)
-{
-	if (lradc->soc == IMX23_LRADC)
-		return LRADC_CTRL0_MX23_PLATE_MASK;
-	return LRADC_CTRL0_MX28_PLATE_MASK;
-}
-
-static u32 mxs_lradc_irq_mask(struct mxs_lradc *lradc)
-{
-	if (lradc->soc == IMX23_LRADC)
-		return LRADC_CTRL1_MX23_LRADC_IRQ_MASK;
-	return LRADC_CTRL1_MX28_LRADC_IRQ_MASK;
-}
-
-static u32 mxs_lradc_touch_detect_bit(struct mxs_lradc *lradc)
-{
-	if (lradc->soc == IMX23_LRADC)
-		return LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE;
-	return LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE;
-}
-
-static u32 mxs_lradc_drive_x_plate(struct mxs_lradc *lradc)
-{
-	if (lradc->soc == IMX23_LRADC)
-		return LRADC_CTRL0_MX23_XP | LRADC_CTRL0_MX23_XM;
-	return LRADC_CTRL0_MX28_XPPSW | LRADC_CTRL0_MX28_XNNSW;
-}
-
-static u32 mxs_lradc_drive_y_plate(struct mxs_lradc *lradc)
-{
-	if (lradc->soc == IMX23_LRADC)
-		return LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_YM;
-	return LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_YNNSW;
-}
-
-static u32 mxs_lradc_drive_pressure(struct mxs_lradc *lradc)
-{
-	if (lradc->soc == IMX23_LRADC)
-		return LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_XM;
-	return LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_XNNSW;
-}
-
-static bool mxs_lradc_check_touch_event(struct mxs_lradc *lradc)
-{
-	return !!(readl(lradc->base + LRADC_STATUS) &
-					LRADC_STATUS_TOUCH_DETECT_RAW);
-}
-
-static void mxs_lradc_map_channel(struct mxs_lradc *lradc, unsigned vch,
-				  unsigned ch)
-{
-	mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(vch),
-			    LRADC_CTRL4);
-	mxs_lradc_reg_set(lradc, LRADC_CTRL4_LRADCSELECT(vch, ch), LRADC_CTRL4);
-}
-
-static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
-{
-	/*
-	 * prepare for oversampling conversion
-	 *
-	 * from the datasheet:
-	 * "The ACCUMULATE bit in the appropriate channel register
-	 * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0;
-	 * otherwise, the IRQs will not fire."
-	 */
-	mxs_lradc_reg_wrt(lradc, LRADC_CH_ACCUMULATE |
-			  LRADC_CH_NUM_SAMPLES(lradc->over_sample_cnt - 1),
-			  LRADC_CH(ch));
-
-	/*
-	 * from the datasheet:
-	 * "Software must clear this register in preparation for a
-	 * multi-cycle accumulation.
-	 */
-	mxs_lradc_reg_clear(lradc, LRADC_CH_VALUE_MASK, LRADC_CH(ch));
-
-	/*
-	 * prepare the delay/loop unit according to the oversampling count
-	 *
-	 * from the datasheet:
-	 * "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1,
-	 * HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise,
-	 * the LRADC will not trigger the delay group."
-	 */
-	mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << ch) |
-			  LRADC_DELAY_TRIGGER_DELAYS(0) |
-			  LRADC_DELAY_LOOP(lradc->over_sample_cnt - 1) |
-			  LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
-			  LRADC_DELAY(3));
-
-	mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch), LRADC_CTRL1);
-
-	/*
-	 * after changing the touchscreen plates setting
-	 * the signals need some initial time to settle. Start the
-	 * SoC's delay unit and start the conversion later
-	 * and automatically.
-	 */
-	mxs_lradc_reg_wrt(
-		lradc,
-		LRADC_DELAY_TRIGGER(0) | /* don't trigger ADC */
-		LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) | /* trigger DELAY unit#3 */
-		LRADC_DELAY_KICK |
-		LRADC_DELAY_DELAY(lradc->settling_delay),
-		LRADC_DELAY(2));
-}
-
-/*
- * Pressure detection is special:
- * We want to do both required measurements for the pressure detection in
- * one turn. Use the hardware features to chain both conversions and let the
- * hardware report one interrupt if both conversions are done
- */
-static void mxs_lradc_setup_ts_pressure(struct mxs_lradc *lradc, unsigned ch1,
-					unsigned ch2)
-{
-	u32 reg;
-
-	/*
-	 * prepare for oversampling conversion
-	 *
-	 * from the datasheet:
-	 * "The ACCUMULATE bit in the appropriate channel register
-	 * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0;
-	 * otherwise, the IRQs will not fire."
-	 */
-	reg = LRADC_CH_ACCUMULATE |
-		LRADC_CH_NUM_SAMPLES(lradc->over_sample_cnt - 1);
-	mxs_lradc_reg_wrt(lradc, reg, LRADC_CH(ch1));
-	mxs_lradc_reg_wrt(lradc, reg, LRADC_CH(ch2));
-
-	/*
-	 * from the datasheet:
-	 * "Software must clear this register in preparation for a
-	 * multi-cycle accumulation.
-	 */
-	mxs_lradc_reg_clear(lradc, LRADC_CH_VALUE_MASK, LRADC_CH(ch1));
-	mxs_lradc_reg_clear(lradc, LRADC_CH_VALUE_MASK, LRADC_CH(ch2));
-
-	/* prepare the delay/loop unit according to the oversampling count */
-	mxs_lradc_reg_wrt(
-		    lradc,
-		    LRADC_DELAY_TRIGGER(1 << ch1) |
-		    LRADC_DELAY_TRIGGER(1 << ch2) | /* start both channels */
-		    LRADC_DELAY_TRIGGER_DELAYS(0) |
-		    LRADC_DELAY_LOOP(lradc->over_sample_cnt - 1) |
-		    LRADC_DELAY_DELAY(lradc->over_sample_delay - 1),
-		    LRADC_DELAY(3));
-
-	mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch2), LRADC_CTRL1);
-
-	/*
-	 * after changing the touchscreen plates setting
-	 * the signals need some initial time to settle. Start the
-	 * SoC's delay unit and start the conversion later
-	 * and automatically.
-	 */
-	mxs_lradc_reg_wrt(
-		lradc,
-		LRADC_DELAY_TRIGGER(0) | /* don't trigger ADC */
-		LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) | /* trigger DELAY unit#3 */
-		LRADC_DELAY_KICK |
-		LRADC_DELAY_DELAY(lradc->settling_delay), LRADC_DELAY(2));
-}
-
-static unsigned mxs_lradc_read_raw_channel(struct mxs_lradc *lradc,
-					   unsigned channel)
-{
-	u32 reg;
-	unsigned num_samples, val;
-
-	reg = readl(lradc->base + LRADC_CH(channel));
-	if (reg & LRADC_CH_ACCUMULATE)
-		num_samples = lradc->over_sample_cnt;
-	else
-		num_samples = 1;
-
-	val = (reg & LRADC_CH_VALUE_MASK) >> LRADC_CH_VALUE_OFFSET;
-	return val / num_samples;
-}
-
-static unsigned mxs_lradc_read_ts_pressure(struct mxs_lradc *lradc,
-					   unsigned ch1, unsigned ch2)
-{
-	u32 reg, mask;
-	unsigned pressure, m1, m2;
-
-	mask = LRADC_CTRL1_LRADC_IRQ(ch1) | LRADC_CTRL1_LRADC_IRQ(ch2);
-	reg = readl(lradc->base + LRADC_CTRL1) & mask;
-
-	while (reg != mask) {
-		reg = readl(lradc->base + LRADC_CTRL1) & mask;
-		dev_dbg(lradc->dev, "One channel is still busy: %X\n", reg);
-	}
-
-	m1 = mxs_lradc_read_raw_channel(lradc, ch1);
-	m2 = mxs_lradc_read_raw_channel(lradc, ch2);
-
-	if (m2 == 0) {
-		dev_warn(lradc->dev, "Cannot calculate pressure\n");
-		return 1 << (LRADC_RESOLUTION - 1);
-	}
-
-	/* simply scale the value from 0 ... max ADC resolution */
-	pressure = m1;
-	pressure *= (1 << LRADC_RESOLUTION);
-	pressure /= m2;
-
-	dev_dbg(lradc->dev, "Pressure = %u\n", pressure);
-	return pressure;
-}
-
-#define TS_CH_XP 2
-#define TS_CH_YP 3
-#define TS_CH_XM 4
-#define TS_CH_YM 5
-
-/*
- * YP(open)--+-------------+
- *           |             |--+
- *           |             |  |
- *    YM(-)--+-------------+  |
- *             +--------------+
- *             |              |
- *         XP(weak+)        XM(open)
- *
- * "weak+" means 200k Ohm VDDIO
- * (-) means GND
- */
-static void mxs_lradc_setup_touch_detection(struct mxs_lradc *lradc)
-{
-	/*
-	 * In order to detect a touch event the 'touch detect enable' bit
-	 * enables:
-	 *  - a weak pullup to the X+ connector
-	 *  - a strong ground at the Y- connector
-	 */
-	mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
-	mxs_lradc_reg_set(lradc, mxs_lradc_touch_detect_bit(lradc),
-			  LRADC_CTRL0);
-}
-
-/*
- * YP(meas)--+-------------+
- *           |             |--+
- *           |             |  |
- * YM(open)--+-------------+  |
- *             +--------------+
- *             |              |
- *           XP(+)          XM(-)
- *
- * (+) means here 1.85 V
- * (-) means here GND
- */
-static void mxs_lradc_prepare_x_pos(struct mxs_lradc *lradc)
-{
-	mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
-	mxs_lradc_reg_set(lradc, mxs_lradc_drive_x_plate(lradc), LRADC_CTRL0);
-
-	lradc->cur_plate = LRADC_SAMPLE_X;
-	mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YP);
-	mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
-}
-
-/*
- *   YP(+)--+-------------+
- *          |             |--+
- *          |             |  |
- *   YM(-)--+-------------+  |
- *            +--------------+
- *            |              |
- *         XP(open)        XM(meas)
- *
- * (+) means here 1.85 V
- * (-) means here GND
- */
-static void mxs_lradc_prepare_y_pos(struct mxs_lradc *lradc)
-{
-	mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
-	mxs_lradc_reg_set(lradc, mxs_lradc_drive_y_plate(lradc), LRADC_CTRL0);
-
-	lradc->cur_plate = LRADC_SAMPLE_Y;
-	mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_XM);
-	mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1);
-}
-
-/*
- *    YP(+)--+-------------+
- *           |             |--+
- *           |             |  |
- * YM(meas)--+-------------+  |
- *             +--------------+
- *             |              |
- *          XP(meas)        XM(-)
- *
- * (+) means here 1.85 V
- * (-) means here GND
- */
-static void mxs_lradc_prepare_pressure(struct mxs_lradc *lradc)
-{
-	mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
-	mxs_lradc_reg_set(lradc, mxs_lradc_drive_pressure(lradc), LRADC_CTRL0);
-
-	lradc->cur_plate = LRADC_SAMPLE_PRESSURE;
-	mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YM);
-	mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL2, TS_CH_XP);
-	mxs_lradc_setup_ts_pressure(lradc, TOUCHSCREEN_VCHANNEL2,
-				    TOUCHSCREEN_VCHANNEL1);
-}
-
-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;
-	mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ |
-			    LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
-	mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
-}
-
-static void mxs_lradc_start_touch_event(struct mxs_lradc *lradc)
-{
-	mxs_lradc_reg_clear(lradc,
-			    LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
-			    LRADC_CTRL1);
-	mxs_lradc_reg_set(lradc,
-			  LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1),
-			  LRADC_CTRL1);
-	/*
-	 * start with the Y-pos, because it uses nearly the same plate
-	 * settings like the touch detection
-	 */
-	mxs_lradc_prepare_y_pos(lradc);
-}
-
-static void mxs_lradc_report_ts_event(struct mxs_lradc *lradc)
-{
-	input_report_abs(lradc->ts_input, ABS_X, lradc->ts_x_pos);
-	input_report_abs(lradc->ts_input, ABS_Y, lradc->ts_y_pos);
-	input_report_abs(lradc->ts_input, ABS_PRESSURE, lradc->ts_pressure);
-	input_report_key(lradc->ts_input, BTN_TOUCH, 1);
-	input_sync(lradc->ts_input);
-}
-
-static void mxs_lradc_complete_touch_event(struct mxs_lradc *lradc)
-{
-	mxs_lradc_setup_touch_detection(lradc);
-	lradc->cur_plate = LRADC_SAMPLE_VALID;
-	/*
-	 * start a dummy conversion to burn time to settle the signals
-	 * note: we are not interested in the conversion's value
-	 */
-	mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(TOUCHSCREEN_VCHANNEL1));
-	mxs_lradc_reg_clear(lradc,
-			    LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
-			    LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2),
-			    LRADC_CTRL1);
-	mxs_lradc_reg_wrt(
-		    lradc,
-		    LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) |
-		    LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), /* waste 5 ms */
-		    LRADC_DELAY(2));
-}
-
-/*
- * in order to avoid false measurements, report only samples where
- * the surface is still touched after the position measurement
- */
-static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid)
-{
-	/* if it is still touched, report the sample */
-	if (valid && mxs_lradc_check_touch_event(lradc)) {
-		lradc->ts_valid = true;
-		mxs_lradc_report_ts_event(lradc);
-	}
-
-	/* if it is even still touched, continue with the next measurement */
-	if (mxs_lradc_check_touch_event(lradc)) {
-		mxs_lradc_prepare_y_pos(lradc);
-		return;
-	}
-
-	if (lradc->ts_valid) {
-		/* signal the release */
-		lradc->ts_valid = false;
-		input_report_key(lradc->ts_input, BTN_TOUCH, 0);
-		input_sync(lradc->ts_input);
-	}
-
-	/* if it is released, wait for the next touch via IRQ */
-	lradc->cur_plate = LRADC_TOUCH;
-	mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
-	mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
-	mxs_lradc_reg_clear(lradc,
-			    LRADC_CTRL1_TOUCH_DETECT_IRQ |
-			    LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
-			    LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1),
-			    LRADC_CTRL1);
-	mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
-}
-
-/* touchscreen's state machine */
-static void mxs_lradc_handle_touch(struct mxs_lradc *lradc)
-{
-	switch (lradc->cur_plate) {
-	case LRADC_TOUCH:
-		if (mxs_lradc_check_touch_event(lradc))
-			mxs_lradc_start_touch_event(lradc);
-		mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ,
-				    LRADC_CTRL1);
-		return;
-
-	case LRADC_SAMPLE_Y:
-		lradc->ts_y_pos =
-		    mxs_lradc_read_raw_channel(lradc,
-					       TOUCHSCREEN_VCHANNEL1);
-		mxs_lradc_prepare_x_pos(lradc);
-		return;
-
-	case LRADC_SAMPLE_X:
-		lradc->ts_x_pos =
-		    mxs_lradc_read_raw_channel(lradc,
-					       TOUCHSCREEN_VCHANNEL1);
-		mxs_lradc_prepare_pressure(lradc);
-		return;
-
-	case LRADC_SAMPLE_PRESSURE:
-		lradc->ts_pressure =
-		    mxs_lradc_read_ts_pressure(lradc,
-					       TOUCHSCREEN_VCHANNEL2,
-					       TOUCHSCREEN_VCHANNEL1);
-		mxs_lradc_complete_touch_event(lradc);
-		return;
-
-	case LRADC_SAMPLE_VALID:
-		mxs_lradc_finish_touch_event(lradc, 1);
-		break;
-	}
-}
-
-/*
- * Raw I/O operations
- */
-static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val)
-{
-	struct mxs_lradc *lradc = iio_priv(iio_dev);
-	int ret;
-
-	/*
-	 * See if there is no buffered operation in progress. If there is, simply
-	 * bail out. This can be improved to support both buffered and raw IO at
-	 * the same time, yet the code becomes horribly complicated. Therefore I
-	 * applied KISS principle here.
-	 */
-	ret = mutex_trylock(&lradc->lock);
-	if (!ret)
-		return -EBUSY;
-
-	reinit_completion(&lradc->completion);
-
-	/*
-	 * No buffered operation in progress, map the channel and trigger it.
-	 * Virtual channel 0 is always used here as the others are always not
-	 * used if doing raw sampling.
-	 */
-	if (lradc->soc == IMX28_LRADC)
-		mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0),
-				    LRADC_CTRL1);
-	mxs_lradc_reg_clear(lradc, 0x1, LRADC_CTRL0);
-
-	/* Enable / disable the divider per requirement */
-	if (test_bit(chan, &lradc->is_divided))
-		mxs_lradc_reg_set(lradc,
-				  1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
-				  LRADC_CTRL2);
-	else
-		mxs_lradc_reg_clear(lradc,
-				    1 << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET,
-				    LRADC_CTRL2);
-
-	/* Clean the slot's previous content, then set new one. */
-	mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(0),
-			    LRADC_CTRL4);
-	mxs_lradc_reg_set(lradc, chan, LRADC_CTRL4);
-
-	mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(0));
-
-	/* Enable the IRQ and start sampling the channel. */
-	mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0), LRADC_CTRL1);
-	mxs_lradc_reg_set(lradc, BIT(0), LRADC_CTRL0);
-
-	/* Wait for completion on the channel, 1 second max. */
-	ret = wait_for_completion_killable_timeout(&lradc->completion, HZ);
-	if (!ret)
-		ret = -ETIMEDOUT;
-	if (ret < 0)
-		goto err;
-
-	/* Read the data. */
-	*val = readl(lradc->base + LRADC_CH(0)) & LRADC_CH_VALUE_MASK;
-	ret = IIO_VAL_INT;
-
-err:
-	mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0), LRADC_CTRL1);
-
-	mutex_unlock(&lradc->lock);
-
-	return ret;
-}
-
-static int mxs_lradc_read_temp(struct iio_dev *iio_dev, int *val)
-{
-	int ret, min, max;
-
-	ret = mxs_lradc_read_single(iio_dev, 8, &min);
-	if (ret != IIO_VAL_INT)
-		return ret;
-
-	ret = mxs_lradc_read_single(iio_dev, 9, &max);
-	if (ret != IIO_VAL_INT)
-		return ret;
-
-	*val = max - min;
-
-	return IIO_VAL_INT;
-}
-
-static int mxs_lradc_read_raw(struct iio_dev *iio_dev,
-			      const struct iio_chan_spec *chan,
-			      int *val, int *val2, long m)
-{
-	struct mxs_lradc *lradc = iio_priv(iio_dev);
-
-	switch (m) {
-	case IIO_CHAN_INFO_RAW:
-		if (chan->type == IIO_TEMP)
-			return mxs_lradc_read_temp(iio_dev, val);
-
-		return mxs_lradc_read_single(iio_dev, chan->channel, val);
-
-	case IIO_CHAN_INFO_SCALE:
-		if (chan->type == IIO_TEMP) {
-			/*
-			 * From the datasheet, we have to multiply by 1.012 and
-			 * divide by 4
-			 */
-			*val = 0;
-			*val2 = 253000;
-			return IIO_VAL_INT_PLUS_MICRO;
-		}
-
-		*val = lradc->vref_mv[chan->channel];
-		*val2 = chan->scan_type.realbits -
-			test_bit(chan->channel, &lradc->is_divided);
-		return IIO_VAL_FRACTIONAL_LOG2;
-
-	case IIO_CHAN_INFO_OFFSET:
-		if (chan->type == IIO_TEMP) {
-			/*
-			 * The calculated value from the ADC is in Kelvin, we
-			 * want Celsius for hwmon so the offset is -273.15
-			 * The offset is applied before scaling so it is
-			 * actually -213.15 * 4 / 1.012 = -1079.644268
-			 */
-			*val = -1079;
-			*val2 = 644268;
-
-			return IIO_VAL_INT_PLUS_MICRO;
-		}
-
-		return -EINVAL;
-
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
-static int mxs_lradc_write_raw(struct iio_dev *iio_dev,
-			       const struct iio_chan_spec *chan,
-			       int val, int val2, long m)
-{
-	struct mxs_lradc *lradc = iio_priv(iio_dev);
-	struct mxs_lradc_scale *scale_avail =
-			lradc->scale_avail[chan->channel];
-	int ret;
-
-	ret = mutex_trylock(&lradc->lock);
-	if (!ret)
-		return -EBUSY;
-
-	switch (m) {
-	case IIO_CHAN_INFO_SCALE:
-		ret = -EINVAL;
-		if (val == scale_avail[MXS_LRADC_DIV_DISABLED].integer &&
-		    val2 == scale_avail[MXS_LRADC_DIV_DISABLED].nano) {
-			/* divider by two disabled */
-			clear_bit(chan->channel, &lradc->is_divided);
-			ret = 0;
-		} else if (val == scale_avail[MXS_LRADC_DIV_ENABLED].integer &&
-			   val2 == scale_avail[MXS_LRADC_DIV_ENABLED].nano) {
-			/* divider by two enabled */
-			set_bit(chan->channel, &lradc->is_divided);
-			ret = 0;
-		}
-
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	mutex_unlock(&lradc->lock);
-
-	return ret;
-}
-
-static int mxs_lradc_write_raw_get_fmt(struct iio_dev *iio_dev,
-				       const struct iio_chan_spec *chan,
-				       long m)
-{
-	return IIO_VAL_INT_PLUS_NANO;
-}
-
-static ssize_t mxs_lradc_show_scale_available_ch(struct device *dev,
-						 struct device_attribute *attr,
-						 char *buf,
-						 int ch)
-{
-	struct iio_dev *iio = dev_to_iio_dev(dev);
-	struct mxs_lradc *lradc = iio_priv(iio);
-	int i, len = 0;
-
-	for (i = 0; i < ARRAY_SIZE(lradc->scale_avail[ch]); i++)
-		len += sprintf(buf + len, "%u.%09u ",
-			       lradc->scale_avail[ch][i].integer,
-			       lradc->scale_avail[ch][i].nano);
-
-	len += sprintf(buf + len, "\n");
-
-	return len;
-}
-
-static ssize_t mxs_lradc_show_scale_available(struct device *dev,
-					      struct device_attribute *attr,
-					      char *buf)
-{
-	struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr);
-
-	return mxs_lradc_show_scale_available_ch(dev, attr, buf,
-						 iio_attr->address);
-}
-
-#define SHOW_SCALE_AVAILABLE_ATTR(ch)					\
-static IIO_DEVICE_ATTR(in_voltage##ch##_scale_available, S_IRUGO,	\
-		       mxs_lradc_show_scale_available, NULL, ch)
-
-SHOW_SCALE_AVAILABLE_ATTR(0);
-SHOW_SCALE_AVAILABLE_ATTR(1);
-SHOW_SCALE_AVAILABLE_ATTR(2);
-SHOW_SCALE_AVAILABLE_ATTR(3);
-SHOW_SCALE_AVAILABLE_ATTR(4);
-SHOW_SCALE_AVAILABLE_ATTR(5);
-SHOW_SCALE_AVAILABLE_ATTR(6);
-SHOW_SCALE_AVAILABLE_ATTR(7);
-SHOW_SCALE_AVAILABLE_ATTR(10);
-SHOW_SCALE_AVAILABLE_ATTR(11);
-SHOW_SCALE_AVAILABLE_ATTR(12);
-SHOW_SCALE_AVAILABLE_ATTR(13);
-SHOW_SCALE_AVAILABLE_ATTR(14);
-SHOW_SCALE_AVAILABLE_ATTR(15);
-
-static struct attribute *mxs_lradc_attributes[] = {
-	&iio_dev_attr_in_voltage0_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage1_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage2_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage3_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage4_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage5_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage6_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage7_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage10_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage11_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage12_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage13_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage14_scale_available.dev_attr.attr,
-	&iio_dev_attr_in_voltage15_scale_available.dev_attr.attr,
-	NULL
-};
-
-static const struct attribute_group mxs_lradc_attribute_group = {
-	.attrs = mxs_lradc_attributes,
-};
-
-static const struct iio_info mxs_lradc_iio_info = {
-	.driver_module		= THIS_MODULE,
-	.read_raw		= mxs_lradc_read_raw,
-	.write_raw		= mxs_lradc_write_raw,
-	.write_raw_get_fmt	= mxs_lradc_write_raw_get_fmt,
-	.attrs			= &mxs_lradc_attribute_group,
-};
-
-static int mxs_lradc_ts_open(struct input_dev *dev)
-{
-	struct mxs_lradc *lradc = input_get_drvdata(dev);
-
-	/* Enable the touch-detect circuitry. */
-	mxs_lradc_enable_touch_detection(lradc);
-
-	return 0;
-}
-
-static void mxs_lradc_disable_ts(struct mxs_lradc *lradc)
-{
-	/* stop all interrupts from firing */
-	mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN |
-		LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
-		LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1);
-
-	/* Power-down touchscreen touch-detect circuitry. */
-	mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0);
-}
-
-static void mxs_lradc_ts_close(struct input_dev *dev)
-{
-	struct mxs_lradc *lradc = input_get_drvdata(dev);
-
-	mxs_lradc_disable_ts(lradc);
-}
-
-static int mxs_lradc_ts_register(struct mxs_lradc *lradc)
-{
-	struct input_dev *input;
-	struct device *dev = lradc->dev;
-
-	if (!lradc->use_touchscreen)
-		return 0;
-
-	input = devm_input_allocate_device(dev);
-	if (!input)
-		return -ENOMEM;
-
-	input->name = DRIVER_NAME;
-	input->id.bustype = BUS_HOST;
-	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,
-			     0, 0);
-
-	lradc->ts_input = input;
-	input_set_drvdata(input, lradc);
-
-	return input_register_device(input);
-}
-
-/*
- * IRQ Handling
- */
-static irqreturn_t mxs_lradc_handle_irq(int irq, void *data)
-{
-	struct iio_dev *iio = data;
-	struct mxs_lradc *lradc = iio_priv(iio);
-	unsigned long reg = readl(lradc->base + LRADC_CTRL1);
-	u32 clr_irq = mxs_lradc_irq_mask(lradc);
-	const u32 ts_irq_mask =
-		LRADC_CTRL1_TOUCH_DETECT_IRQ |
-		LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
-		LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2);
-
-	if (!(reg & mxs_lradc_irq_mask(lradc)))
-		return IRQ_NONE;
-
-	if (lradc->use_touchscreen && (reg & ts_irq_mask)) {
-		mxs_lradc_handle_touch(lradc);
-
-		/* Make sure we don't clear the next conversion's interrupt. */
-		clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
-				LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2));
-	}
-
-	if (iio_buffer_enabled(iio)) {
-		if (reg & lradc->buffer_vchans)
-			iio_trigger_poll(iio->trig);
-	} else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) {
-		complete(&lradc->completion);
-	}
-
-	mxs_lradc_reg_clear(lradc, reg & clr_irq, LRADC_CTRL1);
-
-	return IRQ_HANDLED;
-}
-
-/*
- * Trigger handling
- */
-static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p)
-{
-	struct iio_poll_func *pf = p;
-	struct iio_dev *iio = pf->indio_dev;
-	struct mxs_lradc *lradc = iio_priv(iio);
-	const u32 chan_value = LRADC_CH_ACCUMULATE |
-		((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
-	unsigned int i, j = 0;
-
-	for_each_set_bit(i, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
-		lradc->buffer[j] = readl(lradc->base + LRADC_CH(j));
-		mxs_lradc_reg_wrt(lradc, chan_value, LRADC_CH(j));
-		lradc->buffer[j] &= LRADC_CH_VALUE_MASK;
-		lradc->buffer[j] /= LRADC_DELAY_TIMER_LOOP;
-		j++;
-	}
-
-	iio_push_to_buffers_with_timestamp(iio, lradc->buffer, pf->timestamp);
-
-	iio_trigger_notify_done(iio->trig);
-
-	return IRQ_HANDLED;
-}
-
-static int mxs_lradc_configure_trigger(struct iio_trigger *trig, bool state)
-{
-	struct iio_dev *iio = iio_trigger_get_drvdata(trig);
-	struct mxs_lradc *lradc = iio_priv(iio);
-	const u32 st = state ? STMP_OFFSET_REG_SET : STMP_OFFSET_REG_CLR;
-
-	mxs_lradc_reg_wrt(lradc, LRADC_DELAY_KICK, LRADC_DELAY(0) + st);
-
-	return 0;
-}
-
-static const struct iio_trigger_ops mxs_lradc_trigger_ops = {
-	.owner = THIS_MODULE,
-	.set_trigger_state = &mxs_lradc_configure_trigger,
-};
-
-static int mxs_lradc_trigger_init(struct iio_dev *iio)
-{
-	int ret;
-	struct iio_trigger *trig;
-	struct mxs_lradc *lradc = iio_priv(iio);
-
-	trig = iio_trigger_alloc("%s-dev%i", iio->name, iio->id);
-	if (!trig)
-		return -ENOMEM;
-
-	trig->dev.parent = lradc->dev;
-	iio_trigger_set_drvdata(trig, iio);
-	trig->ops = &mxs_lradc_trigger_ops;
-
-	ret = iio_trigger_register(trig);
-	if (ret) {
-		iio_trigger_free(trig);
-		return ret;
-	}
-
-	lradc->trig = trig;
-
-	return 0;
-}
-
-static void mxs_lradc_trigger_remove(struct iio_dev *iio)
-{
-	struct mxs_lradc *lradc = iio_priv(iio);
-
-	iio_trigger_unregister(lradc->trig);
-	iio_trigger_free(lradc->trig);
-}
-
-static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
-{
-	struct mxs_lradc *lradc = iio_priv(iio);
-	int ret = 0, chan, ofs = 0;
-	unsigned long enable = 0;
-	u32 ctrl4_set = 0;
-	u32 ctrl4_clr = 0;
-	u32 ctrl1_irq = 0;
-	const u32 chan_value = LRADC_CH_ACCUMULATE |
-		((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
-	const int len = bitmap_weight(iio->active_scan_mask,
-			LRADC_MAX_TOTAL_CHANS);
-
-	if (!len)
-		return -EINVAL;
-
-	/*
-	 * Lock the driver so raw access can not be done during buffered
-	 * operation. This simplifies the code a lot.
-	 */
-	ret = mutex_trylock(&lradc->lock);
-	if (!ret)
-		return -EBUSY;
-
-	lradc->buffer = kmalloc_array(len, sizeof(*lradc->buffer), GFP_KERNEL);
-	if (!lradc->buffer) {
-		ret = -ENOMEM;
-		goto err_mem;
-	}
-
-	if (lradc->soc == IMX28_LRADC)
-		mxs_lradc_reg_clear(
-			lradc,
-			lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
-			LRADC_CTRL1);
-	mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
-
-	for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
-		ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
-		ctrl4_clr |= LRADC_CTRL4_LRADCSELECT_MASK(ofs);
-		ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs);
-		mxs_lradc_reg_wrt(lradc, chan_value, LRADC_CH(ofs));
-		bitmap_set(&enable, ofs, 1);
-		ofs++;
-	}
-
-	mxs_lradc_reg_clear(lradc, LRADC_DELAY_TRIGGER_LRADCS_MASK |
-			    LRADC_DELAY_KICK, LRADC_DELAY(0));
-	mxs_lradc_reg_clear(lradc, ctrl4_clr, LRADC_CTRL4);
-	mxs_lradc_reg_set(lradc, ctrl4_set, LRADC_CTRL4);
-	mxs_lradc_reg_set(lradc, ctrl1_irq, LRADC_CTRL1);
-	mxs_lradc_reg_set(lradc, enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET,
-			  LRADC_DELAY(0));
-
-	return 0;
-
-err_mem:
-	mutex_unlock(&lradc->lock);
-	return ret;
-}
-
-static int mxs_lradc_buffer_postdisable(struct iio_dev *iio)
-{
-	struct mxs_lradc *lradc = iio_priv(iio);
-
-	mxs_lradc_reg_clear(lradc, LRADC_DELAY_TRIGGER_LRADCS_MASK |
-			    LRADC_DELAY_KICK, LRADC_DELAY(0));
-
-	mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0);
-	if (lradc->soc == IMX28_LRADC)
-		mxs_lradc_reg_clear(
-			lradc,
-			lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
-			LRADC_CTRL1);
-
-	kfree(lradc->buffer);
-	mutex_unlock(&lradc->lock);
-
-	return 0;
-}
-
-static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio,
-					 const unsigned long *mask)
-{
-	struct mxs_lradc *lradc = iio_priv(iio);
-	const int map_chans = bitmap_weight(mask, LRADC_MAX_TOTAL_CHANS);
-	int rsvd_chans = 0;
-	unsigned long rsvd_mask = 0;
-
-	if (lradc->use_touchbutton)
-		rsvd_mask |= CHAN_MASK_TOUCHBUTTON;
-	if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_4WIRE)
-		rsvd_mask |= CHAN_MASK_TOUCHSCREEN_4WIRE;
-	if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE)
-		rsvd_mask |= CHAN_MASK_TOUCHSCREEN_5WIRE;
-
-	if (lradc->use_touchbutton)
-		rsvd_chans++;
-	if (lradc->use_touchscreen)
-		rsvd_chans += 2;
-
-	/* Test for attempts to map channels with special mode of operation. */
-	if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS))
-		return false;
-
-	/* Test for attempts to map more channels then available slots. */
-	if (map_chans + rsvd_chans > LRADC_MAX_MAPPED_CHANS)
-		return false;
-
-	return true;
-}
-
-static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
-	.preenable = &mxs_lradc_buffer_preenable,
-	.postenable = &iio_triggered_buffer_postenable,
-	.predisable = &iio_triggered_buffer_predisable,
-	.postdisable = &mxs_lradc_buffer_postdisable,
-	.validate_scan_mask = &mxs_lradc_validate_scan_mask,
-};
-
-/*
- * Driver initialization
- */
-
-#define MXS_ADC_CHAN(idx, chan_type, name) {			\
-	.type = (chan_type),					\
-	.indexed = 1,						\
-	.scan_index = (idx),					\
-	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
-			      BIT(IIO_CHAN_INFO_SCALE),		\
-	.channel = (idx),					\
-	.address = (idx),					\
-	.scan_type = {						\
-		.sign = 'u',					\
-		.realbits = LRADC_RESOLUTION,			\
-		.storagebits = 32,				\
-	},							\
-	.datasheet_name = (name),				\
-}
-
-static const struct iio_chan_spec mx23_lradc_chan_spec[] = {
-	MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
-	MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
-	MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
-	MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
-	MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
-	MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
-	MXS_ADC_CHAN(6, IIO_VOLTAGE, "VDDIO"),
-	MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
-	/* Combined Temperature sensors */
-	{
-		.type = IIO_TEMP,
-		.indexed = 1,
-		.scan_index = 8,
-		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-				      BIT(IIO_CHAN_INFO_OFFSET) |
-				      BIT(IIO_CHAN_INFO_SCALE),
-		.channel = 8,
-		.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
-		.datasheet_name = "TEMP_DIE",
-	},
-	/* Hidden channel to keep indexes */
-	{
-		.type = IIO_TEMP,
-		.indexed = 1,
-		.scan_index = -1,
-		.channel = 9,
-	},
-	MXS_ADC_CHAN(10, IIO_VOLTAGE, NULL),
-	MXS_ADC_CHAN(11, IIO_VOLTAGE, NULL),
-	MXS_ADC_CHAN(12, IIO_VOLTAGE, "USB_DP"),
-	MXS_ADC_CHAN(13, IIO_VOLTAGE, "USB_DN"),
-	MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
-	MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
-};
-
-static const struct iio_chan_spec mx28_lradc_chan_spec[] = {
-	MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
-	MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
-	MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
-	MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
-	MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
-	MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
-	MXS_ADC_CHAN(6, IIO_VOLTAGE, "LRADC6"),
-	MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
-	/* Combined Temperature sensors */
-	{
-		.type = IIO_TEMP,
-		.indexed = 1,
-		.scan_index = 8,
-		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-				      BIT(IIO_CHAN_INFO_OFFSET) |
-				      BIT(IIO_CHAN_INFO_SCALE),
-		.channel = 8,
-		.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
-		.datasheet_name = "TEMP_DIE",
-	},
-	/* Hidden channel to keep indexes */
-	{
-		.type = IIO_TEMP,
-		.indexed = 1,
-		.scan_index = -1,
-		.channel = 9,
-	},
-	MXS_ADC_CHAN(10, IIO_VOLTAGE, "VDDIO"),
-	MXS_ADC_CHAN(11, IIO_VOLTAGE, "VTH"),
-	MXS_ADC_CHAN(12, IIO_VOLTAGE, "VDDA"),
-	MXS_ADC_CHAN(13, IIO_VOLTAGE, "VDDD"),
-	MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
-	MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
-};
-
-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);
-
-	/* Configure DELAY CHANNEL 0 for generic ADC sampling. */
-	mxs_lradc_reg_wrt(lradc, adc_cfg, LRADC_DELAY(0));
-
-	/* Disable remaining DELAY CHANNELs */
-	mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(1));
-	mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
-	mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
-
-	/* Start internal temperature sensing. */
-	mxs_lradc_reg_wrt(lradc, 0, LRADC_CTRL2);
-}
-
-static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
-{
-	int i;
-
-	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));
-}
-
-static const struct of_device_id mxs_lradc_dt_ids[] = {
-	{ .compatible = "fsl,imx23-lradc", .data = (void *)IMX23_LRADC, },
-	{ .compatible = "fsl,imx28-lradc", .data = (void *)IMX28_LRADC, },
-	{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids);
-
-static int mxs_lradc_probe_touchscreen(struct mxs_lradc *lradc,
-				       struct device_node *lradc_node)
-{
-	int ret;
-	u32 ts_wires = 0, adapt;
-
-	ret = of_property_read_u32(lradc_node, "fsl,lradc-touchscreen-wires",
-				   &ts_wires);
-	if (ret)
-		return -ENODEV; /* touchscreen feature disabled */
-
-	switch (ts_wires) {
-	case 4:
-		lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_4WIRE;
-		break;
-	case 5:
-		if (lradc->soc == IMX28_LRADC) {
-			lradc->use_touchscreen = MXS_LRADC_TOUCHSCREEN_5WIRE;
-			break;
-		}
-		/* fall through an error message for i.MX23 */
-	default:
-		dev_err(lradc->dev,
-			"Unsupported number of touchscreen wires (%d)\n",
-			ts_wires);
-		return -EINVAL;
-	}
-
-	if (of_property_read_u32(lradc_node, "fsl,ave-ctrl", &adapt)) {
-		lradc->over_sample_cnt = 4;
-	} else {
-		if (adapt < 1 || adapt > 32) {
-			dev_err(lradc->dev, "Invalid sample count (%u)\n",
-				adapt);
-			return -EINVAL;
-		}
-		lradc->over_sample_cnt = adapt;
-	}
-
-	if (of_property_read_u32(lradc_node, "fsl,ave-delay", &adapt)) {
-		lradc->over_sample_delay = 2;
-	} else {
-		if (adapt < 2 || adapt > LRADC_DELAY_DELAY_MASK + 1) {
-			dev_err(lradc->dev, "Invalid sample delay (%u)\n",
-				adapt);
-			return -EINVAL;
-		}
-		lradc->over_sample_delay = adapt;
-	}
-
-	if (of_property_read_u32(lradc_node, "fsl,settling", &adapt)) {
-		lradc->settling_delay = 10;
-	} else {
-		if (adapt < 1 || adapt > LRADC_DELAY_DELAY_MASK) {
-			dev_err(lradc->dev, "Invalid settling delay (%u)\n",
-				adapt);
-			return -EINVAL;
-		}
-		lradc->settling_delay = adapt;
-	}
-
-	return 0;
-}
-
-static int mxs_lradc_probe(struct platform_device *pdev)
-{
-	const struct of_device_id *of_id =
-		of_match_device(mxs_lradc_dt_ids, &pdev->dev);
-	const struct mxs_lradc_of_config *of_cfg =
-		&mxs_lradc_of_config[(enum mxs_lradc_id)of_id->data];
-	struct device *dev = &pdev->dev;
-	struct device_node *node = dev->of_node;
-	struct mxs_lradc *lradc;
-	struct iio_dev *iio;
-	struct resource *iores;
-	int ret = 0, touch_ret;
-	int i, s;
-	u64 scale_uv;
-
-	/* Allocate the IIO device. */
-	iio = devm_iio_device_alloc(dev, sizeof(*lradc));
-	if (!iio) {
-		dev_err(dev, "Failed to allocate IIO device\n");
-		return -ENOMEM;
-	}
-
-	lradc = iio_priv(iio);
-	lradc->soc = (enum mxs_lradc_id)of_id->data;
-
-	/* Grab the memory area */
-	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	lradc->dev = &pdev->dev;
-	lradc->base = devm_ioremap_resource(dev, iores);
-	if (IS_ERR(lradc->base))
-		return PTR_ERR(lradc->base);
-
-	lradc->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(lradc->clk)) {
-		dev_err(dev, "Failed to get the delay unit clock\n");
-		return PTR_ERR(lradc->clk);
-	}
-	ret = clk_prepare_enable(lradc->clk);
-	if (ret != 0) {
-		dev_err(dev, "Failed to enable the delay unit clock\n");
-		return ret;
-	}
-
-	touch_ret = mxs_lradc_probe_touchscreen(lradc, node);
-
-	if (touch_ret == 0)
-		lradc->buffer_vchans = BUFFER_VCHANS_LIMITED;
-	else
-		lradc->buffer_vchans = BUFFER_VCHANS_ALL;
-
-	/* Grab all IRQ sources */
-	for (i = 0; i < of_cfg->irq_count; i++) {
-		lradc->irq[i] = platform_get_irq(pdev, i);
-		if (lradc->irq[i] < 0) {
-			ret = lradc->irq[i];
-			goto err_clk;
-		}
-
-		ret = devm_request_irq(dev, lradc->irq[i],
-				       mxs_lradc_handle_irq, 0,
-				       of_cfg->irq_name[i], iio);
-		if (ret)
-			goto err_clk;
-	}
-
-	lradc->vref_mv = of_cfg->vref_mv;
-
-	platform_set_drvdata(pdev, iio);
-
-	init_completion(&lradc->completion);
-	mutex_init(&lradc->lock);
-
-	iio->name = pdev->name;
-	iio->dev.parent = &pdev->dev;
-	iio->info = &mxs_lradc_iio_info;
-	iio->modes = INDIO_DIRECT_MODE;
-	iio->masklength = LRADC_MAX_TOTAL_CHANS;
-
-	if (lradc->soc == IMX23_LRADC) {
-		iio->channels = mx23_lradc_chan_spec;
-		iio->num_channels = ARRAY_SIZE(mx23_lradc_chan_spec);
-	} else {
-		iio->channels = mx28_lradc_chan_spec;
-		iio->num_channels = ARRAY_SIZE(mx28_lradc_chan_spec);
-	}
-
-	ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time,
-					 &mxs_lradc_trigger_handler,
-					 &mxs_lradc_buffer_ops);
-	if (ret)
-		goto err_clk;
-
-	ret = mxs_lradc_trigger_init(iio);
-	if (ret)
-		goto err_trig;
-
-	/* Populate available ADC input ranges */
-	for (i = 0; i < LRADC_MAX_TOTAL_CHANS; i++) {
-		for (s = 0; s < ARRAY_SIZE(lradc->scale_avail[i]); s++) {
-			/*
-			 * [s=0] = optional divider by two disabled (default)
-			 * [s=1] = optional divider by two enabled
-			 *
-			 * The scale is calculated by doing:
-			 *   Vref >> (realbits - s)
-			 * which multiplies by two on the second component
-			 * of the array.
-			 */
-			scale_uv = ((u64)lradc->vref_mv[i] * 100000000) >>
-				   (LRADC_RESOLUTION - s);
-			lradc->scale_avail[i][s].nano =
-					do_div(scale_uv, 100000000) * 10;
-			lradc->scale_avail[i][s].integer = scale_uv;
-		}
-	}
-
-	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);
-		if (ret)
-			goto err_ts_register;
-	}
-
-	/* Register IIO device. */
-	ret = iio_device_register(iio);
-	if (ret) {
-		dev_err(dev, "Failed to register IIO device\n");
-		return ret;
-	}
-
-	return 0;
-
-err_ts_register:
-	mxs_lradc_hw_stop(lradc);
-err_dev:
-	mxs_lradc_trigger_remove(iio);
-err_trig:
-	iio_triggered_buffer_cleanup(iio);
-err_clk:
-	clk_disable_unprepare(lradc->clk);
-	return ret;
-}
-
-static int mxs_lradc_remove(struct platform_device *pdev)
-{
-	struct iio_dev *iio = platform_get_drvdata(pdev);
-	struct mxs_lradc *lradc = iio_priv(iio);
-
-	iio_device_unregister(iio);
-	mxs_lradc_hw_stop(lradc);
-	mxs_lradc_trigger_remove(iio);
-	iio_triggered_buffer_cleanup(iio);
-
-	clk_disable_unprepare(lradc->clk);
-
-	return 0;
-}
-
-static struct platform_driver mxs_lradc_driver = {
-	.driver	= {
-		.name	= DRIVER_NAME,
-		.of_match_table = mxs_lradc_dt_ids,
-	},
-	.probe	= mxs_lradc_probe,
-	.remove	= mxs_lradc_remove,
-};
-
-module_platform_driver(mxs_lradc_driver);
-
-MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
-MODULE_DESCRIPTION("Freescale MXS LRADC driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 5b6c52210d20..9f7b72249eac 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -316,6 +316,16 @@ config INPUT_COBALT_BTNS
 	  To compile this driver as a module, choose M here: the
 	  module will be called cobalt_btns.
 
+config INPUT_CPCAP_PWRBUTTON
+	tristate "CPCAP OnKey"
+	depends on MFD_CPCAP
+	help
+	  Say Y here if you want to enable power key reporting via the
+	  Motorola CPCAP chip.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called cpcap-pwrbutton.
+
 config INPUT_WISTRON_BTNS
 	tristate "x86 Wistron laptop button interface"
 	depends on X86_32
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index b10523f2878e..b923a9828c88 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_INPUT_CM109)		+= cm109.o
 obj-$(CONFIG_INPUT_CMA3000)		+= cma3000_d0x.o
 obj-$(CONFIG_INPUT_CMA3000_I2C)		+= cma3000_d0x_i2c.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)		+= cobalt_btns.o
+obj-$(CONFIG_INPUT_CPCAP_PWRBUTTON)	+= cpcap-pwrbutton.o
 obj-$(CONFIG_INPUT_DA9052_ONKEY)	+= da9052_onkey.o
 obj-$(CONFIG_INPUT_DA9055_ONKEY)	+= da9055_onkey.o
 obj-$(CONFIG_INPUT_DA9063_ONKEY)	+= da9063_onkey.o
diff --git a/drivers/input/misc/cpcap-pwrbutton.c b/drivers/input/misc/cpcap-pwrbutton.c
new file mode 100644
index 000000000000..0abef63217e2
--- /dev/null
+++ b/drivers/input/misc/cpcap-pwrbutton.c
@@ -0,0 +1,117 @@
+/**
+ * CPCAP Power Button Input Driver
+ *
+ * Copyright (C) 2017 Sebastian Reichel <sre@kernel.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/motorola-cpcap.h>
+
+#define CPCAP_IRQ_ON 23
+#define CPCAP_IRQ_ON_BITMASK (1 << (CPCAP_IRQ_ON % 16))
+
+struct cpcap_power_button {
+	struct regmap *regmap;
+	struct input_dev *idev;
+	struct device *dev;
+};
+
+static irqreturn_t powerbutton_irq(int irq, void *_button)
+{
+	struct cpcap_power_button *button = _button;
+	int val;
+
+	val = cpcap_sense_virq(button->regmap, irq);
+	if (val < 0) {
+		dev_err(button->dev, "irq read failed: %d", val);
+		return IRQ_HANDLED;
+	}
+
+	pm_wakeup_event(button->dev, 0);
+	input_report_key(button->idev, KEY_POWER, val);
+	input_sync(button->idev);
+
+	return IRQ_HANDLED;
+}
+
+static int cpcap_power_button_probe(struct platform_device *pdev)
+{
+	struct cpcap_power_button *button;
+	int irq = platform_get_irq(pdev, 0);
+	int err;
+
+	button = devm_kmalloc(&pdev->dev, sizeof(*button), GFP_KERNEL);
+	if (!button)
+		return -ENOMEM;
+
+	button->idev = devm_input_allocate_device(&pdev->dev);
+	if (!button->idev)
+		return -ENOMEM;
+
+	button->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!button->regmap)
+		return -ENODEV;
+
+	button->dev = &pdev->dev;
+
+	button->idev->name = "cpcap-pwrbutton";
+	button->idev->phys = "cpcap-pwrbutton/input0";
+	button->idev->dev.parent = button->dev;
+	input_set_capability(button->idev, EV_KEY, KEY_POWER);
+
+	err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+		powerbutton_irq, IRQF_ONESHOT, "cpcap_pwrbutton", button);
+	if (err < 0) {
+		dev_err(&pdev->dev, "IRQ request failed: %d\n", err);
+		return err;
+	}
+
+	err = input_register_device(button->idev);
+	if (err) {
+		dev_err(&pdev->dev, "Input register failed: %d\n", err);
+		return err;
+	}
+
+	device_init_wakeup(&pdev->dev, true);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id cpcap_pwrbutton_dt_match_table[] = {
+	{ .compatible = "motorola,cpcap-pwrbutton" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, cpcap_pwrbutton_dt_match_table);
+#endif
+
+static struct platform_driver cpcap_power_button_driver = {
+	.probe		= cpcap_power_button_probe,
+	.driver		= {
+		.name	= "cpcap-pwrbutton",
+		.of_match_table = of_match_ptr(cpcap_pwrbutton_dt_match_table),
+	},
+};
+module_platform_driver(cpcap_power_button_driver);
+
+MODULE_ALIAS("platform:cpcap-pwrbutton");
+MODULE_DESCRIPTION("CPCAP Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 033599777651..52458cfdf017 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -829,6 +829,16 @@ config TOUCHSCREEN_USB_COMPOSITE
 	  To compile this driver as a module, choose M here: the
 	  module will be called usbtouchscreen.
 
+config TOUCHSCREEN_MXS_LRADC
+	tristate "Freescale i.MX23/i.MX28 LRADC touchscreen"
+	depends on MFD_MXS_LRADC
+	help
+	  Say Y here if you have a touchscreen connected to the low-resolution
+	  analog-to-digital converter (LRADC) on an i.MX23 or i.MX28 processor.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called mxs-lradc-ts.
+
 config TOUCHSCREEN_MX25
 	tristate "Freescale i.MX25 touchscreen input driver"
 	depends on MFD_MX25_TSADC
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index b622e5344137..96761ce2ee6d 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
 obj-$(CONFIG_TOUCHSCREEN_IPROC)		+= bcm_iproc_tsc.o
 obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MAX11801)	+= max11801_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC)     += mxs-lradc-ts.o
 obj-$(CONFIG_TOUCHSCREEN_MX25)		+= fsl-imx25-tcq.o
 obj-$(CONFIG_TOUCHSCREEN_MC13783)	+= mc13783_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MCS5000)	+= mcs5000_ts.o
diff --git a/drivers/input/touchscreen/mxs-lradc-ts.c b/drivers/input/touchscreen/mxs-lradc-ts.c
new file mode 100644
index 000000000000..58c016cd6809
--- /dev/null
+++ b/drivers/input/touchscreen/mxs-lradc-ts.c
@@ -0,0 +1,714 @@
+/*
+ * Freescale MXS LRADC touchscreen driver
+ *
+ * Copyright (c) 2012 DENX Software Engineering, GmbH.
+ * Copyright (c) 2017 Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
+ *
+ * Authors:
+ *  Marek Vasut <marex@denx.de>
+ *  Ksenija Stanojevic <ksenija.stanojevic@gmail.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/device.h>
+#include <linux/err.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mxs-lradc.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+const char *mxs_lradc_ts_irq_names[] = {
+	"mxs-lradc-touchscreen",
+	"mxs-lradc-channel6",
+	"mxs-lradc-channel7",
+};
+
+/*
+ * Touchscreen handling
+ */
+enum mxs_lradc_ts_plate {
+	LRADC_TOUCH = 0,
+	LRADC_SAMPLE_X,
+	LRADC_SAMPLE_Y,
+	LRADC_SAMPLE_PRESSURE,
+	LRADC_SAMPLE_VALID,
+};
+
+struct mxs_lradc_ts {
+	struct mxs_lradc	*lradc;
+	struct device		*dev;
+
+	void __iomem		*base;
+	/*
+	 * When the touchscreen is enabled, we give it two private virtual
+	 * channels: #6 and #7. This means that only 6 virtual channels (instead
+	 * of 8) will be available for buffered capture.
+	 */
+#define TOUCHSCREEN_VCHANNEL1		7
+#define TOUCHSCREEN_VCHANNEL2		6
+
+	struct input_dev	*ts_input;
+
+	enum mxs_lradc_ts_plate	cur_plate; /* state machine */
+	bool			ts_valid;
+	unsigned int		ts_x_pos;
+	unsigned int		ts_y_pos;
+	unsigned int		ts_pressure;
+
+	/* handle touchscreen's physical behaviour */
+	/* samples per coordinate */
+	unsigned int		over_sample_cnt;
+	/* time clocks between samples */
+	unsigned int		over_sample_delay;
+	/* time in clocks to wait after the plates where switched */
+	unsigned int		settling_delay;
+	spinlock_t		lock;
+};
+
+struct state_info {
+	u32		mask;
+	u32		bit;
+	u32		x_plate;
+	u32		y_plate;
+	u32		pressure;
+};
+
+static struct state_info info[] = {
+	{LRADC_CTRL0_MX23_PLATE_MASK, LRADC_CTRL0_MX23_TOUCH_DETECT_ENABLE,
+	 LRADC_CTRL0_MX23_XP | LRADC_CTRL0_MX23_XM,
+	 LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_YM,
+	 LRADC_CTRL0_MX23_YP | LRADC_CTRL0_MX23_XM},
+	{LRADC_CTRL0_MX28_PLATE_MASK, LRADC_CTRL0_MX28_TOUCH_DETECT_ENABLE,
+	 LRADC_CTRL0_MX28_XPPSW | LRADC_CTRL0_MX28_XNNSW,
+	 LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_YNNSW,
+	 LRADC_CTRL0_MX28_YPPSW | LRADC_CTRL0_MX28_XNNSW}
+};
+
+static bool mxs_lradc_check_touch_event(struct mxs_lradc_ts *ts)
+{
+	return !!(readl(ts->base + LRADC_STATUS) &
+					LRADC_STATUS_TOUCH_DETECT_RAW);
+}
+
+static void mxs_lradc_map_ts_channel(struct mxs_lradc_ts *ts, unsigned int vch,
+				     unsigned int ch)
+{
+	writel(LRADC_CTRL4_LRADCSELECT_MASK(vch),
+	       ts->base + LRADC_CTRL4 + STMP_OFFSET_REG_CLR);
+	writel(LRADC_CTRL4_LRADCSELECT(vch, ch),
+	       ts->base + LRADC_CTRL4 + STMP_OFFSET_REG_SET);
+}
+
+static void mxs_lradc_setup_ts_channel(struct mxs_lradc_ts *ts, unsigned int ch)
+{
+	/*
+	 * prepare for oversampling conversion
+	 *
+	 * from the datasheet:
+	 * "The ACCUMULATE bit in the appropriate channel register
+	 * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0;
+	 * otherwise, the IRQs will not fire."
+	 */
+	writel(LRADC_CH_ACCUMULATE |
+	       LRADC_CH_NUM_SAMPLES(ts->over_sample_cnt - 1),
+	       ts->base + LRADC_CH(ch));
+
+	/* from the datasheet:
+	 * "Software must clear this register in preparation for a
+	 * multi-cycle accumulation.
+	 */
+	writel(LRADC_CH_VALUE_MASK,
+	       ts->base + LRADC_CH(ch) + STMP_OFFSET_REG_CLR);
+
+	/*
+	 * prepare the delay/loop unit according to the oversampling count
+	 *
+	 * from the datasheet:
+	 * "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1,
+	 * HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise,
+	 * the LRADC will not trigger the delay group."
+	 */
+	writel(LRADC_DELAY_TRIGGER(1 << ch) | LRADC_DELAY_TRIGGER_DELAYS(0) |
+	       LRADC_DELAY_LOOP(ts->over_sample_cnt - 1) |
+	       LRADC_DELAY_DELAY(ts->over_sample_delay - 1),
+	       ts->base + LRADC_DELAY(3));
+
+	writel(LRADC_CTRL1_LRADC_IRQ(ch),
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	/*
+	 * after changing the touchscreen plates setting
+	 * the signals need some initial time to settle. Start the
+	 * SoC's delay unit and start the conversion later
+	 * and automatically.
+	 */
+	writel(LRADC_DELAY_TRIGGER(0) | LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) |
+	       LRADC_DELAY_KICK | LRADC_DELAY_DELAY(ts->settling_delay),
+	       ts->base + LRADC_DELAY(2));
+}
+
+/*
+ * Pressure detection is special:
+ * We want to do both required measurements for the pressure detection in
+ * one turn. Use the hardware features to chain both conversions and let the
+ * hardware report one interrupt if both conversions are done
+ */
+static void mxs_lradc_setup_ts_pressure(struct mxs_lradc_ts *ts,
+					unsigned int ch1, unsigned int ch2)
+{
+	u32 reg;
+
+	/*
+	 * prepare for oversampling conversion
+	 *
+	 * from the datasheet:
+	 * "The ACCUMULATE bit in the appropriate channel register
+	 * HW_LRADC_CHn must be set to 1 if NUM_SAMPLES is greater then 0;
+	 * otherwise, the IRQs will not fire."
+	 */
+	reg = LRADC_CH_ACCUMULATE |
+		LRADC_CH_NUM_SAMPLES(ts->over_sample_cnt - 1);
+	writel(reg, ts->base + LRADC_CH(ch1));
+	writel(reg, ts->base + LRADC_CH(ch2));
+
+	/* from the datasheet:
+	 * "Software must clear this register in preparation for a
+	 * multi-cycle accumulation.
+	 */
+	writel(LRADC_CH_VALUE_MASK,
+	       ts->base + LRADC_CH(ch1) + STMP_OFFSET_REG_CLR);
+	writel(LRADC_CH_VALUE_MASK,
+	       ts->base + LRADC_CH(ch2) + STMP_OFFSET_REG_CLR);
+
+	/* prepare the delay/loop unit according to the oversampling count */
+	writel(LRADC_DELAY_TRIGGER(1 << ch1) | LRADC_DELAY_TRIGGER(1 << ch2) |
+	       LRADC_DELAY_TRIGGER_DELAYS(0) |
+	       LRADC_DELAY_LOOP(ts->over_sample_cnt - 1) |
+	       LRADC_DELAY_DELAY(ts->over_sample_delay - 1),
+	       ts->base + LRADC_DELAY(3));
+
+	writel(LRADC_CTRL1_LRADC_IRQ(ch2),
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	/*
+	 * after changing the touchscreen plates setting
+	 * the signals need some initial time to settle. Start the
+	 * SoC's delay unit and start the conversion later
+	 * and automatically.
+	 */
+	writel(LRADC_DELAY_TRIGGER(0) | LRADC_DELAY_TRIGGER_DELAYS(BIT(3)) |
+	       LRADC_DELAY_KICK | LRADC_DELAY_DELAY(ts->settling_delay),
+	       ts->base + LRADC_DELAY(2));
+}
+
+static unsigned int mxs_lradc_ts_read_raw_channel(struct mxs_lradc_ts *ts,
+						  unsigned int channel)
+{
+	u32 reg;
+	unsigned int num_samples, val;
+
+	reg = readl(ts->base + LRADC_CH(channel));
+	if (reg & LRADC_CH_ACCUMULATE)
+		num_samples = ts->over_sample_cnt;
+	else
+		num_samples = 1;
+
+	val = (reg & LRADC_CH_VALUE_MASK) >> LRADC_CH_VALUE_OFFSET;
+	return val / num_samples;
+}
+
+static unsigned int mxs_lradc_read_ts_pressure(struct mxs_lradc_ts *ts,
+					unsigned int ch1, unsigned int ch2)
+{
+	u32 reg, mask;
+	unsigned int pressure, m1, m2;
+
+	mask = LRADC_CTRL1_LRADC_IRQ(ch1) | LRADC_CTRL1_LRADC_IRQ(ch2);
+	reg = readl(ts->base + LRADC_CTRL1) & mask;
+
+	while (reg != mask) {
+		reg = readl(ts->base + LRADC_CTRL1) & mask;
+		dev_dbg(ts->dev, "One channel is still busy: %X\n", reg);
+	}
+
+	m1 = mxs_lradc_ts_read_raw_channel(ts, ch1);
+	m2 = mxs_lradc_ts_read_raw_channel(ts, ch2);
+
+	if (m2 == 0) {
+		dev_warn(ts->dev, "Cannot calculate pressure\n");
+		return 1 << (LRADC_RESOLUTION - 1);
+	}
+
+	/* simply scale the value from 0 ... max ADC resolution */
+	pressure = m1;
+	pressure *= (1 << LRADC_RESOLUTION);
+	pressure /= m2;
+
+	dev_dbg(ts->dev, "Pressure = %u\n", pressure);
+	return pressure;
+}
+
+#define TS_CH_XP 2
+#define TS_CH_YP 3
+#define TS_CH_XM 4
+#define TS_CH_YM 5
+
+/*
+ * YP(open)--+-------------+
+ *	     |		   |--+
+ *	     |		   |  |
+ *    YM(-)--+-------------+  |
+ *	       +--------------+
+ *	       |	      |
+ *	   XP(weak+)	    XM(open)
+ *
+ * "weak+" means 200k Ohm VDDIO
+ * (-) means GND
+ */
+static void mxs_lradc_setup_touch_detection(struct mxs_lradc_ts *ts)
+{
+	struct mxs_lradc *lradc = ts->lradc;
+
+	/*
+	 * In order to detect a touch event the 'touch detect enable' bit
+	 * enables:
+	 *  - a weak pullup to the X+ connector
+	 *  - a strong ground at the Y- connector
+	 */
+	writel(info[lradc->soc].mask,
+	       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+	writel(info[lradc->soc].bit,
+	       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+}
+
+/*
+ * YP(meas)--+-------------+
+ *	     |		   |--+
+ *	     |		   |  |
+ * YM(open)--+-------------+  |
+ *	       +--------------+
+ *	       |	      |
+ *	     XP(+)	    XM(-)
+ *
+ * (+) means here 1.85 V
+ * (-) means here GND
+ */
+static void mxs_lradc_prepare_x_pos(struct mxs_lradc_ts *ts)
+{
+	struct mxs_lradc *lradc = ts->lradc;
+
+	writel(info[lradc->soc].mask,
+	       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+	writel(info[lradc->soc].x_plate,
+	       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+	ts->cur_plate = LRADC_SAMPLE_X;
+	mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL1, TS_CH_YP);
+	mxs_lradc_setup_ts_channel(ts, TOUCHSCREEN_VCHANNEL1);
+}
+
+/*
+ *   YP(+)--+-------------+
+ *	    |		  |--+
+ *	    |		  |  |
+ *   YM(-)--+-------------+  |
+ *	      +--------------+
+ *	      |		     |
+ *	   XP(open)	   XM(meas)
+ *
+ * (+) means here 1.85 V
+ * (-) means here GND
+ */
+static void mxs_lradc_prepare_y_pos(struct mxs_lradc_ts *ts)
+{
+	struct mxs_lradc *lradc = ts->lradc;
+
+	writel(info[lradc->soc].mask,
+	       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+	writel(info[lradc->soc].y_plate,
+	       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+	ts->cur_plate = LRADC_SAMPLE_Y;
+	mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL1, TS_CH_XM);
+	mxs_lradc_setup_ts_channel(ts, TOUCHSCREEN_VCHANNEL1);
+}
+
+/*
+ *    YP(+)--+-------------+
+ *	     |		   |--+
+ *	     |		   |  |
+ * YM(meas)--+-------------+  |
+ *	       +--------------+
+ *	       |	      |
+ *	    XP(meas)	    XM(-)
+ *
+ * (+) means here 1.85 V
+ * (-) means here GND
+ */
+static void mxs_lradc_prepare_pressure(struct mxs_lradc_ts *ts)
+{
+	struct mxs_lradc *lradc = ts->lradc;
+
+	writel(info[lradc->soc].mask,
+	       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+	writel(info[lradc->soc].pressure,
+	       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+	ts->cur_plate = LRADC_SAMPLE_PRESSURE;
+	mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL1, TS_CH_YM);
+	mxs_lradc_map_ts_channel(ts, TOUCHSCREEN_VCHANNEL2, TS_CH_XP);
+	mxs_lradc_setup_ts_pressure(ts, TOUCHSCREEN_VCHANNEL2,
+				    TOUCHSCREEN_VCHANNEL1);
+}
+
+static void mxs_lradc_enable_touch_detection(struct mxs_lradc_ts *ts)
+{
+	mxs_lradc_setup_touch_detection(ts);
+
+	ts->cur_plate = LRADC_TOUCH;
+	writel(LRADC_CTRL1_TOUCH_DETECT_IRQ | LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+	writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+}
+
+static void mxs_lradc_start_touch_event(struct mxs_lradc_ts *ts)
+{
+	writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+	writel(LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1),
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+	/*
+	 * start with the Y-pos, because it uses nearly the same plate
+	 * settings like the touch detection
+	 */
+	mxs_lradc_prepare_y_pos(ts);
+}
+
+static void mxs_lradc_report_ts_event(struct mxs_lradc_ts *ts)
+{
+	input_report_abs(ts->ts_input, ABS_X, ts->ts_x_pos);
+	input_report_abs(ts->ts_input, ABS_Y, ts->ts_y_pos);
+	input_report_abs(ts->ts_input, ABS_PRESSURE, ts->ts_pressure);
+	input_report_key(ts->ts_input, BTN_TOUCH, 1);
+	input_sync(ts->ts_input);
+}
+
+static void mxs_lradc_complete_touch_event(struct mxs_lradc_ts *ts)
+{
+	mxs_lradc_setup_touch_detection(ts);
+	ts->cur_plate = LRADC_SAMPLE_VALID;
+	/*
+	 * start a dummy conversion to burn time to settle the signals
+	 * note: we are not interested in the conversion's value
+	 */
+	writel(0, ts->base + LRADC_CH(TOUCHSCREEN_VCHANNEL1));
+	writel(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+	       LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2),
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+	writel(LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) |
+	       LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10),
+	       ts->base + LRADC_DELAY(2));
+}
+
+/*
+ * in order to avoid false measurements, report only samples where
+ * the surface is still touched after the position measurement
+ */
+static void mxs_lradc_finish_touch_event(struct mxs_lradc_ts *ts, bool valid)
+{
+	/* if it is still touched, report the sample */
+	if (valid && mxs_lradc_check_touch_event(ts)) {
+		ts->ts_valid = true;
+		mxs_lradc_report_ts_event(ts);
+	}
+
+	/* if it is even still touched, continue with the next measurement */
+	if (mxs_lradc_check_touch_event(ts)) {
+		mxs_lradc_prepare_y_pos(ts);
+		return;
+	}
+
+	if (ts->ts_valid) {
+		/* signal the release */
+		ts->ts_valid = false;
+		input_report_key(ts->ts_input, BTN_TOUCH, 0);
+		input_sync(ts->ts_input);
+	}
+
+	/* if it is released, wait for the next touch via IRQ */
+	ts->cur_plate = LRADC_TOUCH;
+	writel(0, ts->base + LRADC_DELAY(2));
+	writel(0, ts->base + LRADC_DELAY(3));
+	writel(LRADC_CTRL1_TOUCH_DETECT_IRQ |
+	       LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+	       LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1),
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+	writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN,
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+}
+
+/* touchscreen's state machine */
+static void mxs_lradc_handle_touch(struct mxs_lradc_ts *ts)
+{
+	switch (ts->cur_plate) {
+	case LRADC_TOUCH:
+		if (mxs_lradc_check_touch_event(ts))
+			mxs_lradc_start_touch_event(ts);
+		writel(LRADC_CTRL1_TOUCH_DETECT_IRQ,
+		       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+		return;
+
+	case LRADC_SAMPLE_Y:
+		ts->ts_y_pos =
+		    mxs_lradc_ts_read_raw_channel(ts, TOUCHSCREEN_VCHANNEL1);
+		mxs_lradc_prepare_x_pos(ts);
+		return;
+
+	case LRADC_SAMPLE_X:
+		ts->ts_x_pos =
+		    mxs_lradc_ts_read_raw_channel(ts, TOUCHSCREEN_VCHANNEL1);
+		mxs_lradc_prepare_pressure(ts);
+		return;
+
+	case LRADC_SAMPLE_PRESSURE:
+		ts->ts_pressure =
+		    mxs_lradc_read_ts_pressure(ts,
+					       TOUCHSCREEN_VCHANNEL2,
+					       TOUCHSCREEN_VCHANNEL1);
+		mxs_lradc_complete_touch_event(ts);
+		return;
+
+	case LRADC_SAMPLE_VALID:
+		mxs_lradc_finish_touch_event(ts, 1);
+		break;
+	}
+}
+
+/* IRQ Handling */
+static irqreturn_t mxs_lradc_ts_handle_irq(int irq, void *data)
+{
+	struct mxs_lradc_ts *ts = data;
+	struct mxs_lradc *lradc = ts->lradc;
+	unsigned long reg = readl(ts->base + LRADC_CTRL1);
+	u32 clr_irq = mxs_lradc_irq_mask(lradc);
+	const u32 ts_irq_mask =
+		LRADC_CTRL1_TOUCH_DETECT_IRQ |
+		LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+		LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2);
+	unsigned long flags;
+
+	if (!(reg & mxs_lradc_irq_mask(lradc)))
+		return IRQ_NONE;
+
+	if (reg & ts_irq_mask) {
+		spin_lock_irqsave(&ts->lock, flags);
+		mxs_lradc_handle_touch(ts);
+		spin_unlock_irqrestore(&ts->lock, flags);
+		/* Make sure we don't clear the next conversion's interrupt. */
+		clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
+				LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2));
+		writel(reg & clr_irq,
+		       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mxs_lradc_ts_open(struct input_dev *dev)
+{
+	struct mxs_lradc_ts *ts = input_get_drvdata(dev);
+
+	/* Enable the touch-detect circuitry. */
+	mxs_lradc_enable_touch_detection(ts);
+
+	return 0;
+}
+
+static void mxs_lradc_ts_stop(struct mxs_lradc_ts *ts)
+{
+	int i;
+	struct mxs_lradc *lradc = ts->lradc;
+
+	/* stop all interrupts from firing */
+	writel(LRADC_CTRL1_TOUCH_DETECT_IRQ_EN |
+	       LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) |
+	       LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2),
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	/* Power-down touchscreen touch-detect circuitry. */
+	writel(info[lradc->soc].mask,
+	       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+	writel(lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
+	       ts->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+	for (i = 1; i < LRADC_MAX_DELAY_CHANS; i++)
+		writel(0, ts->base + LRADC_DELAY(i));
+}
+
+static void mxs_lradc_ts_close(struct input_dev *dev)
+{
+	struct mxs_lradc_ts *ts = input_get_drvdata(dev);
+
+	mxs_lradc_ts_stop(ts);
+}
+
+static void mxs_lradc_ts_hw_init(struct mxs_lradc_ts *ts)
+{
+	struct mxs_lradc *lradc = ts->lradc;
+
+	/* Configure the touchscreen type */
+	if (lradc->soc == IMX28_LRADC) {
+		writel(LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
+		       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+		if (lradc->touchscreen_wire == MXS_LRADC_TOUCHSCREEN_5WIRE)
+			writel(LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
+			       ts->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+	}
+}
+
+static int mxs_lradc_ts_register(struct mxs_lradc_ts *ts)
+{
+	struct input_dev *input = ts->ts_input;
+	struct device *dev = ts->dev;
+
+	input = devm_input_allocate_device(dev);
+	if (!input)
+		return -ENOMEM;
+
+	input->name = "mxs-lradc-ts";
+	input->id.bustype = BUS_HOST;
+	input->open = mxs_lradc_ts_open;
+	input->close = mxs_lradc_ts_close;
+
+	__set_bit(INPUT_PROP_DIRECT, input->propbit);
+	input_set_capability(input, EV_KEY, BTN_TOUCH);
+	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,
+			     0, 0);
+
+	ts->ts_input = input;
+	input_set_drvdata(input, ts);
+
+	return input_register_device(input);
+}
+
+static int mxs_lradc_ts_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->parent->of_node;
+	struct mxs_lradc *lradc = dev_get_drvdata(dev->parent);
+	struct mxs_lradc_ts *ts;
+	struct resource *iores;
+	int ret, irq, virq, i;
+	u32 ts_wires = 0, adapt;
+
+	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, ts);
+
+	ts->lradc = lradc;
+	ts->dev = dev;
+	spin_lock_init(&ts->lock);
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ts->base = devm_ioremap(dev, iores->start, resource_size(iores));
+	if (IS_ERR(ts->base))
+		return PTR_ERR(ts->base);
+
+	ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires",
+				   &ts_wires);
+	if (ret)
+		return ret;
+
+	if (of_property_read_u32(node, "fsl,ave-ctrl", &adapt)) {
+		ts->over_sample_cnt = 4;
+	} else {
+		if (adapt >= 1 && adapt <= 32) {
+			ts->over_sample_cnt = adapt;
+		} else {
+			dev_err(ts->dev, "Invalid sample count (%u)\n",
+				adapt);
+			return -EINVAL;
+		}
+	}
+
+	if (of_property_read_u32(node, "fsl,ave-delay", &adapt)) {
+		ts->over_sample_delay = 2;
+	} else {
+		if (adapt >= 2 && adapt <= LRADC_DELAY_DELAY_MASK + 1) {
+			ts->over_sample_delay = adapt;
+		} else {
+			dev_err(ts->dev, "Invalid sample delay (%u)\n",
+				adapt);
+			return -EINVAL;
+		}
+	}
+
+	if (of_property_read_u32(node, "fsl,settling", &adapt)) {
+		ts->settling_delay = 10;
+	} else {
+		if (adapt >= 1 && adapt <= LRADC_DELAY_DELAY_MASK) {
+			ts->settling_delay = adapt;
+		} else {
+			dev_err(ts->dev, "Invalid settling delay (%u)\n",
+				adapt);
+			return -EINVAL;
+		}
+	}
+
+	ret = stmp_reset_block(ts->base);
+	if (ret)
+		return ret;
+
+	mxs_lradc_ts_hw_init(ts);
+
+	for (i = 0; i < 3; i++) {
+		irq = platform_get_irq_byname(pdev, mxs_lradc_ts_irq_names[i]);
+		if (irq < 0)
+			return irq;
+
+		virq = irq_of_parse_and_map(node, irq);
+
+		mxs_lradc_ts_stop(ts);
+
+		ret = devm_request_irq(dev, virq,
+				       mxs_lradc_ts_handle_irq,
+				       0, mxs_lradc_ts_irq_names[i], ts);
+		if (ret)
+			return ret;
+	}
+
+	return mxs_lradc_ts_register(ts);
+}
+
+static struct platform_driver mxs_lradc_ts_driver = {
+	.driver	= {
+		.name = "mxs-lradc-ts",
+	},
+	.probe	= mxs_lradc_ts_probe,
+};
+module_platform_driver(mxs_lradc_ts_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Freescale MXS LRADC touchscreen driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxs-lradc-ts");
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index ec80e35c8dfe..3ecc429297a0 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -30,6 +30,7 @@ config ATMEL_EBI
 	default y
 	depends on ARCH_AT91 && OF
 	select MFD_SYSCON
+	select MFD_ATMEL_SMC
 	help
 	  Driver for Atmel EBI controller.
 	  Used to configure the EBI (external bus interface) when the device-
diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c
index 4e83a8b92665..35910f945bfa 100644
--- a/drivers/memory/atmel-ebi.c
+++ b/drivers/memory/atmel-ebi.c
@@ -18,219 +18,157 @@
 #include <linux/of_device.h>
 #include <linux/regmap.h>
 
-struct at91sam9_smc_timings {
-	u32 ncs_rd_setup_ns;
-	u32 nrd_setup_ns;
-	u32 ncs_wr_setup_ns;
-	u32 nwe_setup_ns;
-	u32 ncs_rd_pulse_ns;
-	u32 nrd_pulse_ns;
-	u32 ncs_wr_pulse_ns;
-	u32 nwe_pulse_ns;
-	u32 nrd_cycle_ns;
-	u32 nwe_cycle_ns;
-	u32 tdf_ns;
-};
-
-struct at91sam9_smc_generic_fields {
-	struct regmap_field *setup;
-	struct regmap_field *pulse;
-	struct regmap_field *cycle;
-	struct regmap_field *mode;
-};
-
-struct at91sam9_ebi_dev_config {
-	struct at91sam9_smc_timings timings;
-	u32 mode;
-};
-
-struct at91_ebi_dev_config {
+struct atmel_ebi_dev_config {
 	int cs;
-	union {
-		struct at91sam9_ebi_dev_config sam9;
-	};
+	struct atmel_smc_cs_conf smcconf;
 };
 
-struct at91_ebi;
+struct atmel_ebi;
 
-struct at91_ebi_dev {
+struct atmel_ebi_dev {
 	struct list_head node;
-	struct at91_ebi *ebi;
+	struct atmel_ebi *ebi;
 	u32 mode;
 	int numcs;
-	struct at91_ebi_dev_config configs[];
+	struct atmel_ebi_dev_config configs[];
 };
 
-struct at91_ebi_caps {
+struct atmel_ebi_caps {
 	unsigned int available_cs;
-	const struct reg_field *ebi_csa;
-	void (*get_config)(struct at91_ebi_dev *ebid,
-			   struct at91_ebi_dev_config *conf);
-	int (*xlate_config)(struct at91_ebi_dev *ebid,
+	unsigned int ebi_csa_offs;
+	void (*get_config)(struct atmel_ebi_dev *ebid,
+			   struct atmel_ebi_dev_config *conf);
+	int (*xlate_config)(struct atmel_ebi_dev *ebid,
 			    struct device_node *configs_np,
-			    struct at91_ebi_dev_config *conf);
-	int (*apply_config)(struct at91_ebi_dev *ebid,
-			    struct at91_ebi_dev_config *conf);
-	int (*init)(struct at91_ebi *ebi);
+			    struct atmel_ebi_dev_config *conf);
+	void (*apply_config)(struct atmel_ebi_dev *ebid,
+			     struct atmel_ebi_dev_config *conf);
 };
 
-struct at91_ebi {
+struct atmel_ebi {
 	struct clk *clk;
 	struct regmap *matrix;
 	struct  {
 		struct regmap *regmap;
 		struct clk *clk;
 	} smc;
-	struct regmap_field *ebi_csa;
 
 	struct device *dev;
-	const struct at91_ebi_caps *caps;
+	const struct atmel_ebi_caps *caps;
 	struct list_head devs;
-	union {
-		struct at91sam9_smc_generic_fields sam9;
-	};
 };
 
-static void at91sam9_ebi_get_config(struct at91_ebi_dev *ebid,
-				    struct at91_ebi_dev_config *conf)
-{
-	struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
-	unsigned int clk_period = NSEC_PER_SEC / clk_get_rate(ebid->ebi->clk);
-	struct at91sam9_ebi_dev_config *config = &conf->sam9;
-	struct at91sam9_smc_timings *timings = &config->timings;
-	unsigned int val;
-
-	regmap_fields_read(fields->mode, conf->cs, &val);
-	config->mode = val & ~AT91_SMC_TDF;
-
-	val = (val & AT91_SMC_TDF) >> 16;
-	timings->tdf_ns = clk_period * val;
-
-	regmap_fields_read(fields->setup, conf->cs, &val);
-	timings->ncs_rd_setup_ns = (val >> 24) & 0x1f;
-	timings->ncs_rd_setup_ns += ((val >> 29) & 0x1) * 128;
-	timings->ncs_rd_setup_ns *= clk_period;
-	timings->nrd_setup_ns = (val >> 16) & 0x1f;
-	timings->nrd_setup_ns += ((val >> 21) & 0x1) * 128;
-	timings->nrd_setup_ns *= clk_period;
-	timings->ncs_wr_setup_ns = (val >> 8) & 0x1f;
-	timings->ncs_wr_setup_ns += ((val >> 13) & 0x1) * 128;
-	timings->ncs_wr_setup_ns *= clk_period;
-	timings->nwe_setup_ns = val & 0x1f;
-	timings->nwe_setup_ns += ((val >> 5) & 0x1) * 128;
-	timings->nwe_setup_ns *= clk_period;
-
-	regmap_fields_read(fields->pulse, conf->cs, &val);
-	timings->ncs_rd_pulse_ns = (val >> 24) & 0x3f;
-	timings->ncs_rd_pulse_ns += ((val >> 30) & 0x1) * 256;
-	timings->ncs_rd_pulse_ns *= clk_period;
-	timings->nrd_pulse_ns = (val >> 16) & 0x3f;
-	timings->nrd_pulse_ns += ((val >> 22) & 0x1) * 256;
-	timings->nrd_pulse_ns *= clk_period;
-	timings->ncs_wr_pulse_ns = (val >> 8) & 0x3f;
-	timings->ncs_wr_pulse_ns += ((val >> 14) & 0x1) * 256;
-	timings->ncs_wr_pulse_ns *= clk_period;
-	timings->nwe_pulse_ns = val & 0x3f;
-	timings->nwe_pulse_ns += ((val >> 6) & 0x1) * 256;
-	timings->nwe_pulse_ns *= clk_period;
-
-	regmap_fields_read(fields->cycle, conf->cs, &val);
-	timings->nrd_cycle_ns = (val >> 16) & 0x7f;
-	timings->nrd_cycle_ns += ((val >> 23) & 0x3) * 256;
-	timings->nrd_cycle_ns *= clk_period;
-	timings->nwe_cycle_ns = val & 0x7f;
-	timings->nwe_cycle_ns += ((val >> 7) & 0x3) * 256;
-	timings->nwe_cycle_ns *= clk_period;
-}
+struct atmel_smc_timing_xlate {
+	const char *name;
+	int (*converter)(struct atmel_smc_cs_conf *conf,
+			 unsigned int shift, unsigned int nycles);
+	unsigned int shift;
+};
 
-static int at91_xlate_timing(struct device_node *np, const char *prop,
-			     u32 *val, bool *required)
-{
-	if (!of_property_read_u32(np, prop, val)) {
-		*required = true;
-		return 0;
-	}
+#define ATMEL_SMC_SETUP_XLATE(nm, pos)	\
+	{ .name = nm, .converter = atmel_smc_cs_conf_set_setup, .shift = pos}
 
-	if (*required)
-		return -EINVAL;
+#define ATMEL_SMC_PULSE_XLATE(nm, pos)	\
+	{ .name = nm, .converter = atmel_smc_cs_conf_set_pulse, .shift = pos}
 
-	return 0;
-}
+#define ATMEL_SMC_CYCLE_XLATE(nm, pos)	\
+	{ .name = nm, .converter = atmel_smc_cs_conf_set_setup, .shift = pos}
 
-static int at91sam9_smc_xslate_timings(struct at91_ebi_dev *ebid,
-				       struct device_node *np,
-				       struct at91sam9_smc_timings *timings,
-				       bool *required)
+static void at91sam9_ebi_get_config(struct atmel_ebi_dev *ebid,
+				    struct atmel_ebi_dev_config *conf)
 {
-	int ret;
-
-	ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-setup-ns",
-				&timings->ncs_rd_setup_ns, required);
-	if (ret)
-		goto out;
+	atmel_smc_cs_conf_get(ebid->ebi->smc.regmap, conf->cs,
+			      &conf->smcconf);
+}
 
-	ret = at91_xlate_timing(np, "atmel,smc-nrd-setup-ns",
-				&timings->nrd_setup_ns, required);
-	if (ret)
-		goto out;
+static void sama5_ebi_get_config(struct atmel_ebi_dev *ebid,
+				 struct atmel_ebi_dev_config *conf)
+{
+	atmel_hsmc_cs_conf_get(ebid->ebi->smc.regmap, conf->cs,
+			       &conf->smcconf);
+}
 
-	ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-setup-ns",
-				&timings->ncs_wr_setup_ns, required);
-	if (ret)
-		goto out;
+static const struct atmel_smc_timing_xlate timings_xlate_table[] = {
+	ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-rd-setup-ns",
+			      ATMEL_SMC_NCS_RD_SHIFT),
+	ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-wr-setup-ns",
+			      ATMEL_SMC_NCS_WR_SHIFT),
+	ATMEL_SMC_SETUP_XLATE("atmel,smc-nrd-setup-ns", ATMEL_SMC_NRD_SHIFT),
+	ATMEL_SMC_SETUP_XLATE("atmel,smc-nwe-setup-ns", ATMEL_SMC_NWE_SHIFT),
+	ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-rd-pulse-ns",
+			      ATMEL_SMC_NCS_RD_SHIFT),
+	ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-wr-pulse-ns",
+			      ATMEL_SMC_NCS_WR_SHIFT),
+	ATMEL_SMC_PULSE_XLATE("atmel,smc-nrd-pulse-ns", ATMEL_SMC_NRD_SHIFT),
+	ATMEL_SMC_PULSE_XLATE("atmel,smc-nwe-pulse-ns", ATMEL_SMC_NWE_SHIFT),
+	ATMEL_SMC_CYCLE_XLATE("atmel,smc-nrd-cycle-ns", ATMEL_SMC_NRD_SHIFT),
+	ATMEL_SMC_CYCLE_XLATE("atmel,smc-nwe-cycle-ns", ATMEL_SMC_NWE_SHIFT),
+};
 
-	ret = at91_xlate_timing(np, "atmel,smc-nwe-setup-ns",
-				&timings->nwe_setup_ns, required);
-	if (ret)
-		goto out;
+static int atmel_ebi_xslate_smc_timings(struct atmel_ebi_dev *ebid,
+					struct device_node *np,
+					struct atmel_smc_cs_conf *smcconf)
+{
+	unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
+	unsigned int clk_period_ns = NSEC_PER_SEC / clk_rate;
+	bool required = false;
+	unsigned int ncycles;
+	int ret, i;
+	u32 val;
 
-	ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-pulse-ns",
-				&timings->ncs_rd_pulse_ns, required);
-	if (ret)
-		goto out;
+	ret = of_property_read_u32(np, "atmel,smc-tdf-ns", &val);
+	if (!ret) {
+		required = true;
+		ncycles = DIV_ROUND_UP(val, clk_period_ns);
+		if (ncycles > ATMEL_SMC_MODE_TDF_MAX ||
+		    ncycles < ATMEL_SMC_MODE_TDF_MIN) {
+			ret = -EINVAL;
+			goto out;
+		}
 
-	ret = at91_xlate_timing(np, "atmel,smc-nrd-pulse-ns",
-				&timings->nrd_pulse_ns, required);
-	if (ret)
-		goto out;
+		smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles);
+	}
 
-	ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-pulse-ns",
-				&timings->ncs_wr_pulse_ns, required);
-	if (ret)
-		goto out;
+	for (i = 0; i < ARRAY_SIZE(timings_xlate_table); i++) {
+		const struct atmel_smc_timing_xlate *xlate;
 
-	ret = at91_xlate_timing(np, "atmel,smc-nwe-pulse-ns",
-				&timings->nwe_pulse_ns, required);
-	if (ret)
-		goto out;
+		xlate = &timings_xlate_table[i];
 
-	ret = at91_xlate_timing(np, "atmel,smc-nwe-cycle-ns",
-				&timings->nwe_cycle_ns, required);
-	if (ret)
-		goto out;
+		ret = of_property_read_u32(np, xlate->name, &val);
+		if (ret) {
+			if (!required)
+				continue;
+			else
+				break;
+		}
 
-	ret = at91_xlate_timing(np, "atmel,smc-nrd-cycle-ns",
-				&timings->nrd_cycle_ns, required);
-	if (ret)
-		goto out;
+		if (!required) {
+			ret = -EINVAL;
+			break;
+		}
 
-	ret = at91_xlate_timing(np, "atmel,smc-tdf-ns",
-				&timings->tdf_ns, required);
+		ncycles = DIV_ROUND_UP(val, clk_period_ns);
+		ret = xlate->converter(smcconf, xlate->shift, ncycles);
+		if (ret)
+			goto out;
+	}
 
 out:
-	if (ret)
+	if (ret) {
 		dev_err(ebid->ebi->dev,
 			"missing or invalid timings definition in %s",
 			np->full_name);
+		return ret;
+	}
 
-	return ret;
+	return required;
 }
 
-static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid,
-				      struct device_node *np,
-				      struct at91_ebi_dev_config *conf)
+static int atmel_ebi_xslate_smc_config(struct atmel_ebi_dev *ebid,
+				       struct device_node *np,
+				       struct atmel_ebi_dev_config *conf)
 {
-	struct at91sam9_ebi_dev_config *config = &conf->sam9;
+	struct atmel_smc_cs_conf *smcconf = &conf->smcconf;
 	bool required = false;
 	const char *tmp_str;
 	u32 tmp;
@@ -240,15 +178,15 @@ static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid,
 	if (!ret) {
 		switch (tmp) {
 		case 8:
-			config->mode |= AT91_SMC_DBW_8;
+			smcconf->mode |= ATMEL_SMC_MODE_DBW_8;
 			break;
 
 		case 16:
-			config->mode |= AT91_SMC_DBW_16;
+			smcconf->mode |= ATMEL_SMC_MODE_DBW_16;
 			break;
 
 		case 32:
-			config->mode |= AT91_SMC_DBW_32;
+			smcconf->mode |= ATMEL_SMC_MODE_DBW_32;
 			break;
 
 		default:
@@ -259,28 +197,28 @@ static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid,
 	}
 
 	if (of_property_read_bool(np, "atmel,smc-tdf-optimized")) {
-		config->mode |= AT91_SMC_TDFMODE_OPTIMIZED;
+		smcconf->mode |= ATMEL_SMC_MODE_TDFMODE_OPTIMIZED;
 		required = true;
 	}
 
 	tmp_str = NULL;
 	of_property_read_string(np, "atmel,smc-byte-access-type", &tmp_str);
 	if (tmp_str && !strcmp(tmp_str, "write")) {
-		config->mode |= AT91_SMC_BAT_WRITE;
+		smcconf->mode |= ATMEL_SMC_MODE_BAT_WRITE;
 		required = true;
 	}
 
 	tmp_str = NULL;
 	of_property_read_string(np, "atmel,smc-read-mode", &tmp_str);
 	if (tmp_str && !strcmp(tmp_str, "nrd")) {
-		config->mode |= AT91_SMC_READMODE_NRD;
+		smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD;
 		required = true;
 	}
 
 	tmp_str = NULL;
 	of_property_read_string(np, "atmel,smc-write-mode", &tmp_str);
 	if (tmp_str && !strcmp(tmp_str, "nwe")) {
-		config->mode |= AT91_SMC_WRITEMODE_NWE;
+		smcconf->mode |= ATMEL_SMC_MODE_WRITEMODE_NWE;
 		required = true;
 	}
 
@@ -288,9 +226,9 @@ static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid,
 	of_property_read_string(np, "atmel,smc-exnw-mode", &tmp_str);
 	if (tmp_str) {
 		if (!strcmp(tmp_str, "frozen"))
-			config->mode |= AT91_SMC_EXNWMODE_FROZEN;
+			smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_FROZEN;
 		else if (!strcmp(tmp_str, "ready"))
-			config->mode |= AT91_SMC_EXNWMODE_READY;
+			smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_READY;
 		else if (strcmp(tmp_str, "disabled"))
 			return -EINVAL;
 
@@ -301,164 +239,63 @@ static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid,
 	if (!ret) {
 		switch (tmp) {
 		case 4:
-			config->mode |= AT91_SMC_PS_4;
+			smcconf->mode |= ATMEL_SMC_MODE_PS_4;
 			break;
 
 		case 8:
-			config->mode |= AT91_SMC_PS_8;
+			smcconf->mode |= ATMEL_SMC_MODE_PS_8;
 			break;
 
 		case 16:
-			config->mode |= AT91_SMC_PS_16;
+			smcconf->mode |= ATMEL_SMC_MODE_PS_16;
 			break;
 
 		case 32:
-			config->mode |= AT91_SMC_PS_32;
+			smcconf->mode |= ATMEL_SMC_MODE_PS_32;
 			break;
 
 		default:
 			return -EINVAL;
 		}
 
-		config->mode |= AT91_SMC_PMEN;
+		smcconf->mode |= ATMEL_SMC_MODE_PMEN;
 		required = true;
 	}
 
-	ret = at91sam9_smc_xslate_timings(ebid, np, &config->timings,
-					  &required);
+	ret = atmel_ebi_xslate_smc_timings(ebid, np, &conf->smcconf);
 	if (ret)
-		return ret;
-
-	return required;
-}
-
-static int at91sam9_ebi_apply_config(struct at91_ebi_dev *ebid,
-				     struct at91_ebi_dev_config *conf)
-{
-	unsigned int clk_rate = clk_get_rate(ebid->ebi->clk);
-	unsigned int clk_period = NSEC_PER_SEC / clk_rate;
-	struct at91sam9_ebi_dev_config *config = &conf->sam9;
-	struct at91sam9_smc_timings *timings = &config->timings;
-	struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9;
-	u32 coded_val;
-	u32 val;
+		return -EINVAL;
 
-	coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
-						    timings->ncs_rd_setup_ns);
-	val = AT91SAM9_SMC_NCS_NRDSETUP(coded_val);
-	coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
-						    timings->nrd_setup_ns);
-	val |= AT91SAM9_SMC_NRDSETUP(coded_val);
-	coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
-						    timings->ncs_wr_setup_ns);
-	val |= AT91SAM9_SMC_NCS_WRSETUP(coded_val);
-	coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate,
-						    timings->nwe_setup_ns);
-	val |= AT91SAM9_SMC_NWESETUP(coded_val);
-	regmap_fields_write(fields->setup, conf->cs, val);
-
-	coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
-						    timings->ncs_rd_pulse_ns);
-	val = AT91SAM9_SMC_NCS_NRDPULSE(coded_val);
-	coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
-						    timings->nrd_pulse_ns);
-	val |= AT91SAM9_SMC_NRDPULSE(coded_val);
-	coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
-						    timings->ncs_wr_pulse_ns);
-	val |= AT91SAM9_SMC_NCS_WRPULSE(coded_val);
-	coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate,
-						    timings->nwe_pulse_ns);
-	val |= AT91SAM9_SMC_NWEPULSE(coded_val);
-	regmap_fields_write(fields->pulse, conf->cs, val);
-
-	coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate,
-						    timings->nrd_cycle_ns);
-	val = AT91SAM9_SMC_NRDCYCLE(coded_val);
-	coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate,
-						    timings->nwe_cycle_ns);
-	val |= AT91SAM9_SMC_NWECYCLE(coded_val);
-	regmap_fields_write(fields->cycle, conf->cs, val);
-
-	val = DIV_ROUND_UP(timings->tdf_ns, clk_period);
-	if (val > AT91_SMC_TDF_MAX)
-		val = AT91_SMC_TDF_MAX;
-	regmap_fields_write(fields->mode, conf->cs,
-			    config->mode | AT91_SMC_TDF_(val));
+	if ((ret > 0 && !required) || (!ret && required)) {
+		dev_err(ebid->ebi->dev, "missing atmel,smc- properties in %s",
+			np->full_name);
+		return -EINVAL;
+	}
 
-	return 0;
+	return required;
 }
 
-static int at91sam9_ebi_init(struct at91_ebi *ebi)
+static void at91sam9_ebi_apply_config(struct atmel_ebi_dev *ebid,
+				      struct atmel_ebi_dev_config *conf)
 {
-	struct at91sam9_smc_generic_fields *fields = &ebi->sam9;
-	struct reg_field field = REG_FIELD(0, 0, 31);
-
-	field.id_size = fls(ebi->caps->available_cs);
-	field.id_offset = AT91SAM9_SMC_GENERIC_BLK_SZ;
-
-	field.reg = AT91SAM9_SMC_SETUP(AT91SAM9_SMC_GENERIC);
-	fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
-						field);
-	if (IS_ERR(fields->setup))
-		return PTR_ERR(fields->setup);
-
-	field.reg = AT91SAM9_SMC_PULSE(AT91SAM9_SMC_GENERIC);
-	fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
-						field);
-	if (IS_ERR(fields->pulse))
-		return PTR_ERR(fields->pulse);
-
-	field.reg = AT91SAM9_SMC_CYCLE(AT91SAM9_SMC_GENERIC);
-	fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
-						field);
-	if (IS_ERR(fields->cycle))
-		return PTR_ERR(fields->cycle);
-
-	field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC);
-	fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
-					       field);
-	return PTR_ERR_OR_ZERO(fields->mode);
+	atmel_smc_cs_conf_apply(ebid->ebi->smc.regmap, conf->cs,
+				&conf->smcconf);
 }
 
-static int sama5d3_ebi_init(struct at91_ebi *ebi)
+static void sama5_ebi_apply_config(struct atmel_ebi_dev *ebid,
+				   struct atmel_ebi_dev_config *conf)
 {
-	struct at91sam9_smc_generic_fields *fields = &ebi->sam9;
-	struct reg_field field = REG_FIELD(0, 0, 31);
-
-	field.id_size = fls(ebi->caps->available_cs);
-	field.id_offset = SAMA5_SMC_GENERIC_BLK_SZ;
-
-	field.reg = AT91SAM9_SMC_SETUP(SAMA5_SMC_GENERIC);
-	fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
-						field);
-	if (IS_ERR(fields->setup))
-		return PTR_ERR(fields->setup);
-
-	field.reg = AT91SAM9_SMC_PULSE(SAMA5_SMC_GENERIC);
-	fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
-						field);
-	if (IS_ERR(fields->pulse))
-		return PTR_ERR(fields->pulse);
-
-	field.reg = AT91SAM9_SMC_CYCLE(SAMA5_SMC_GENERIC);
-	fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
-						field);
-	if (IS_ERR(fields->cycle))
-		return PTR_ERR(fields->cycle);
-
-	field.reg = SAMA5_SMC_MODE(SAMA5_SMC_GENERIC);
-	fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap,
-					       field);
-	return PTR_ERR_OR_ZERO(fields->mode);
+	atmel_hsmc_cs_conf_apply(ebid->ebi->smc.regmap, conf->cs,
+				 &conf->smcconf);
 }
 
-static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
-			      int reg_cells)
+static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
+			       int reg_cells)
 {
-	const struct at91_ebi_caps *caps = ebi->caps;
-	struct at91_ebi_dev_config conf = { };
+	const struct atmel_ebi_caps *caps = ebi->caps;
+	struct atmel_ebi_dev_config conf = { };
 	struct device *dev = ebi->dev;
-	struct at91_ebi_dev *ebid;
+	struct atmel_ebi_dev *ebid;
 	unsigned long cslines = 0;
 	int ret, numcs = 0, nentries, i;
 	bool apply = false;
@@ -495,6 +332,7 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
 		return -ENOMEM;
 
 	ebid->ebi = ebi;
+	ebid->numcs = numcs;
 
 	ret = caps->xlate_config(ebid, np, &conf);
 	if (ret < 0)
@@ -508,9 +346,7 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
 
 		if (apply) {
 			conf.cs = cs;
-			ret = caps->apply_config(ebid, &conf);
-			if (ret)
-				return ret;
+			caps->apply_config(ebid, &conf);
 		}
 
 		caps->get_config(ebid, &ebid->configs[i]);
@@ -519,9 +355,10 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
 		 * Attach the EBI device to the generic SMC logic if at least
 		 * one "atmel,smc-" property is present.
 		 */
-		if (ebi->ebi_csa && apply)
-			regmap_field_update_bits(ebi->ebi_csa,
-						 BIT(cs), 0);
+		if (ebi->caps->ebi_csa_offs && apply)
+			regmap_update_bits(ebi->matrix,
+					   ebi->caps->ebi_csa_offs,
+					   BIT(cs), 0);
 
 		i++;
 	}
@@ -531,102 +368,70 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np,
 	return 0;
 }
 
-static const struct reg_field at91sam9260_ebi_csa =
-				REG_FIELD(AT91SAM9260_MATRIX_EBICSA, 0,
-					  AT91_MATRIX_EBI_NUM_CS - 1);
-
-static const struct at91_ebi_caps at91sam9260_ebi_caps = {
+static const struct atmel_ebi_caps at91sam9260_ebi_caps = {
 	.available_cs = 0xff,
-	.ebi_csa = &at91sam9260_ebi_csa,
+	.ebi_csa_offs = AT91SAM9260_MATRIX_EBICSA,
 	.get_config = at91sam9_ebi_get_config,
-	.xlate_config = at91sam9_ebi_xslate_config,
+	.xlate_config = atmel_ebi_xslate_smc_config,
 	.apply_config = at91sam9_ebi_apply_config,
-	.init = at91sam9_ebi_init,
 };
 
-static const struct reg_field at91sam9261_ebi_csa =
-				REG_FIELD(AT91SAM9261_MATRIX_EBICSA, 0,
-					  AT91_MATRIX_EBI_NUM_CS - 1);
-
-static const struct at91_ebi_caps at91sam9261_ebi_caps = {
+static const struct atmel_ebi_caps at91sam9261_ebi_caps = {
 	.available_cs = 0xff,
-	.ebi_csa = &at91sam9261_ebi_csa,
+	.ebi_csa_offs = AT91SAM9261_MATRIX_EBICSA,
 	.get_config = at91sam9_ebi_get_config,
-	.xlate_config = at91sam9_ebi_xslate_config,
+	.xlate_config = atmel_ebi_xslate_smc_config,
 	.apply_config = at91sam9_ebi_apply_config,
-	.init = at91sam9_ebi_init,
 };
 
-static const struct reg_field at91sam9263_ebi0_csa =
-				REG_FIELD(AT91SAM9263_MATRIX_EBI0CSA, 0,
-					  AT91_MATRIX_EBI_NUM_CS - 1);
-
-static const struct at91_ebi_caps at91sam9263_ebi0_caps = {
+static const struct atmel_ebi_caps at91sam9263_ebi0_caps = {
 	.available_cs = 0x3f,
-	.ebi_csa = &at91sam9263_ebi0_csa,
+	.ebi_csa_offs = AT91SAM9263_MATRIX_EBI0CSA,
 	.get_config = at91sam9_ebi_get_config,
-	.xlate_config = at91sam9_ebi_xslate_config,
+	.xlate_config = atmel_ebi_xslate_smc_config,
 	.apply_config = at91sam9_ebi_apply_config,
-	.init = at91sam9_ebi_init,
 };
 
-static const struct reg_field at91sam9263_ebi1_csa =
-				REG_FIELD(AT91SAM9263_MATRIX_EBI1CSA, 0,
-					  AT91_MATRIX_EBI_NUM_CS - 1);
-
-static const struct at91_ebi_caps at91sam9263_ebi1_caps = {
+static const struct atmel_ebi_caps at91sam9263_ebi1_caps = {
 	.available_cs = 0x7,
-	.ebi_csa = &at91sam9263_ebi1_csa,
+	.ebi_csa_offs = AT91SAM9263_MATRIX_EBI1CSA,
 	.get_config = at91sam9_ebi_get_config,
-	.xlate_config = at91sam9_ebi_xslate_config,
+	.xlate_config = atmel_ebi_xslate_smc_config,
 	.apply_config = at91sam9_ebi_apply_config,
-	.init = at91sam9_ebi_init,
 };
 
-static const struct reg_field at91sam9rl_ebi_csa =
-				REG_FIELD(AT91SAM9RL_MATRIX_EBICSA, 0,
-					  AT91_MATRIX_EBI_NUM_CS - 1);
-
-static const struct at91_ebi_caps at91sam9rl_ebi_caps = {
+static const struct atmel_ebi_caps at91sam9rl_ebi_caps = {
 	.available_cs = 0x3f,
-	.ebi_csa = &at91sam9rl_ebi_csa,
+	.ebi_csa_offs = AT91SAM9RL_MATRIX_EBICSA,
 	.get_config = at91sam9_ebi_get_config,
-	.xlate_config = at91sam9_ebi_xslate_config,
+	.xlate_config = atmel_ebi_xslate_smc_config,
 	.apply_config = at91sam9_ebi_apply_config,
-	.init = at91sam9_ebi_init,
 };
 
-static const struct reg_field at91sam9g45_ebi_csa =
-				REG_FIELD(AT91SAM9G45_MATRIX_EBICSA, 0,
-					  AT91_MATRIX_EBI_NUM_CS - 1);
-
-static const struct at91_ebi_caps at91sam9g45_ebi_caps = {
+static const struct atmel_ebi_caps at91sam9g45_ebi_caps = {
 	.available_cs = 0x3f,
-	.ebi_csa = &at91sam9g45_ebi_csa,
+	.ebi_csa_offs = AT91SAM9G45_MATRIX_EBICSA,
 	.get_config = at91sam9_ebi_get_config,
-	.xlate_config = at91sam9_ebi_xslate_config,
+	.xlate_config = atmel_ebi_xslate_smc_config,
 	.apply_config = at91sam9_ebi_apply_config,
-	.init = at91sam9_ebi_init,
 };
 
-static const struct at91_ebi_caps at91sam9x5_ebi_caps = {
+static const struct atmel_ebi_caps at91sam9x5_ebi_caps = {
 	.available_cs = 0x3f,
-	.ebi_csa = &at91sam9263_ebi0_csa,
+	.ebi_csa_offs = AT91SAM9X5_MATRIX_EBICSA,
 	.get_config = at91sam9_ebi_get_config,
-	.xlate_config = at91sam9_ebi_xslate_config,
+	.xlate_config = atmel_ebi_xslate_smc_config,
 	.apply_config = at91sam9_ebi_apply_config,
-	.init = at91sam9_ebi_init,
 };
 
-static const struct at91_ebi_caps sama5d3_ebi_caps = {
+static const struct atmel_ebi_caps sama5d3_ebi_caps = {
 	.available_cs = 0xf,
-	.get_config = at91sam9_ebi_get_config,
-	.xlate_config = at91sam9_ebi_xslate_config,
-	.apply_config = at91sam9_ebi_apply_config,
-	.init = sama5d3_ebi_init,
+	.get_config = sama5_ebi_get_config,
+	.xlate_config = atmel_ebi_xslate_smc_config,
+	.apply_config = sama5_ebi_apply_config,
 };
 
-static const struct of_device_id at91_ebi_id_table[] = {
+static const struct of_device_id atmel_ebi_id_table[] = {
 	{
 		.compatible = "atmel,at91sam9260-ebi",
 		.data = &at91sam9260_ebi_caps,
@@ -662,7 +467,7 @@ static const struct of_device_id at91_ebi_id_table[] = {
 	{ /* sentinel */ }
 };
 
-static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np)
+static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np)
 {
 	struct device *dev = ebi->dev;
 	struct property *newprop;
@@ -684,17 +489,17 @@ static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np)
 	return of_update_property(np, newprop);
 }
 
-static int at91_ebi_probe(struct platform_device *pdev)
+static int atmel_ebi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *child, *np = dev->of_node, *smc_np;
 	const struct of_device_id *match;
-	struct at91_ebi *ebi;
+	struct atmel_ebi *ebi;
 	int ret, reg_cells;
 	struct clk *clk;
 	u32 val;
 
-	match = of_match_device(at91_ebi_id_table, dev);
+	match = of_match_device(atmel_ebi_id_table, dev);
 	if (!match || !match->data)
 		return -EINVAL;
 
@@ -702,6 +507,8 @@ static int at91_ebi_probe(struct platform_device *pdev)
 	if (!ebi)
 		return -ENOMEM;
 
+	platform_set_drvdata(pdev, ebi);
+
 	INIT_LIST_HEAD(&ebi->devs);
 	ebi->caps = match->data;
 	ebi->dev = dev;
@@ -733,22 +540,13 @@ static int at91_ebi_probe(struct platform_device *pdev)
 	 * The sama5d3 does not provide an EBICSA register and thus does need
 	 * to access the matrix registers.
 	 */
-	if (ebi->caps->ebi_csa) {
+	if (ebi->caps->ebi_csa_offs) {
 		ebi->matrix =
 			syscon_regmap_lookup_by_phandle(np, "atmel,matrix");
 		if (IS_ERR(ebi->matrix))
 			return PTR_ERR(ebi->matrix);
-
-		ebi->ebi_csa = regmap_field_alloc(ebi->matrix,
-						  *ebi->caps->ebi_csa);
-		if (IS_ERR(ebi->ebi_csa))
-			return PTR_ERR(ebi->ebi_csa);
 	}
 
-	ret = ebi->caps->init(ebi);
-	if (ret)
-		return ret;
-
 	ret = of_property_read_u32(np, "#address-cells", &val);
 	if (ret) {
 		dev_err(dev, "missing #address-cells property\n");
@@ -769,12 +567,12 @@ static int at91_ebi_probe(struct platform_device *pdev)
 		if (!of_find_property(child, "reg", NULL))
 			continue;
 
-		ret = at91_ebi_dev_setup(ebi, child, reg_cells);
+		ret = atmel_ebi_dev_setup(ebi, child, reg_cells);
 		if (ret) {
 			dev_err(dev, "failed to configure EBI bus for %s, disabling the device",
 				child->full_name);
 
-			ret = at91_ebi_dev_disable(ebi, child);
+			ret = atmel_ebi_dev_disable(ebi, child);
 			if (ret)
 				return ret;
 		}
@@ -783,10 +581,28 @@ static int at91_ebi_probe(struct platform_device *pdev)
 	return of_platform_populate(np, NULL, NULL, dev);
 }
 
-static struct platform_driver at91_ebi_driver = {
+static int atmel_ebi_resume(struct device *dev)
+{
+	struct atmel_ebi *ebi = dev_get_drvdata(dev);
+	struct atmel_ebi_dev *ebid;
+
+	list_for_each_entry(ebid, &ebi->devs, node) {
+		int i;
+
+		for (i = 0; i < ebid->numcs; i++)
+			ebid->ebi->caps->apply_config(ebid, &ebid->configs[i]);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(atmel_ebi_pm_ops, NULL, atmel_ebi_resume);
+
+static struct platform_driver atmel_ebi_driver = {
 	.driver = {
 		.name = "atmel-ebi",
-		.of_match_table	= at91_ebi_id_table,
+		.of_match_table	= atmel_ebi_id_table,
+		.pm = &atmel_ebi_pm_ops,
 	},
 };
-builtin_platform_driver_probe(at91_ebi_driver, at91_ebi_probe);
+builtin_platform_driver_probe(atmel_ebi_driver, atmel_ebi_probe);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 55ecdfb74d31..3eb5c93595f6 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -121,6 +121,10 @@ config MFD_ATMEL_HLCDC
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 
+config MFD_ATMEL_SMC
+	bool
+	select MFD_SYSCON
+
 config MFD_BCM590XX
 	tristate "Broadcom BCM590xx PMUs"
 	select MFD_CORE
@@ -263,13 +267,14 @@ config MFD_DA9055
 	  called "da9055"
 
 config MFD_DA9062
-	tristate "Dialog Semiconductor DA9062 PMIC Support"
+	tristate "Dialog Semiconductor DA9062/61 PMIC Support"
 	select MFD_CORE
 	select REGMAP_I2C
 	select REGMAP_IRQ
 	depends on I2C
 	help
-	  Say yes here for support for the Dialog Semiconductor DA9062 PMIC.
+	  Say yes here for support for the Dialog Semiconductor DA9061 and
+	  DA9062 PMICs.
 	  This includes the I2C driver and core APIs.
 	  Additional drivers must be enabled in order to use the functionality
 	  of the device.
@@ -344,6 +349,23 @@ config MFD_MC13XXX_I2C
 	help
 	  Select this if your MC13xxx is connected via an I2C bus.
 
+config MFD_MXS_LRADC
+	tristate "Freescale i.MX23/i.MX28 LRADC"
+	depends on ARCH_MXS || COMPILE_TEST
+	select MFD_CORE
+	select STMP_DEVICE
+	help
+	  Say yes here to build support for the Low Resolution
+	  Analog-to-Digital Converter (LRADC) found on the i.MX23 and i.MX28
+	  processors. This driver provides common support for accessing the
+	  device, additional drivers must be enabled in order to use the
+	  functionality of the device:
+		mxs-lradc-adc for ADC readings
+		mxs-lradc-ts  for touchscreen support
+
+	  This driver can also be built as a module. If so, the module will be
+	  called mxs-lradc.
+
 config MFD_MX25_TSADC
 	tristate "Freescale i.MX25 integrated Touchscreen and ADC unit"
 	select REGMAP_MMIO
@@ -425,18 +447,29 @@ config LPC_SCH
 	  System Management Bus and General Purpose I/O.
 
 config INTEL_SOC_PMIC
-	bool "Support for Intel Atom SoC PMIC"
+	bool "Support for Crystal Cove PMIC"
 	depends on GPIOLIB
 	depends on I2C=y
 	select MFD_CORE
 	select REGMAP_I2C
 	select REGMAP_IRQ
 	help
-	  Select this option to enable support for the PMIC device
+	  Select this option to enable support for Crystal Cove PMIC
 	  on some Intel SoC systems. The PMIC provides ADC, GPIO,
 	  thermal, charger and related power management functions
 	  on these systems.
 
+config INTEL_SOC_PMIC_BXTWC
+	tristate "Support for Intel Broxton Whiskey Cove PMIC"
+	depends on INTEL_PMC_IPC
+	select MFD_CORE
+	select REGMAP_IRQ
+	help
+	  Select this option to enable support for Whiskey Cove PMIC
+	  on Intel Broxton systems. The PMIC provides ADC, GPIO,
+	  thermal, charger and related power management functions
+	  on these systems.
+
 config MFD_INTEL_LPSS
 	tristate
 	select COMMON_CLK
@@ -1164,6 +1197,18 @@ config MFD_LP8788
 	  TI LP8788 PMU supports regulators, battery charger, RTC,
 	  ADC, backlight driver and current sinks.
 
+config MFD_TI_LMU
+	tristate "TI Lighting Management Unit driver"
+	depends on I2C
+	select MFD_CORE
+	select REGMAP_I2C
+	help
+	  Say yes here to enable support for TI LMU chips.
+
+	  TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697.
+	  It consists of backlight, LED and regulator driver.
+	  It provides consistent device controls for lighting functions.
+
 config MFD_OMAP_USB_HOST
 	bool "TI OMAP USBHS core and TLL driver"
 	depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 31ce07611a6f..c16bf1ea0ea9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_MFD_ACT8945A)	+= act8945a.o
 obj-$(CONFIG_MFD_SM501)		+= sm501.o
 obj-$(CONFIG_MFD_ASIC3)		+= asic3.o tmio_core.o
 obj-$(CONFIG_MFD_BCM590XX)	+= bcm590xx.o
-obj-$(CONFIG_MFD_CROS_EC)	+= cros_ec.o
+cros_ec_core-objs		:= cros_ec.o
+cros_ec_core-$(CONFIG_ACPI)	+= cros_ec_acpi_gpe.o
+obj-$(CONFIG_MFD_CROS_EC)	+= cros_ec_core.o
 obj-$(CONFIG_MFD_CROS_EC_I2C)	+= cros_ec_i2c.o
 obj-$(CONFIG_MFD_CROS_EC_SPI)	+= cros_ec_spi.o
 obj-$(CONFIG_MFD_EXYNOS_LPASS)	+= exynos-lpass.o
@@ -125,6 +127,8 @@ obj-$(CONFIG_MFD_AXP20X_RSB)	+= axp20x-rsb.o
 obj-$(CONFIG_MFD_LP3943)	+= lp3943.o
 obj-$(CONFIG_MFD_LP8788)	+= lp8788.o lp8788-irq.o
 
+obj-$(CONFIG_MFD_TI_LMU)	+= ti-lmu.o
+
 da9055-objs			:= da9055-core.o da9055-i2c.o
 obj-$(CONFIG_MFD_DA9055)	+= da9055.o
 obj-$(CONFIG_MFD_DA9062)	+= da9062-core.o
@@ -181,6 +185,7 @@ obj-$(CONFIG_MFD_TPS65090)	+= tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE)	+= aat2870-core.o
 obj-$(CONFIG_MFD_ATMEL_FLEXCOM)	+= atmel-flexcom.o
 obj-$(CONFIG_MFD_ATMEL_HLCDC)	+= atmel-hlcdc.o
+obj-$(CONFIG_MFD_ATMEL_SMC)	+= atmel-smc.o
 obj-$(CONFIG_MFD_INTEL_LPSS)	+= intel-lpss.o
 obj-$(CONFIG_MFD_INTEL_LPSS_PCI)	+= intel-lpss-pci.o
 obj-$(CONFIG_MFD_INTEL_LPSS_ACPI)	+= intel-lpss-acpi.o
@@ -207,11 +212,12 @@ obj-$(CONFIG_MFD_RT5033)	+= rt5033.o
 obj-$(CONFIG_MFD_SKY81452)	+= sky81452.o
 
 intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
-intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC)	+= intel_soc_pmic_bxtwc.o
 obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
+obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC)	+= intel_soc_pmic_bxtwc.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
 obj-$(CONFIG_MFD_SUN4I_GPADC)	+= sun4i-gpadc.o
 
 obj-$(CONFIG_MFD_STM32_TIMERS) 	+= stm32-timers.o
+obj-$(CONFIG_MFD_MXS_LRADC)     += mxs-lradc.o
diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c
index 06e1f7fc5605..96e7d2cb7b89 100644
--- a/drivers/mfd/altera-a10sr.c
+++ b/drivers/mfd/altera-a10sr.c
@@ -33,6 +33,10 @@ static const struct mfd_cell altr_a10sr_subdev_info[] = {
 		.name = "altr_a10sr_gpio",
 		.of_compatible = "altr,a10sr-gpio",
 	},
+	{
+		.name = "altr_a10sr_reset",
+		.of_compatible = "altr,a10sr-reset",
+	},
 };
 
 static bool altr_a10sr_reg_readable(struct device *dev, unsigned int reg)
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index b6d4bc63c426..75488e65cd96 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -235,29 +235,25 @@ static irqreturn_t arizona_overclocked(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+#define ARIZONA_REG_POLL_DELAY_US 7500
+
 static int arizona_poll_reg(struct arizona *arizona,
-			    int timeout, unsigned int reg,
+			    int timeout_ms, unsigned int reg,
 			    unsigned int mask, unsigned int target)
 {
 	unsigned int val = 0;
-	int ret, i;
-
-	for (i = 0; i < timeout; i++) {
-		ret = regmap_read(arizona->regmap, reg, &val);
-		if (ret != 0) {
-			dev_err(arizona->dev, "Failed to read reg %u: %d\n",
-				reg, ret);
-			continue;
-		}
-
-		if ((val & mask) == target)
-			return 0;
+	int ret;
 
-		usleep_range(1000, 5000);
-	}
+	ret = regmap_read_poll_timeout(arizona->regmap,
+				       ARIZONA_INTERRUPT_RAW_STATUS_5, val,
+				       ((val & mask) == target),
+				       ARIZONA_REG_POLL_DELAY_US,
+				       timeout_ms * 1000);
+	if (ret)
+		dev_err(arizona->dev, "Polling reg 0x%x timed out: %x\n",
+			reg, val);
 
-	dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val);
-	return -ETIMEDOUT;
+	return ret;
 }
 
 static int arizona_wait_for_boot(struct arizona *arizona)
@@ -269,7 +265,7 @@ static int arizona_wait_for_boot(struct arizona *arizona)
 	 * we won't race with the interrupt handler as it'll be blocked on
 	 * runtime resume.
 	 */
-	ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5,
+	ret = arizona_poll_reg(arizona, 30, ARIZONA_INTERRUPT_RAW_STATUS_5,
 			       ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS);
 
 	if (!ret)
@@ -339,13 +335,11 @@ static int arizona_enable_freerun_sysclk(struct arizona *arizona,
 			ret);
 		return ret;
 	}
-	ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5,
+	ret = arizona_poll_reg(arizona, 180, ARIZONA_INTERRUPT_RAW_STATUS_5,
 			       ARIZONA_FLL1_CLOCK_OK_STS,
 			       ARIZONA_FLL1_CLOCK_OK_STS);
-	if (ret) {
-		ret = -ETIMEDOUT;
+	if (ret)
 		goto err_fll;
-	}
 
 	ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144);
 	if (ret) {
@@ -405,13 +399,11 @@ static int wm5102_apply_hardware_patch(struct arizona *arizona)
 		goto err;
 	}
 
-	ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1,
+	ret = arizona_poll_reg(arizona, 30, ARIZONA_WRITE_SEQUENCER_CTRL_1,
 			       ARIZONA_WSEQ_BUSY, 0);
-	if (ret) {
+	if (ret)
 		regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0,
 			     ARIZONA_WSEQ_ABORT);
-		ret = -ETIMEDOUT;
-	}
 
 err:
 	err = arizona_disable_freerun_sysclk(arizona, &state);
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 0413c8159551..cf2e25ab2940 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -78,7 +78,7 @@ struct asic3 {
 	unsigned int bus_shift;
 	unsigned int irq_nr;
 	unsigned int irq_base;
-	spinlock_t lock;
+	raw_spinlock_t lock;
 	u16 irq_bothedge[4];
 	struct gpio_chip gpio;
 	struct device *dev;
@@ -108,14 +108,14 @@ static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
 	unsigned long flags;
 	u32 val;
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 	val = asic3_read_register(asic, reg);
 	if (set)
 		val |= bits;
 	else
 		val &= ~bits;
 	asic3_write_register(asic, reg, val);
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 }
 
 /* IRQs */
@@ -129,13 +129,13 @@ static void asic3_irq_flip_edge(struct asic3 *asic,
 	u16 edge;
 	unsigned long flags;
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 	edge = asic3_read_register(asic,
 				   base + ASIC3_GPIO_EDGE_TRIGGER);
 	edge ^= bit;
 	asic3_write_register(asic,
 			     base + ASIC3_GPIO_EDGE_TRIGGER, edge);
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 }
 
 static void asic3_irq_demux(struct irq_desc *desc)
@@ -151,10 +151,10 @@ static void asic3_irq_demux(struct irq_desc *desc)
 		u32 status;
 		int bank;
 
-		spin_lock_irqsave(&asic->lock, flags);
+		raw_spin_lock_irqsave(&asic->lock, flags);
 		status = asic3_read_register(asic,
 					     ASIC3_OFFSET(INTR, P_INT_STAT));
-		spin_unlock_irqrestore(&asic->lock, flags);
+		raw_spin_unlock_irqrestore(&asic->lock, flags);
 
 		/* Check all ten register bits */
 		if ((status & 0x3ff) == 0)
@@ -167,7 +167,7 @@ static void asic3_irq_demux(struct irq_desc *desc)
 
 				base = ASIC3_GPIO_A_BASE
 				       + bank * ASIC3_GPIO_BASE_INCR;
-				spin_lock_irqsave(&asic->lock, flags);
+				raw_spin_lock_irqsave(&asic->lock, flags);
 				istat = asic3_read_register(asic,
 							    base +
 							    ASIC3_GPIO_INT_STATUS);
@@ -175,7 +175,7 @@ static void asic3_irq_demux(struct irq_desc *desc)
 				asic3_write_register(asic,
 						     base +
 						     ASIC3_GPIO_INT_STATUS, 0);
-				spin_unlock_irqrestore(&asic->lock, flags);
+				raw_spin_unlock_irqrestore(&asic->lock, flags);
 
 				for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) {
 					int bit = (1 << i);
@@ -230,11 +230,11 @@ static void asic3_mask_gpio_irq(struct irq_data *data)
 	bank = asic3_irq_to_bank(asic, data->irq);
 	index = asic3_irq_to_index(asic, data->irq);
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 	val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
 	val |= 1 << index;
 	asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val);
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 }
 
 static void asic3_mask_irq(struct irq_data *data)
@@ -243,7 +243,7 @@ static void asic3_mask_irq(struct irq_data *data)
 	int regval;
 	unsigned long flags;
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 	regval = asic3_read_register(asic,
 				     ASIC3_INTR_BASE +
 				     ASIC3_INTR_INT_MASK);
@@ -255,7 +255,7 @@ static void asic3_mask_irq(struct irq_data *data)
 			     ASIC3_INTR_BASE +
 			     ASIC3_INTR_INT_MASK,
 			     regval);
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 }
 
 static void asic3_unmask_gpio_irq(struct irq_data *data)
@@ -267,11 +267,11 @@ static void asic3_unmask_gpio_irq(struct irq_data *data)
 	bank = asic3_irq_to_bank(asic, data->irq);
 	index = asic3_irq_to_index(asic, data->irq);
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 	val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
 	val &= ~(1 << index);
 	asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val);
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 }
 
 static void asic3_unmask_irq(struct irq_data *data)
@@ -280,7 +280,7 @@ static void asic3_unmask_irq(struct irq_data *data)
 	int regval;
 	unsigned long flags;
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 	regval = asic3_read_register(asic,
 				     ASIC3_INTR_BASE +
 				     ASIC3_INTR_INT_MASK);
@@ -292,7 +292,7 @@ static void asic3_unmask_irq(struct irq_data *data)
 			     ASIC3_INTR_BASE +
 			     ASIC3_INTR_INT_MASK,
 			     regval);
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 }
 
 static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
@@ -306,7 +306,7 @@ static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
 	index = asic3_irq_to_index(asic, data->irq);
 	bit = 1<<index;
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 	level = asic3_read_register(asic,
 				    bank + ASIC3_GPIO_LEVEL_TRIGGER);
 	edge = asic3_read_register(asic,
@@ -348,7 +348,7 @@ static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
 			     edge);
 	asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE,
 			     trigger);
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 	return 0;
 }
 
@@ -455,7 +455,7 @@ static int asic3_gpio_direction(struct gpio_chip *chip,
 		return -EINVAL;
 	}
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 
 	out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION);
 
@@ -467,7 +467,7 @@ static int asic3_gpio_direction(struct gpio_chip *chip,
 
 	asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg);
 
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 
 	return 0;
 
@@ -524,7 +524,7 @@ static void asic3_gpio_set(struct gpio_chip *chip,
 
 	mask = ASIC3_GPIO_TO_MASK(offset);
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 
 	out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT);
 
@@ -535,7 +535,7 @@ static void asic3_gpio_set(struct gpio_chip *chip,
 
 	asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg);
 
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 }
 
 static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -611,13 +611,13 @@ static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
 	unsigned long flags;
 	u32 cdex;
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 	if (clk->enabled++ == 0) {
 		cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
 		cdex |= clk->cdex;
 		asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
 	}
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 }
 
 static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
@@ -627,13 +627,13 @@ static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
 
 	WARN_ON(clk->enabled == 0);
 
-	spin_lock_irqsave(&asic->lock, flags);
+	raw_spin_lock_irqsave(&asic->lock, flags);
 	if (--clk->enabled == 0) {
 		cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
 		cdex &= ~clk->cdex;
 		asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
 	}
-	spin_unlock_irqrestore(&asic->lock, flags);
+	raw_spin_unlock_irqrestore(&asic->lock, flags);
 }
 
 /* MFD cells (SPI, PWM, LED, DS1WM, MMC) */
@@ -963,7 +963,7 @@ static int __init asic3_probe(struct platform_device *pdev)
 	if (!asic)
 		return -ENOMEM;
 
-	spin_lock_init(&asic->lock);
+	raw_spin_lock_init(&asic->lock);
 	platform_set_drvdata(pdev, asic);
 	asic->dev = &pdev->dev;
 
diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c
new file mode 100644
index 000000000000..954cf0f66a31
--- /dev/null
+++ b/drivers/mfd/atmel-smc.c
@@ -0,0 +1,314 @@
+/*
+ * Atmel SMC (Static Memory Controller) helper functions.
+ *
+ * Copyright (C) 2017 Atmel
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.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/mfd/syscon/atmel-smc.h>
+
+/**
+ * atmel_smc_cs_conf_init - initialize a SMC CS conf
+ * @conf: the SMC CS conf to initialize
+ *
+ * Set all fields to 0 so that one can start defining a new config.
+ */
+void atmel_smc_cs_conf_init(struct atmel_smc_cs_conf *conf)
+{
+	memset(conf, 0, sizeof(*conf));
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_init);
+
+/**
+ * atmel_smc_cs_encode_ncycles - encode a number of MCK clk cycles in the
+ *				 format expected by the SMC engine
+ * @ncycles: number of MCK clk cycles
+ * @msbpos: position of the MSB part of the timing field
+ * @msbwidth: width of the MSB part of the timing field
+ * @msbfactor: factor applied to the MSB
+ * @encodedval: param used to store the encoding result
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Setup/Pulse/Cycle/Timings Register"). This is a generic
+ * helper which called with different parameter depending on the encoding
+ * scheme.
+ *
+ * If the @ncycles value is too big to be encoded, -ERANGE is returned and
+ * the encodedval is contains the maximum val. Otherwise, 0 is returned.
+ */
+static int atmel_smc_cs_encode_ncycles(unsigned int ncycles,
+				       unsigned int msbpos,
+				       unsigned int msbwidth,
+				       unsigned int msbfactor,
+				       unsigned int *encodedval)
+{
+	unsigned int lsbmask = GENMASK(msbpos - 1, 0);
+	unsigned int msbmask = GENMASK(msbwidth - 1, 0);
+	unsigned int msb, lsb;
+	int ret = 0;
+
+	msb = ncycles / msbfactor;
+	lsb = ncycles % msbfactor;
+
+	if (lsb > lsbmask) {
+		lsb = 0;
+		msb++;
+	}
+
+	/*
+	 * Let's just put the maximum we can if the requested setting does
+	 * not fit in the register field.
+	 * We still return -ERANGE in case the caller cares.
+	 */
+	if (msb > msbmask) {
+		msb = msbmask;
+		lsb = lsbmask;
+		ret = -ERANGE;
+	}
+
+	*encodedval = (msb << msbpos) | lsb;
+
+	return ret;
+}
+
+/**
+ * atmel_smc_cs_conf_set_timing - set the SMC CS conf Txx parameter to a
+ *				  specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the Txx field in the TIMINGS register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this Txx
+ *	     parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Timings Register"), and then stores the result in the
+ * @conf->timings field at @shift position.
+ *
+ * Returns -EINVAL if shift is invalid, -ERANGE if ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_timing(struct atmel_smc_cs_conf *conf,
+				 unsigned int shift, unsigned int ncycles)
+{
+	unsigned int val;
+	int ret;
+
+	if (shift != ATMEL_HSMC_TIMINGS_TCLR_SHIFT &&
+	    shift != ATMEL_HSMC_TIMINGS_TADL_SHIFT &&
+	    shift != ATMEL_HSMC_TIMINGS_TAR_SHIFT &&
+	    shift != ATMEL_HSMC_TIMINGS_TRR_SHIFT &&
+	    shift != ATMEL_HSMC_TIMINGS_TWB_SHIFT)
+		return -EINVAL;
+
+	/*
+	 * The formula described in atmel datasheets (section "HSMC Timings
+	 * Register"):
+	 *
+	 * ncycles = (Txx[3] * 64) + Txx[2:0]
+	 */
+	ret = atmel_smc_cs_encode_ncycles(ncycles, 3, 1, 64, &val);
+	conf->timings &= ~GENMASK(shift + 3, shift);
+	conf->timings |= val << shift;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_timing);
+
+/**
+ * atmel_smc_cs_conf_set_setup - set the SMC CS conf xx_SETUP parameter to a
+ *				 specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the xx_SETUP field in the SETUP register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_SETUP
+ *	     parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Setup Register"), and then stores the result in the
+ * @conf->setup field at @shift position.
+ *
+ * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_setup(struct atmel_smc_cs_conf *conf,
+				unsigned int shift, unsigned int ncycles)
+{
+	unsigned int val;
+	int ret;
+
+	if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
+	    shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
+		return -EINVAL;
+
+	/*
+	 * The formula described in atmel datasheets (section "SMC Setup
+	 * Register"):
+	 *
+	 * ncycles = (128 * xx_SETUP[5]) + xx_SETUP[4:0]
+	 */
+	ret = atmel_smc_cs_encode_ncycles(ncycles, 5, 1, 128, &val);
+	conf->setup &= ~GENMASK(shift + 7, shift);
+	conf->setup |= val << shift;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_setup);
+
+/**
+ * atmel_smc_cs_conf_set_pulse - set the SMC CS conf xx_PULSE parameter to a
+ *				 specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the xx_PULSE field in the PULSE register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_PULSE
+ *	     parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Pulse Register"), and then stores the result in the
+ * @conf->setup field at @shift position.
+ *
+ * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_pulse(struct atmel_smc_cs_conf *conf,
+				unsigned int shift, unsigned int ncycles)
+{
+	unsigned int val;
+	int ret;
+
+	if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
+	    shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
+		return -EINVAL;
+
+	/*
+	 * The formula described in atmel datasheets (section "SMC Pulse
+	 * Register"):
+	 *
+	 * ncycles = (256 * xx_PULSE[6]) + xx_PULSE[5:0]
+	 */
+	ret = atmel_smc_cs_encode_ncycles(ncycles, 6, 1, 256, &val);
+	conf->pulse &= ~GENMASK(shift + 7, shift);
+	conf->pulse |= val << shift;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_pulse);
+
+/**
+ * atmel_smc_cs_conf_set_cycle - set the SMC CS conf xx_CYCLE parameter to a
+ *				 specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the xx_CYCLE field in the CYCLE register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_CYCLE
+ *	     parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Pulse Register"), and then stores the result in the
+ * @conf->setup field at @shift position.
+ *
+ * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf *conf,
+				unsigned int shift, unsigned int ncycles)
+{
+	unsigned int val;
+	int ret;
+
+	if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NRD_SHIFT)
+		return -EINVAL;
+
+	/*
+	 * The formula described in atmel datasheets (section "SMC Cycle
+	 * Register"):
+	 *
+	 * ncycles = (xx_CYCLE[8:7] * 256) + xx_CYCLE[6:0]
+	 */
+	ret = atmel_smc_cs_encode_ncycles(ncycles, 7, 2, 256, &val);
+	conf->cycle &= ~GENMASK(shift + 15, shift);
+	conf->cycle |= val << shift;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle);
+
+/**
+ * atmel_smc_cs_conf_apply - apply an SMC CS conf
+ * @regmap: the SMC regmap
+ * @cs: the CS id
+ * @conf the SMC CS conf to apply
+ *
+ * Applies an SMC CS configuration.
+ * Only valid on at91sam9/avr32 SoCs.
+ */
+void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs,
+			     const struct atmel_smc_cs_conf *conf)
+{
+	regmap_write(regmap, ATMEL_SMC_SETUP(cs), conf->setup);
+	regmap_write(regmap, ATMEL_SMC_PULSE(cs), conf->pulse);
+	regmap_write(regmap, ATMEL_SMC_CYCLE(cs), conf->cycle);
+	regmap_write(regmap, ATMEL_SMC_MODE(cs), conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply);
+
+/**
+ * atmel_hsmc_cs_conf_apply - apply an SMC CS conf
+ * @regmap: the HSMC regmap
+ * @cs: the CS id
+ * @conf the SMC CS conf to apply
+ *
+ * Applies an SMC CS configuration.
+ * Only valid on post-sama5 SoCs.
+ */
+void atmel_hsmc_cs_conf_apply(struct regmap *regmap, int cs,
+			      const struct atmel_smc_cs_conf *conf)
+{
+	regmap_write(regmap, ATMEL_HSMC_SETUP(cs), conf->setup);
+	regmap_write(regmap, ATMEL_HSMC_PULSE(cs), conf->pulse);
+	regmap_write(regmap, ATMEL_HSMC_CYCLE(cs), conf->cycle);
+	regmap_write(regmap, ATMEL_HSMC_TIMINGS(cs), conf->timings);
+	regmap_write(regmap, ATMEL_HSMC_MODE(cs), conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply);
+
+/**
+ * atmel_smc_cs_conf_get - retrieve the current SMC CS conf
+ * @regmap: the SMC regmap
+ * @cs: the CS id
+ * @conf: the SMC CS conf object to store the current conf
+ *
+ * Retrieve the SMC CS configuration.
+ * Only valid on at91sam9/avr32 SoCs.
+ */
+void atmel_smc_cs_conf_get(struct regmap *regmap, int cs,
+			   struct atmel_smc_cs_conf *conf)
+{
+	regmap_read(regmap, ATMEL_SMC_SETUP(cs), &conf->setup);
+	regmap_read(regmap, ATMEL_SMC_PULSE(cs), &conf->pulse);
+	regmap_read(regmap, ATMEL_SMC_CYCLE(cs), &conf->cycle);
+	regmap_read(regmap, ATMEL_SMC_MODE(cs), &conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get);
+
+/**
+ * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf
+ * @regmap: the HSMC regmap
+ * @cs: the CS id
+ * @conf: the SMC CS conf object to store the current conf
+ *
+ * Retrieve the SMC CS configuration.
+ * Only valid on post-sama5 SoCs.
+ */
+void atmel_hsmc_cs_conf_get(struct regmap *regmap, int cs,
+			    struct atmel_smc_cs_conf *conf)
+{
+	regmap_read(regmap, ATMEL_HSMC_SETUP(cs), &conf->setup);
+	regmap_read(regmap, ATMEL_HSMC_PULSE(cs), &conf->pulse);
+	regmap_read(regmap, ATMEL_HSMC_CYCLE(cs), &conf->cycle);
+	regmap_read(regmap, ATMEL_HSMC_TIMINGS(cs), &conf->timings);
+	regmap_read(regmap, ATMEL_HSMC_MODE(cs), &conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get);
diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c
index a732cb50bcff..fd5c7267b136 100644
--- a/drivers/mfd/axp20x-rsb.c
+++ b/drivers/mfd/axp20x-rsb.c
@@ -61,6 +61,7 @@ static int axp20x_rsb_remove(struct sunxi_rsb_device *rdev)
 
 static const struct of_device_id axp20x_rsb_of_match[] = {
 	{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
+	{ .compatible = "x-powers,axp803", .data = (void *)AXP803_ID },
 	{ .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
 	{ .compatible = "x-powers,axp809", .data = (void *)AXP809_ID },
 	{ },
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 25115fe2acdf..1dc6235778eb 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -31,6 +31,7 @@
 
 #define AXP20X_OFF	0x80
 
+#define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE	0
 #define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE	BIT(4)
 
 static const char * const axp20x_model_names[] = {
@@ -40,6 +41,7 @@ static const char * const axp20x_model_names[] = {
 	"AXP221",
 	"AXP223",
 	"AXP288",
+	"AXP803",
 	"AXP806",
 	"AXP809",
 };
@@ -67,6 +69,7 @@ static const struct regmap_access_table axp152_volatile_table = {
 
 static const struct regmap_range axp20x_writeable_ranges[] = {
 	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
+	regmap_reg_range(AXP20X_CHRG_CTRL1, AXP20X_CHRG_CTRL2),
 	regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
 	regmap_reg_range(AXP20X_RDC_H, AXP20X_OCV(AXP20X_OCV_MAX)),
 };
@@ -93,6 +96,7 @@ static const struct regmap_access_table axp20x_volatile_table = {
 /* AXP22x ranges are shared with the AXP809, as they cover the same range */
 static const struct regmap_range axp22x_writeable_ranges[] = {
 	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
+	regmap_reg_range(AXP20X_CHRG_CTRL1, AXP22X_CHRG_CTRL3),
 	regmap_reg_range(AXP20X_DCDC_MODE, AXP22X_BATLOW_THRES1),
 };
 
@@ -100,7 +104,7 @@ static const struct regmap_range axp22x_volatile_ranges[] = {
 	regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_PWR_OP_MODE),
 	regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
 	regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
-	regmap_reg_range(AXP22X_PMIC_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
+	regmap_reg_range(AXP22X_PMIC_TEMP_H, AXP20X_IPSOUT_V_HIGH_L),
 	regmap_reg_range(AXP20X_FG_RES, AXP20X_FG_RES),
 };
 
@@ -114,6 +118,7 @@ static const struct regmap_access_table axp22x_volatile_table = {
 	.n_yes_ranges	= ARRAY_SIZE(axp22x_volatile_ranges),
 };
 
+/* AXP288 ranges are shared with the AXP803, as they cover the same range */
 static const struct regmap_range axp288_writeable_ranges[] = {
 	regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
 	regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
@@ -261,6 +266,20 @@ static struct resource axp288_fuel_gauge_resources[] = {
 	},
 };
 
+static struct resource axp803_pek_resources[] = {
+	{
+		.name   = "PEK_DBR",
+		.start  = AXP803_IRQ_PEK_RIS_EDGE,
+		.end    = AXP803_IRQ_PEK_RIS_EDGE,
+		.flags  = IORESOURCE_IRQ,
+	}, {
+		.name   = "PEK_DBF",
+		.start  = AXP803_IRQ_PEK_FAL_EDGE,
+		.end    = AXP803_IRQ_PEK_FAL_EDGE,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
 static struct resource axp809_pek_resources[] = {
 	{
 		.name   = "PEK_DBR",
@@ -454,6 +473,43 @@ static const struct regmap_irq axp288_regmap_irqs[] = {
 	INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG,            5, 1),
 };
 
+static const struct regmap_irq axp803_regmap_irqs[] = {
+	INIT_REGMAP_IRQ(AXP803, ACIN_OVER_V,		0, 7),
+	INIT_REGMAP_IRQ(AXP803, ACIN_PLUGIN,		0, 6),
+	INIT_REGMAP_IRQ(AXP803, ACIN_REMOVAL,	        0, 5),
+	INIT_REGMAP_IRQ(AXP803, VBUS_OVER_V,		0, 4),
+	INIT_REGMAP_IRQ(AXP803, VBUS_PLUGIN,		0, 3),
+	INIT_REGMAP_IRQ(AXP803, VBUS_REMOVAL,	        0, 2),
+	INIT_REGMAP_IRQ(AXP803, BATT_PLUGIN,		1, 7),
+	INIT_REGMAP_IRQ(AXP803, BATT_REMOVAL,	        1, 6),
+	INIT_REGMAP_IRQ(AXP803, BATT_ENT_ACT_MODE,	1, 5),
+	INIT_REGMAP_IRQ(AXP803, BATT_EXIT_ACT_MODE,	1, 4),
+	INIT_REGMAP_IRQ(AXP803, CHARG,		        1, 3),
+	INIT_REGMAP_IRQ(AXP803, CHARG_DONE,		1, 2),
+	INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_HIGH,	2, 7),
+	INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_HIGH_END,	2, 6),
+	INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_LOW,	2, 5),
+	INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_LOW_END,	2, 4),
+	INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_HIGH,	2, 3),
+	INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_HIGH_END,	2, 2),
+	INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_LOW,	2, 1),
+	INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_LOW_END,	2, 0),
+	INIT_REGMAP_IRQ(AXP803, DIE_TEMP_HIGH,	        3, 7),
+	INIT_REGMAP_IRQ(AXP803, GPADC,		        3, 2),
+	INIT_REGMAP_IRQ(AXP803, LOW_PWR_LVL1,	        3, 1),
+	INIT_REGMAP_IRQ(AXP803, LOW_PWR_LVL2,	        3, 0),
+	INIT_REGMAP_IRQ(AXP803, TIMER,		        4, 7),
+	INIT_REGMAP_IRQ(AXP803, PEK_RIS_EDGE,	        4, 6),
+	INIT_REGMAP_IRQ(AXP803, PEK_FAL_EDGE,	        4, 5),
+	INIT_REGMAP_IRQ(AXP803, PEK_SHORT,		4, 4),
+	INIT_REGMAP_IRQ(AXP803, PEK_LONG,		4, 3),
+	INIT_REGMAP_IRQ(AXP803, PEK_OVER_OFF,		4, 2),
+	INIT_REGMAP_IRQ(AXP803, GPIO1_INPUT,		4, 1),
+	INIT_REGMAP_IRQ(AXP803, GPIO0_INPUT,		4, 0),
+	INIT_REGMAP_IRQ(AXP803, BC_USB_CHNG,            5, 1),
+	INIT_REGMAP_IRQ(AXP803, MV_CHNG,                5, 0),
+};
+
 static const struct regmap_irq axp806_regmap_irqs[] = {
 	INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV1,	0, 0),
 	INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV2,	0, 1),
@@ -554,6 +610,18 @@ static const struct regmap_irq_chip axp288_regmap_irq_chip = {
 
 };
 
+static const struct regmap_irq_chip axp803_regmap_irq_chip = {
+	.name			= "axp803",
+	.status_base		= AXP20X_IRQ1_STATE,
+	.ack_base		= AXP20X_IRQ1_STATE,
+	.mask_base		= AXP20X_IRQ1_EN,
+	.mask_invert		= true,
+	.init_ack_masked	= true,
+	.irqs			= axp803_regmap_irqs,
+	.num_irqs		= ARRAY_SIZE(axp803_regmap_irqs),
+	.num_regs		= 6,
+};
+
 static const struct regmap_irq_chip axp806_regmap_irq_chip = {
 	.name			= "axp806",
 	.status_base		= AXP20X_IRQ1_STATE,
@@ -589,6 +657,11 @@ static struct mfd_cell axp20x_cells[] = {
 	}, {
 		.name		= "axp20x-regulator",
 	}, {
+		.name		= "axp20x-adc",
+	}, {
+		.name		= "axp20x-battery-power-supply",
+		.of_compatible	= "x-powers,axp209-battery-power-supply",
+	}, {
 		.name		= "axp20x-ac-power-supply",
 		.of_compatible	= "x-powers,axp202-ac-power-supply",
 		.num_resources	= ARRAY_SIZE(axp20x_ac_power_supply_resources),
@@ -609,6 +682,16 @@ static struct mfd_cell axp221_cells[] = {
 	}, {
 		.name		= "axp20x-regulator",
 	}, {
+		.name		= "axp22x-adc"
+	}, {
+		.name		= "axp20x-ac-power-supply",
+		.of_compatible	= "x-powers,axp221-ac-power-supply",
+		.num_resources	= ARRAY_SIZE(axp20x_ac_power_supply_resources),
+		.resources	= axp20x_ac_power_supply_resources,
+	}, {
+		.name		= "axp20x-battery-power-supply",
+		.of_compatible	= "x-powers,axp221-battery-power-supply",
+	}, {
 		.name		= "axp20x-usb-power-supply",
 		.of_compatible	= "x-powers,axp221-usb-power-supply",
 		.num_resources	= ARRAY_SIZE(axp22x_usb_power_supply_resources),
@@ -622,8 +705,18 @@ static struct mfd_cell axp223_cells[] = {
 		.num_resources		= ARRAY_SIZE(axp22x_pek_resources),
 		.resources		= axp22x_pek_resources,
 	}, {
+		.name		= "axp22x-adc",
+	}, {
+		.name		= "axp20x-battery-power-supply",
+		.of_compatible	= "x-powers,axp221-battery-power-supply",
+	}, {
 		.name			= "axp20x-regulator",
 	}, {
+		.name		= "axp20x-ac-power-supply",
+		.of_compatible	= "x-powers,axp221-ac-power-supply",
+		.num_resources	= ARRAY_SIZE(axp20x_ac_power_supply_resources),
+		.resources	= axp20x_ac_power_supply_resources,
+	}, {
 		.name		= "axp20x-usb-power-supply",
 		.of_compatible	= "x-powers,axp223-usb-power-supply",
 		.num_resources	= ARRAY_SIZE(axp22x_usb_power_supply_resources),
@@ -750,6 +843,14 @@ static struct mfd_cell axp288_cells[] = {
 	},
 };
 
+static struct mfd_cell axp803_cells[] = {
+	{
+		.name			= "axp20x-pek",
+		.num_resources		= ARRAY_SIZE(axp803_pek_resources),
+		.resources		= axp803_pek_resources,
+	}
+};
+
 static struct mfd_cell axp806_cells[] = {
 	{
 		.id			= 2,
@@ -836,6 +937,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
 		axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
 		axp20x->irq_flags = IRQF_TRIGGER_LOW;
 		break;
+	case AXP803_ID:
+		axp20x->nr_cells = ARRAY_SIZE(axp803_cells);
+		axp20x->cells = axp803_cells;
+		axp20x->regmap_cfg = &axp288_regmap_config;
+		axp20x->regmap_irq_chip = &axp803_regmap_irq_chip;
+		break;
 	case AXP806_ID:
 		axp20x->nr_cells = ARRAY_SIZE(axp806_cells);
 		axp20x->cells = axp806_cells;
@@ -877,15 +984,19 @@ int axp20x_device_probe(struct axp20x_dev *axp20x)
 	 * the these device addressing bits (in the upper 4 bits of the
 	 * registers) match.
 	 *
-	 * Since we only support an AXP806 chained to an AXP809 in slave
-	 * mode, and there isn't any existing hardware which uses AXP806
-	 * in master mode, or has 2 AXP806s in the same system, we can
-	 * just program the register address extension to the slave mode
-	 * address.
+	 * By default we support an AXP806 chained to an AXP809 in slave
+	 * mode. Boards which use an AXP806 in master mode can set the
+	 * property "x-powers,master-mode" to override the default.
 	 */
-	if (axp20x->variant == AXP806_ID)
-		regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
-			     AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
+	if (axp20x->variant == AXP806_ID) {
+		if (of_property_read_bool(axp20x->dev->of_node,
+					  "x-powers,master-mode"))
+			regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
+				     AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE);
+		else
+			regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
+				     AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
+	}
 
 	ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq,
 			  IRQF_ONESHOT | IRQF_SHARED | axp20x->irq_flags,
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index 9b66a98ba4bf..d4a407e466b5 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -166,6 +166,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
 
 	dev_info(dev, "Chrome EC device registered\n");
 
+	cros_ec_acpi_install_gpe_handler(dev);
+
 	return 0;
 
 fail_mfd:
@@ -179,6 +181,8 @@ int cros_ec_remove(struct cros_ec_device *ec_dev)
 {
 	mfd_remove_devices(ec_dev->dev);
 
+	cros_ec_acpi_remove_gpe_handler();
+
 	return 0;
 }
 EXPORT_SYMBOL(cros_ec_remove);
@@ -190,9 +194,14 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
 	int ret;
 	u8 sleep_event;
 
-	sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ?
-		      HOST_SLEEP_EVENT_S3_RESUME :
-		      HOST_SLEEP_EVENT_S0IX_RESUME;
+	if (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) {
+		sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND;
+	} else {
+		sleep_event = HOST_SLEEP_EVENT_S0IX_SUSPEND;
+
+		/* Clearing the GPE status for any pending event */
+		cros_ec_acpi_clear_gpe();
+	}
 
 	ret = cros_ec_sleep_event(ec_dev, sleep_event);
 	if (ret < 0)
diff --git a/drivers/mfd/cros_ec_acpi_gpe.c b/drivers/mfd/cros_ec_acpi_gpe.c
new file mode 100644
index 000000000000..56d305dab2d4
--- /dev/null
+++ b/drivers/mfd/cros_ec_acpi_gpe.c
@@ -0,0 +1,103 @@
+/*
+ * ChromeOS EC multi-function device
+ *
+ * Copyright (C) 2017 Google, Inc
+ *
+ * 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.
+ *
+ * The ChromeOS EC multi function device is used to mux all the requests
+ * to the EC device for its multiple features: keyboard controller,
+ * battery charging and regulator control, firmware update.
+ */
+#include <linux/acpi.h>
+
+#define ACPI_LID_DEVICE      "LID0"
+
+static int ec_wake_gpe = -EINVAL;
+
+/*
+ * This handler indicates to ACPI core that this GPE should stay enabled for
+ * lid to work in suspend to idle path.
+ */
+static u32 cros_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number,
+			       void *data)
+{
+	return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
+}
+
+/*
+ * Get ACPI GPE for LID0 device.
+ */
+static int cros_ec_get_ec_wake_gpe(struct device *dev)
+{
+	struct acpi_device *cros_acpi_dev;
+	struct acpi_device *adev;
+	acpi_handle handle;
+	acpi_status status;
+	int ret;
+
+	cros_acpi_dev = ACPI_COMPANION(dev);
+
+	if (!cros_acpi_dev || !cros_acpi_dev->parent ||
+	   !cros_acpi_dev->parent->handle)
+		return -EINVAL;
+
+	status = acpi_get_handle(cros_acpi_dev->parent->handle, ACPI_LID_DEVICE,
+				 &handle);
+	if (ACPI_FAILURE(status))
+		return -EINVAL;
+
+	ret = acpi_bus_get_device(handle, &adev);
+	if (ret)
+		return ret;
+
+	return adev->wakeup.gpe_number;
+}
+
+int cros_ec_acpi_install_gpe_handler(struct device *dev)
+{
+	acpi_status status;
+
+	ec_wake_gpe = cros_ec_get_ec_wake_gpe(dev);
+
+	if (ec_wake_gpe < 0)
+		return ec_wake_gpe;
+
+	status = acpi_install_gpe_handler(NULL, ec_wake_gpe,
+					  ACPI_GPE_EDGE_TRIGGERED,
+					  &cros_ec_gpe_handler, NULL);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	dev_info(dev, "Initialized, GPE = 0x%x\n", ec_wake_gpe);
+
+	return 0;
+}
+
+void cros_ec_acpi_remove_gpe_handler(void)
+{
+	acpi_status status;
+
+	if (ec_wake_gpe < 0)
+		return;
+
+	status = acpi_remove_gpe_handler(NULL, ec_wake_gpe,
+						 &cros_ec_gpe_handler);
+	if (ACPI_FAILURE(status))
+		pr_err("failed to remove gpe handler\n");
+}
+
+void cros_ec_acpi_clear_gpe(void)
+{
+	if (ec_wake_gpe < 0)
+		return;
+
+	acpi_clear_gpe(NULL, ec_wake_gpe);
+}
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c
index a518832ed5f5..c9714072e224 100644
--- a/drivers/mfd/cros_ec_spi.c
+++ b/drivers/mfd/cros_ec_spi.c
@@ -45,8 +45,11 @@
  * on the other end and need to transfer ~256 bytes, then we need:
  *  10 us/bit * ~10 bits/byte * ~256 bytes = ~25ms
  *
- * We'll wait 4 times that to handle clock stretching and other
- * paranoia.
+ * We'll wait 8 times that to handle clock stretching and other
+ * paranoia.  Note that some battery gas gauge ICs claim to have a
+ * clock stretch of 144ms in rare situations.  That's incentive for
+ * not directly passing i2c through, but it's too late for that for
+ * existing hardware.
  *
  * It's pretty unlikely that we'll really see a 249 byte tunnel in
  * anything other than testing.  If this was more common we might
@@ -54,7 +57,7 @@
  * wait loop.  The 'flash write' command would be another candidate
  * for this, clocking in at 2-3ms.
  */
-#define EC_MSG_DEADLINE_MS		100
+#define EC_MSG_DEADLINE_MS		200
 
 /*
   * Time between raising the SPI chip select (for the end of a
diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
index 8f873866ea60..7f5e8be0a9ea 100644
--- a/drivers/mfd/da9062-core.c
+++ b/drivers/mfd/da9062-core.c
@@ -1,6 +1,6 @@
 /*
- * Core, IRQ and I2C device driver for DA9062 PMIC
- * Copyright (C) 2015  Dialog Semiconductor Ltd.
+ * Core, IRQ and I2C device driver for DA9061 and DA9062 PMICs
+ * Copyright (C) 2015-2017  Dialog Semiconductor
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -30,6 +30,70 @@
 #define	DA9062_REG_EVENT_B_OFFSET	1
 #define	DA9062_REG_EVENT_C_OFFSET	2
 
+static struct regmap_irq da9061_irqs[] = {
+	/* EVENT A */
+	[DA9061_IRQ_ONKEY] = {
+		.reg_offset = DA9062_REG_EVENT_A_OFFSET,
+		.mask = DA9062AA_M_NONKEY_MASK,
+	},
+	[DA9061_IRQ_WDG_WARN] = {
+		.reg_offset = DA9062_REG_EVENT_A_OFFSET,
+		.mask = DA9062AA_M_WDG_WARN_MASK,
+	},
+	[DA9061_IRQ_SEQ_RDY] = {
+		.reg_offset = DA9062_REG_EVENT_A_OFFSET,
+		.mask = DA9062AA_M_SEQ_RDY_MASK,
+	},
+	/* EVENT B */
+	[DA9061_IRQ_TEMP] = {
+		.reg_offset = DA9062_REG_EVENT_B_OFFSET,
+		.mask = DA9062AA_M_TEMP_MASK,
+	},
+	[DA9061_IRQ_LDO_LIM] = {
+		.reg_offset = DA9062_REG_EVENT_B_OFFSET,
+		.mask = DA9062AA_M_LDO_LIM_MASK,
+	},
+	[DA9061_IRQ_DVC_RDY] = {
+		.reg_offset = DA9062_REG_EVENT_B_OFFSET,
+		.mask = DA9062AA_M_DVC_RDY_MASK,
+	},
+	[DA9061_IRQ_VDD_WARN] = {
+		.reg_offset = DA9062_REG_EVENT_B_OFFSET,
+		.mask = DA9062AA_M_VDD_WARN_MASK,
+	},
+	/* EVENT C */
+	[DA9061_IRQ_GPI0] = {
+		.reg_offset = DA9062_REG_EVENT_C_OFFSET,
+		.mask = DA9062AA_M_GPI0_MASK,
+	},
+	[DA9061_IRQ_GPI1] = {
+		.reg_offset = DA9062_REG_EVENT_C_OFFSET,
+		.mask = DA9062AA_M_GPI1_MASK,
+	},
+	[DA9061_IRQ_GPI2] = {
+		.reg_offset = DA9062_REG_EVENT_C_OFFSET,
+		.mask = DA9062AA_M_GPI2_MASK,
+	},
+	[DA9061_IRQ_GPI3] = {
+		.reg_offset = DA9062_REG_EVENT_C_OFFSET,
+		.mask = DA9062AA_M_GPI3_MASK,
+	},
+	[DA9061_IRQ_GPI4] = {
+		.reg_offset = DA9062_REG_EVENT_C_OFFSET,
+		.mask = DA9062AA_M_GPI4_MASK,
+	},
+};
+
+static struct regmap_irq_chip da9061_irq_chip = {
+	.name = "da9061-irq",
+	.irqs = da9061_irqs,
+	.num_irqs = DA9061_NUM_IRQ,
+	.num_regs = 3,
+	.status_base = DA9062AA_EVENT_A,
+	.mask_base = DA9062AA_IRQ_MASK_A,
+	.ack_base = DA9062AA_EVENT_A,
+};
+
 static struct regmap_irq da9062_irqs[] = {
 	/* EVENT A */
 	[DA9062_IRQ_ONKEY] = {
@@ -102,6 +166,57 @@ static struct regmap_irq_chip da9062_irq_chip = {
 	.ack_base = DA9062AA_EVENT_A,
 };
 
+static struct resource da9061_core_resources[] = {
+	DEFINE_RES_IRQ_NAMED(DA9061_IRQ_VDD_WARN, "VDD_WARN"),
+};
+
+static struct resource da9061_regulators_resources[] = {
+	DEFINE_RES_IRQ_NAMED(DA9061_IRQ_LDO_LIM, "LDO_LIM"),
+};
+
+static struct resource da9061_thermal_resources[] = {
+	DEFINE_RES_IRQ_NAMED(DA9061_IRQ_TEMP, "THERMAL"),
+};
+
+static struct resource da9061_wdt_resources[] = {
+	DEFINE_RES_IRQ_NAMED(DA9061_IRQ_WDG_WARN, "WD_WARN"),
+};
+
+static struct resource da9061_onkey_resources[] = {
+	DEFINE_RES_IRQ_NAMED(DA9061_IRQ_ONKEY, "ONKEY"),
+};
+
+static const struct mfd_cell da9061_devs[] = {
+	{
+		.name		= "da9061-core",
+		.num_resources	= ARRAY_SIZE(da9061_core_resources),
+		.resources	= da9061_core_resources,
+	},
+	{
+		.name		= "da9062-regulators",
+		.num_resources	= ARRAY_SIZE(da9061_regulators_resources),
+		.resources	= da9061_regulators_resources,
+	},
+	{
+		.name		= "da9061-watchdog",
+		.num_resources	= ARRAY_SIZE(da9061_wdt_resources),
+		.resources	= da9061_wdt_resources,
+		.of_compatible  = "dlg,da9061-watchdog",
+	},
+	{
+		.name		= "da9061-thermal",
+		.num_resources	= ARRAY_SIZE(da9061_thermal_resources),
+		.resources	= da9061_thermal_resources,
+		.of_compatible  = "dlg,da9061-thermal",
+	},
+	{
+		.name		= "da9061-onkey",
+		.num_resources	= ARRAY_SIZE(da9061_onkey_resources),
+		.resources	= da9061_onkey_resources,
+		.of_compatible = "dlg,da9061-onkey",
+	},
+};
+
 static struct resource da9062_core_resources[] = {
 	DEFINE_RES_NAMED(DA9062_IRQ_VDD_WARN, 1, "VDD_WARN", IORESOURCE_IRQ),
 };
@@ -200,7 +315,8 @@ static int da9062_clear_fault_log(struct da9062 *chip)
 
 static int da9062_get_device_type(struct da9062 *chip)
 {
-	int device_id, variant_id, variant_mrc;
+	int device_id, variant_id, variant_mrc, variant_vrc;
+	char *type;
 	int ret;
 
 	ret = regmap_read(chip->regmap, DA9062AA_DEVICE_ID, &device_id);
@@ -219,9 +335,23 @@ static int da9062_get_device_type(struct da9062 *chip)
 		return -EIO;
 	}
 
+	variant_vrc = (variant_id & DA9062AA_VRC_MASK) >> DA9062AA_VRC_SHIFT;
+
+	switch (variant_vrc) {
+	case DA9062_PMIC_VARIANT_VRC_DA9061:
+		type = "DA9061";
+		break;
+	case DA9062_PMIC_VARIANT_VRC_DA9062:
+		type = "DA9062";
+		break;
+	default:
+		type = "Unknown";
+		break;
+	}
+
 	dev_info(chip->dev,
-		 "Device detected (device-ID: 0x%02X, var-ID: 0x%02X)\n",
-		 device_id, variant_id);
+		 "Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n",
+		 device_id, variant_id, type);
 
 	variant_mrc = (variant_id & DA9062AA_MRC_MASK) >> DA9062AA_MRC_SHIFT;
 
@@ -234,6 +364,234 @@ static int da9062_get_device_type(struct da9062 *chip)
 	return ret;
 }
 
+static const struct regmap_range da9061_aa_readable_ranges[] = {
+	{
+		.range_min = DA9062AA_PAGE_CON,
+		.range_max = DA9062AA_STATUS_B,
+	}, {
+		.range_min = DA9062AA_STATUS_D,
+		.range_max = DA9062AA_EVENT_C,
+	}, {
+		.range_min = DA9062AA_IRQ_MASK_A,
+		.range_max = DA9062AA_IRQ_MASK_C,
+	}, {
+		.range_min = DA9062AA_CONTROL_A,
+		.range_max = DA9062AA_GPIO_4,
+	}, {
+		.range_min = DA9062AA_GPIO_WKUP_MODE,
+		.range_max = DA9062AA_GPIO_OUT3_4,
+	}, {
+		.range_min = DA9062AA_BUCK1_CONT,
+		.range_max = DA9062AA_BUCK4_CONT,
+	}, {
+		.range_min = DA9062AA_BUCK3_CONT,
+		.range_max = DA9062AA_BUCK3_CONT,
+	}, {
+		.range_min = DA9062AA_LDO1_CONT,
+		.range_max = DA9062AA_LDO4_CONT,
+	}, {
+		.range_min = DA9062AA_DVC_1,
+		.range_max = DA9062AA_DVC_1,
+	}, {
+		.range_min = DA9062AA_SEQ,
+		.range_max = DA9062AA_ID_4_3,
+	}, {
+		.range_min = DA9062AA_ID_12_11,
+		.range_max = DA9062AA_ID_16_15,
+	}, {
+		.range_min = DA9062AA_ID_22_21,
+		.range_max = DA9062AA_ID_32_31,
+	}, {
+		.range_min = DA9062AA_SEQ_A,
+		.range_max = DA9062AA_WAIT,
+	}, {
+		.range_min = DA9062AA_RESET,
+		.range_max = DA9062AA_BUCK_ILIM_C,
+	}, {
+		.range_min = DA9062AA_BUCK1_CFG,
+		.range_max = DA9062AA_BUCK3_CFG,
+	}, {
+		.range_min = DA9062AA_VBUCK1_A,
+		.range_max = DA9062AA_VBUCK4_A,
+	}, {
+		.range_min = DA9062AA_VBUCK3_A,
+		.range_max = DA9062AA_VBUCK3_A,
+	}, {
+		.range_min = DA9062AA_VLDO1_A,
+		.range_max = DA9062AA_VLDO4_A,
+	}, {
+		.range_min = DA9062AA_VBUCK1_B,
+		.range_max = DA9062AA_VBUCK4_B,
+	}, {
+		.range_min = DA9062AA_VBUCK3_B,
+		.range_max = DA9062AA_VBUCK3_B,
+	}, {
+		.range_min = DA9062AA_VLDO1_B,
+		.range_max = DA9062AA_VLDO4_B,
+	}, {
+		.range_min = DA9062AA_BBAT_CONT,
+		.range_max = DA9062AA_BBAT_CONT,
+	}, {
+		.range_min = DA9062AA_INTERFACE,
+		.range_max = DA9062AA_CONFIG_E,
+	}, {
+		.range_min = DA9062AA_CONFIG_G,
+		.range_max = DA9062AA_CONFIG_K,
+	}, {
+		.range_min = DA9062AA_CONFIG_M,
+		.range_max = DA9062AA_CONFIG_M,
+	}, {
+		.range_min = DA9062AA_GP_ID_0,
+		.range_max = DA9062AA_GP_ID_19,
+	}, {
+		.range_min = DA9062AA_DEVICE_ID,
+		.range_max = DA9062AA_CONFIG_ID,
+	},
+};
+
+static const struct regmap_range da9061_aa_writeable_ranges[] = {
+	{
+		.range_min = DA9062AA_PAGE_CON,
+		.range_max = DA9062AA_PAGE_CON,
+	}, {
+		.range_min = DA9062AA_FAULT_LOG,
+		.range_max = DA9062AA_EVENT_C,
+	}, {
+		.range_min = DA9062AA_IRQ_MASK_A,
+		.range_max = DA9062AA_IRQ_MASK_C,
+	}, {
+		.range_min = DA9062AA_CONTROL_A,
+		.range_max = DA9062AA_GPIO_4,
+	}, {
+		.range_min = DA9062AA_GPIO_WKUP_MODE,
+		.range_max = DA9062AA_GPIO_OUT3_4,
+	}, {
+		.range_min = DA9062AA_BUCK1_CONT,
+		.range_max = DA9062AA_BUCK4_CONT,
+	}, {
+		.range_min = DA9062AA_BUCK3_CONT,
+		.range_max = DA9062AA_BUCK3_CONT,
+	}, {
+		.range_min = DA9062AA_LDO1_CONT,
+		.range_max = DA9062AA_LDO4_CONT,
+	}, {
+		.range_min = DA9062AA_DVC_1,
+		.range_max = DA9062AA_DVC_1,
+	}, {
+		.range_min = DA9062AA_SEQ,
+		.range_max = DA9062AA_ID_4_3,
+	}, {
+		.range_min = DA9062AA_ID_12_11,
+		.range_max = DA9062AA_ID_16_15,
+	}, {
+		.range_min = DA9062AA_ID_22_21,
+		.range_max = DA9062AA_ID_32_31,
+	}, {
+		.range_min = DA9062AA_SEQ_A,
+		.range_max = DA9062AA_WAIT,
+	}, {
+		.range_min = DA9062AA_RESET,
+		.range_max = DA9062AA_BUCK_ILIM_C,
+	}, {
+		.range_min = DA9062AA_BUCK1_CFG,
+		.range_max = DA9062AA_BUCK3_CFG,
+	}, {
+		.range_min = DA9062AA_VBUCK1_A,
+		.range_max = DA9062AA_VBUCK4_A,
+	}, {
+		.range_min = DA9062AA_VBUCK3_A,
+		.range_max = DA9062AA_VBUCK3_A,
+	}, {
+		.range_min = DA9062AA_VLDO1_A,
+		.range_max = DA9062AA_VLDO4_A,
+	}, {
+		.range_min = DA9062AA_VBUCK1_B,
+		.range_max = DA9062AA_VBUCK4_B,
+	}, {
+		.range_min = DA9062AA_VBUCK3_B,
+		.range_max = DA9062AA_VBUCK3_B,
+	}, {
+		.range_min = DA9062AA_VLDO1_B,
+		.range_max = DA9062AA_VLDO4_B,
+	}, {
+		.range_min = DA9062AA_BBAT_CONT,
+		.range_max = DA9062AA_BBAT_CONT,
+	}, {
+		.range_min = DA9062AA_GP_ID_0,
+		.range_max = DA9062AA_GP_ID_19,
+	},
+};
+
+static const struct regmap_range da9061_aa_volatile_ranges[] = {
+	{
+		.range_min = DA9062AA_PAGE_CON,
+		.range_max = DA9062AA_STATUS_B,
+	}, {
+		.range_min = DA9062AA_STATUS_D,
+		.range_max = DA9062AA_EVENT_C,
+	}, {
+		.range_min = DA9062AA_CONTROL_A,
+		.range_max = DA9062AA_CONTROL_B,
+	}, {
+		.range_min = DA9062AA_CONTROL_E,
+		.range_max = DA9062AA_CONTROL_F,
+	}, {
+		.range_min = DA9062AA_BUCK1_CONT,
+		.range_max = DA9062AA_BUCK4_CONT,
+	}, {
+		.range_min = DA9062AA_BUCK3_CONT,
+		.range_max = DA9062AA_BUCK3_CONT,
+	}, {
+		.range_min = DA9062AA_LDO1_CONT,
+		.range_max = DA9062AA_LDO4_CONT,
+	}, {
+		.range_min = DA9062AA_DVC_1,
+		.range_max = DA9062AA_DVC_1,
+	}, {
+		.range_min = DA9062AA_SEQ,
+		.range_max = DA9062AA_SEQ,
+	},
+};
+
+static const struct regmap_access_table da9061_aa_readable_table = {
+	.yes_ranges = da9061_aa_readable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(da9061_aa_readable_ranges),
+};
+
+static const struct regmap_access_table da9061_aa_writeable_table = {
+	.yes_ranges = da9061_aa_writeable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(da9061_aa_writeable_ranges),
+};
+
+static const struct regmap_access_table da9061_aa_volatile_table = {
+	.yes_ranges = da9061_aa_volatile_ranges,
+	.n_yes_ranges = ARRAY_SIZE(da9061_aa_volatile_ranges),
+};
+
+static const struct regmap_range_cfg da9061_range_cfg[] = {
+	{
+		.range_min = DA9062AA_PAGE_CON,
+		.range_max = DA9062AA_CONFIG_ID,
+		.selector_reg = DA9062AA_PAGE_CON,
+		.selector_mask = 1 << DA9062_I2C_PAGE_SEL_SHIFT,
+		.selector_shift = DA9062_I2C_PAGE_SEL_SHIFT,
+		.window_start = 0,
+		.window_len = 256,
+	}
+};
+
+static struct regmap_config da9061_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.ranges = da9061_range_cfg,
+	.num_ranges = ARRAY_SIZE(da9061_range_cfg),
+	.max_register = DA9062AA_CONFIG_ID,
+	.cache_type = REGCACHE_RBTREE,
+	.rd_table = &da9061_aa_readable_table,
+	.wr_table = &da9061_aa_writeable_table,
+	.volatile_table = &da9061_aa_volatile_table,
+};
+
 static const struct regmap_range da9062_aa_readable_ranges[] = {
 	{
 		.range_min = DA9062AA_PAGE_CON,
@@ -456,17 +814,39 @@ static struct regmap_config da9062_regmap_config = {
 	.volatile_table = &da9062_aa_volatile_table,
 };
 
+static const struct of_device_id da9062_dt_ids[] = {
+	{ .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061, },
+	{ .compatible = "dlg,da9062", .data = (void *)COMPAT_TYPE_DA9062, },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, da9062_dt_ids);
+
 static int da9062_i2c_probe(struct i2c_client *i2c,
 	const struct i2c_device_id *id)
 {
 	struct da9062 *chip;
+	const struct of_device_id *match;
 	unsigned int irq_base;
+	const struct mfd_cell *cell;
+	const struct regmap_irq_chip *irq_chip;
+	const struct regmap_config *config;
+	int cell_num;
 	int ret;
 
 	chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
 
+	if (i2c->dev.of_node) {
+		match = of_match_node(da9062_dt_ids, i2c->dev.of_node);
+		if (!match)
+			return -EINVAL;
+
+		chip->chip_type = (uintptr_t)match->data;
+	} else {
+		chip->chip_type = id->driver_data;
+	}
+
 	i2c_set_clientdata(i2c, chip);
 	chip->dev = &i2c->dev;
 
@@ -475,7 +855,25 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
 		return -EINVAL;
 	}
 
-	chip->regmap = devm_regmap_init_i2c(i2c, &da9062_regmap_config);
+	switch (chip->chip_type) {
+	case COMPAT_TYPE_DA9061:
+		cell = da9061_devs;
+		cell_num = ARRAY_SIZE(da9061_devs);
+		irq_chip = &da9061_irq_chip;
+		config = &da9061_regmap_config;
+		break;
+	case COMPAT_TYPE_DA9062:
+		cell = da9062_devs;
+		cell_num = ARRAY_SIZE(da9062_devs);
+		irq_chip = &da9062_irq_chip;
+		config = &da9062_regmap_config;
+		break;
+	default:
+		dev_err(chip->dev, "Unrecognised chip type\n");
+		return -ENODEV;
+	}
+
+	chip->regmap = devm_regmap_init_i2c(i2c, config);
 	if (IS_ERR(chip->regmap)) {
 		ret = PTR_ERR(chip->regmap);
 		dev_err(chip->dev, "Failed to allocate register map: %d\n",
@@ -493,7 +891,7 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
 
 	ret = regmap_add_irq_chip(chip->regmap, i2c->irq,
 			IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
-			-1, &da9062_irq_chip,
+			-1, irq_chip,
 			&chip->regmap_irq);
 	if (ret) {
 		dev_err(chip->dev, "Failed to request IRQ %d: %d\n",
@@ -503,8 +901,8 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
 
 	irq_base = regmap_irq_chip_get_base(chip->regmap_irq);
 
-	ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, da9062_devs,
-			      ARRAY_SIZE(da9062_devs), NULL, irq_base,
+	ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell,
+			      cell_num, NULL, irq_base,
 			      NULL);
 	if (ret) {
 		dev_err(chip->dev, "Cannot register child devices\n");
@@ -526,17 +924,12 @@ static int da9062_i2c_remove(struct i2c_client *i2c)
 }
 
 static const struct i2c_device_id da9062_i2c_id[] = {
-	{ "da9062", 0 },
+	{ "da9061", COMPAT_TYPE_DA9061 },
+	{ "da9062", COMPAT_TYPE_DA9062 },
 	{ },
 };
 MODULE_DEVICE_TABLE(i2c, da9062_i2c_id);
 
-static const struct of_device_id da9062_dt_ids[] = {
-	{ .compatible = "dlg,da9062", },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, da9062_dt_ids);
-
 static struct i2c_driver da9062_i2c_driver = {
 	.driver = {
 		.name = "da9062",
@@ -549,6 +942,6 @@ static struct i2c_driver da9062_i2c_driver = {
 
 module_i2c_driver(da9062_i2c_driver);
 
-MODULE_DESCRIPTION("Core device driver for Dialog DA9062");
+MODULE_DESCRIPTION("Core device driver for Dialog DA9061 and DA9062");
 MODULE_AUTHOR("Steve Twiss <stwiss.opensource@diasemi.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index ca38a6a14110..5c739ac752e8 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -2377,7 +2377,7 @@ static void ack_dbb_wakeup(void)
 
 static inline void print_unknown_header_warning(u8 n, u8 header)
 {
-	pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+	pr_warn("prcmu: Unknown message header (%d) in mailbox %d\n",
 		header, n);
 }
 
diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c
index 2e064fb8826f..0bf3aebdac45 100644
--- a/drivers/mfd/exynos-lpass.c
+++ b/drivers/mfd/exynos-lpass.c
@@ -14,15 +14,17 @@
  * only version 2 as published by the Free Software Foundation.
  */
 
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/exynos5-pmu.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
+#include <linux/soc/samsung/exynos-regs-pmu.h>
 #include <linux/types.h>
 
 /* LPASS Top register definitions */
@@ -51,10 +53,9 @@
 #define  LPASS_INTR_SFR			BIT(0)
 
 struct exynos_lpass {
-	/* pointer to the Power Management Unit regmap */
-	struct regmap *pmu;
 	/* pointer to the LPASS TOP regmap */
 	struct regmap *top;
+	struct clk *sfr0_clk;
 };
 
 static void exynos_lpass_core_sw_reset(struct exynos_lpass *lpass, int mask)
@@ -74,6 +75,8 @@ static void exynos_lpass_core_sw_reset(struct exynos_lpass *lpass, int mask)
 
 static void exynos_lpass_enable(struct exynos_lpass *lpass)
 {
+	clk_prepare_enable(lpass->sfr0_clk);
+
 	/* Unmask SFR, DMA and I2S interrupt */
 	regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK,
 		     LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
@@ -81,10 +84,6 @@ static void exynos_lpass_enable(struct exynos_lpass *lpass)
 	regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK,
 		     LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
 
-	/* Activate related PADs from retention state */
-	regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION,
-		     EXYNOS5433_PAD_INITIATE_WAKEUP_FROM_LOWPWR);
-
 	exynos_lpass_core_sw_reset(lpass, LPASS_I2S_SW_RESET);
 	exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET);
 	exynos_lpass_core_sw_reset(lpass, LPASS_MEM_SW_RESET);
@@ -96,8 +95,7 @@ static void exynos_lpass_disable(struct exynos_lpass *lpass)
 	regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK, 0);
 	regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK, 0);
 
-	/* Deactivate related PADs from retention state */
-	regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION, 0);
+	clk_disable_unprepare(lpass->sfr0_clk);
 }
 
 static const struct regmap_config exynos_lpass_reg_conf = {
@@ -124,6 +122,10 @@ static int exynos_lpass_probe(struct platform_device *pdev)
 	if (IS_ERR(base_top))
 		return PTR_ERR(base_top);
 
+	lpass->sfr0_clk = devm_clk_get(dev, "sfr0_ctrl");
+	if (IS_ERR(lpass->sfr0_clk))
+		return PTR_ERR(lpass->sfr0_clk);
+
 	lpass->top = regmap_init_mmio(dev, base_top,
 					&exynos_lpass_reg_conf);
 	if (IS_ERR(lpass->top)) {
@@ -131,19 +133,27 @@ static int exynos_lpass_probe(struct platform_device *pdev)
 		return PTR_ERR(lpass->top);
 	}
 
-	lpass->pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
-						"samsung,pmu-syscon");
-	if (IS_ERR(lpass->pmu)) {
-		dev_err(dev, "Failed to lookup PMU regmap\n");
-		return PTR_ERR(lpass->pmu);
-	}
-
 	platform_set_drvdata(pdev, lpass);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
 	exynos_lpass_enable(lpass);
 
 	return of_platform_populate(dev->of_node, NULL, NULL, dev);
 }
 
+static int exynos_lpass_remove(struct platform_device *pdev)
+{
+	struct exynos_lpass *lpass = platform_get_drvdata(pdev);
+
+	exynos_lpass_disable(lpass);
+	pm_runtime_disable(&pdev->dev);
+	if (!pm_runtime_status_suspended(&pdev->dev))
+		exynos_lpass_disable(lpass);
+	regmap_exit(lpass->top);
+
+	return 0;
+}
+
 static int __maybe_unused exynos_lpass_suspend(struct device *dev)
 {
 	struct exynos_lpass *lpass = dev_get_drvdata(dev);
@@ -162,8 +172,11 @@ static int __maybe_unused exynos_lpass_resume(struct device *dev)
 	return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(lpass_pm_ops, exynos_lpass_suspend,
-					exynos_lpass_resume);
+static const struct dev_pm_ops lpass_pm_ops = {
+	SET_RUNTIME_PM_OPS(exynos_lpass_suspend, exynos_lpass_resume, NULL)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				     pm_runtime_force_resume)
+};
 
 static const struct of_device_id exynos_lpass_of_match[] = {
 	{ .compatible = "samsung,exynos5433-lpass" },
@@ -178,6 +191,7 @@ static struct platform_driver exynos_lpass_driver = {
 		.of_match_table	= exynos_lpass_of_match,
 	},
 	.probe	= exynos_lpass_probe,
+	.remove	= exynos_lpass_remove,
 };
 module_platform_driver(exynos_lpass_driver);
 
diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c
index ba706adee38b..c37ccbfd52f2 100644
--- a/drivers/mfd/hi655x-pmic.c
+++ b/drivers/mfd/hi655x-pmic.c
@@ -77,7 +77,8 @@ static const struct mfd_cell hi655x_pmic_devs[] = {
 		.num_resources	= ARRAY_SIZE(pwrkey_resources),
 		.resources	= &pwrkey_resources[0],
 	},
-	{	.name		= "hi655x-regulator", },
+	{	.name		= "hi655x-regulator",	},
+	{	.name		= "hi655x-clk",		},
 };
 
 static void hi655x_local_irq_clear(struct regmap *map)
diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c
index 6bf8d643d942..7911b0a14a6d 100644
--- a/drivers/mfd/intel-lpss-acpi.c
+++ b/drivers/mfd/intel-lpss-acpi.c
@@ -22,10 +22,6 @@
 
 #include "intel-lpss.h"
 
-static const struct intel_lpss_platform_info spt_info = {
-	.clk_rate = 120000000,
-};
-
 static struct property_entry spt_i2c_properties[] = {
 	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
 	{ },
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index 699c8c7c9052..8c3cbf63c6ad 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -20,7 +20,8 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mfd/core.h>
-#include <linux/mfd/intel_bxtwc.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/mfd/intel_soc_pmic_bxtwc.h>
 #include <asm/intel_pmc_ipc.h>
 
 /* PMIC device registers */
@@ -237,15 +238,14 @@ static int regmap_ipc_byte_reg_read(void *context, unsigned int reg,
 	u8 ipc_out[4];
 	struct intel_soc_pmic *pmic = context;
 
+	if (!pmic)
+		return -EINVAL;
+
 	if (reg & REG_ADDR_MASK)
 		i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
-	else {
+	else
 		i2c_addr = BXTWC_DEVICE1_ADDR;
-		if (!i2c_addr) {
-			dev_err(pmic->dev, "I2C address not set\n");
-			return -EINVAL;
-		}
-	}
+
 	reg &= REG_OFFSET_MASK;
 
 	ipc_in[0] = reg;
@@ -270,15 +270,14 @@ static int regmap_ipc_byte_reg_write(void *context, unsigned int reg,
 	u8 ipc_in[3];
 	struct intel_soc_pmic *pmic = context;
 
+	if (!pmic)
+		return -EINVAL;
+
 	if (reg & REG_ADDR_MASK)
 		i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
-	else {
+	else
 		i2c_addr = BXTWC_DEVICE1_ADDR;
-		if (!i2c_addr) {
-			dev_err(pmic->dev, "I2C address not set\n");
-			return -EINVAL;
-		}
-	}
+
 	reg &= REG_OFFSET_MASK;
 
 	ipc_in[0] = reg;
diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c
index 12d6ebb4ae5d..13737be6df35 100644
--- a/drivers/mfd/intel_soc_pmic_core.c
+++ b/drivers/mfd/intel_soc_pmic_core.c
@@ -44,22 +44,6 @@ static struct pwm_lookup crc_pwm_lookup[] = {
 	PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_backlight", 0, PWM_POLARITY_NORMAL),
 };
 
-static int intel_soc_pmic_find_gpio_irq(struct device *dev)
-{
-	struct gpio_desc *desc;
-	int irq;
-
-	desc = devm_gpiod_get_index(dev, "intel_soc_pmic", 0, GPIOD_IN);
-	if (IS_ERR(desc))
-		return PTR_ERR(desc);
-
-	irq = gpiod_to_irq(desc);
-	if (irq < 0)
-		dev_warn(dev, "Can't get irq: %d\n", irq);
-
-	return irq;
-}
-
 static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
 				    const struct i2c_device_id *i2c_id)
 {
@@ -68,7 +52,6 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
 	struct intel_soc_pmic_config *config;
 	struct intel_soc_pmic *pmic;
 	int ret;
-	int irq;
 
 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
 	if (!id || !id->driver_data)
@@ -83,14 +66,10 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
 	dev_set_drvdata(dev, pmic);
 
 	pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config);
+	if (IS_ERR(pmic->regmap))
+		return PTR_ERR(pmic->regmap);
 
-	/*
-	 * On some boards the PMIC interrupt may come from a GPIO line. Try to
-	 * lookup the ACPI table for a such connection and setup a GPIO
-	 * interrupt if it exists. Otherwise use the IRQ provided by I2C
-	 */
-	irq = intel_soc_pmic_find_gpio_irq(dev);
-	pmic->irq = (irq < 0) ? i2c->irq : irq;
+	pmic->irq = i2c->irq;
 
 	ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
 				  config->irq_flags | IRQF_ONESHOT,
diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c
index df16fd1df68b..124aad2b1d02 100644
--- a/drivers/mfd/ipaq-micro.c
+++ b/drivers/mfd/ipaq-micro.c
@@ -400,9 +400,6 @@ static int __init micro_probe(struct platform_device *pdev)
 	micro->dev = &pdev->dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -EINVAL;
-
 	micro->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(micro->base))
 		return PTR_ERR(micro->base);
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index d98a5d974092..773f1554d2f9 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -227,6 +227,8 @@ enum lpc_chipsets {
 	LPC_LEWISBURG,	/* Lewisburg */
 	LPC_9S,		/* 9 Series */
 	LPC_APL,	/* Apollo Lake SoC */
+	LPC_GLK,	/* Gemini Lake SoC */
+	LPC_COUGARMOUNTAIN,/* Cougar Mountain SoC*/
 };
 
 static struct lpc_ich_info lpc_chipset_info[] = {
@@ -554,6 +556,14 @@ static struct lpc_ich_info lpc_chipset_info[] = {
 		.iTCO_version = 5,
 		.spi_type = INTEL_SPI_BXT,
 	},
+	[LPC_GLK] = {
+		.name = "Gemini Lake SoC",
+		.spi_type = INTEL_SPI_BXT,
+	},
+	[LPC_COUGARMOUNTAIN] = {
+		.name = "Cougar Mountain SoC",
+		.iTCO_version = 3,
+	},
 };
 
 /*
@@ -682,6 +692,8 @@ static const struct pci_device_id lpc_ich_ids[] = {
 	{ PCI_VDEVICE(INTEL, 0x2917), LPC_ICH9ME},
 	{ PCI_VDEVICE(INTEL, 0x2918), LPC_ICH9},
 	{ PCI_VDEVICE(INTEL, 0x2919), LPC_ICH9M},
+	{ PCI_VDEVICE(INTEL, 0x3197), LPC_GLK},
+	{ PCI_VDEVICE(INTEL, 0x2b9c), LPC_COUGARMOUNTAIN},
 	{ PCI_VDEVICE(INTEL, 0x3a14), LPC_ICH10DO},
 	{ PCI_VDEVICE(INTEL, 0x3a16), LPC_ICH10R},
 	{ PCI_VDEVICE(INTEL, 0x3a18), LPC_ICH10},
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c
index a4a8f1ec3fb6..29b7164a823b 100644
--- a/drivers/mfd/menelaus.c
+++ b/drivers/mfd/menelaus.c
@@ -1022,9 +1022,7 @@ static int menelaus_set_alarm(struct device *dev, struct rtc_wkalrm *w)
 static void menelaus_rtc_update_work(struct menelaus_chip *m)
 {
 	/* report 1/sec update */
-	local_irq_disable();
 	rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_UF);
-	local_irq_enable();
 }
 
 static int menelaus_ioctl(struct device *dev, unsigned cmd, unsigned long arg)
@@ -1086,9 +1084,7 @@ static const struct rtc_class_ops menelaus_rtc_ops = {
 static void menelaus_rtc_alarm_work(struct menelaus_chip *m)
 {
 	/* report alarm */
-	local_irq_disable();
 	rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_AF);
-	local_irq_enable();
 
 	/* then disable it; alarms are oneshot */
 	the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c
index 6aeada7d7ce5..3cab58ab0b84 100644
--- a/drivers/mfd/motorola-cpcap.c
+++ b/drivers/mfd/motorola-cpcap.c
@@ -23,6 +23,8 @@
 
 #define CPCAP_NR_IRQ_REG_BANKS	6
 #define CPCAP_NR_IRQ_CHIPS	3
+#define CPCAP_REGISTER_SIZE	4
+#define CPCAP_REGISTER_BITS	16
 
 struct cpcap_ddata {
 	struct spi_device *spi;
@@ -32,6 +34,32 @@ struct cpcap_ddata {
 	struct regmap *regmap;
 };
 
+static int cpcap_sense_irq(struct regmap *regmap, int irq)
+{
+	int regnum = irq / CPCAP_REGISTER_BITS;
+	int mask = BIT(irq % CPCAP_REGISTER_BITS);
+	int reg = CPCAP_REG_INTS1 + (regnum * CPCAP_REGISTER_SIZE);
+	int err, val;
+
+	if (reg < CPCAP_REG_INTS1 || reg > CPCAP_REG_INTS4)
+		return -EINVAL;
+
+	err = regmap_read(regmap, reg, &val);
+	if (err)
+		return err;
+
+	return !!(val & mask);
+}
+
+int cpcap_sense_virq(struct regmap *regmap, int virq)
+{
+	struct regmap_irq_chip_data *d = irq_get_chip_data(virq);
+	int irq_base = regmap_irq_chip_get_base(d);
+
+	return cpcap_sense_irq(regmap, virq - irq_base);
+}
+EXPORT_SYMBOL_GPL(cpcap_sense_virq);
+
 static int cpcap_check_revision(struct cpcap_ddata *cpcap)
 {
 	u16 vendor, rev;
@@ -71,6 +99,7 @@ static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
 		.ack_base = CPCAP_REG_MI1,
 		.mask_base = CPCAP_REG_MIM1,
 		.use_ack = true,
+		.ack_invert = true,
 	},
 	{
 		.name = "cpcap-m2",
@@ -79,6 +108,7 @@ static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
 		.ack_base = CPCAP_REG_MI2,
 		.mask_base = CPCAP_REG_MIM2,
 		.use_ack = true,
+		.ack_invert = true,
 	},
 	{
 		.name = "cpcap1-4",
@@ -86,8 +116,8 @@ static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
 		.status_base = CPCAP_REG_INT1,
 		.ack_base = CPCAP_REG_INT1,
 		.mask_base = CPCAP_REG_INTM1,
-		.type_base = CPCAP_REG_INTS1,
 		.use_ack = true,
+		.ack_invert = true,
 	},
 };
 
@@ -126,7 +156,7 @@ static int cpcap_init_irq_chip(struct cpcap_ddata *cpcap, int irq_chip,
 
 	ret = devm_regmap_add_irq_chip(&cpcap->spi->dev, cpcap->regmap,
 				       cpcap->spi->irq,
-				       IRQF_TRIGGER_RISING |
+				       irq_get_trigger_type(cpcap->spi->irq) |
 				       IRQF_SHARED, -1,
 				       chip, &cpcap->irqdata[irq_chip]);
 	if (ret) {
diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index 8e601c846d08..04a601f6aebe 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -47,8 +47,7 @@ static const struct mfd_cell mt6323_devs[] = {
 	{
 		.name = "mt6323-regulator",
 		.of_compatible = "mediatek,mt6323-regulator"
-	},
-	{
+	}, {
 		.name = "mt6323-led",
 		.of_compatible = "mediatek,mt6323-led"
 	},
diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c
new file mode 100644
index 000000000000..630bd19b2c0a
--- /dev/null
+++ b/drivers/mfd/mxs-lradc.c
@@ -0,0 +1,267 @@
+/*
+ * Freescale MXS Low Resolution Analog-to-Digital Converter driver
+ *
+ * Copyright (c) 2012 DENX Software Engineering, GmbH.
+ * Copyright (c) 2017 Ksenija Stanojevic <ksenija.stanojevic@gmail.com>
+ *
+ * Authors:
+ *  Marek Vasut <marex@denx.de>
+ *  Ksenija Stanojevic <ksenija.stanojevic@gmail.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/clk.h>
+#include <linux/device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mxs-lradc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define ADC_CELL		0
+#define TSC_CELL		1
+#define RES_MEM			0
+
+enum mx23_lradc_irqs {
+	MX23_LRADC_TS_IRQ = 0,
+	MX23_LRADC_CH0_IRQ,
+	MX23_LRADC_CH1_IRQ,
+	MX23_LRADC_CH2_IRQ,
+	MX23_LRADC_CH3_IRQ,
+	MX23_LRADC_CH4_IRQ,
+	MX23_LRADC_CH5_IRQ,
+	MX23_LRADC_CH6_IRQ,
+	MX23_LRADC_CH7_IRQ,
+};
+
+enum mx28_lradc_irqs {
+	MX28_LRADC_TS_IRQ = 0,
+	MX28_LRADC_TRESH0_IRQ,
+	MX28_LRADC_TRESH1_IRQ,
+	MX28_LRADC_CH0_IRQ,
+	MX28_LRADC_CH1_IRQ,
+	MX28_LRADC_CH2_IRQ,
+	MX28_LRADC_CH3_IRQ,
+	MX28_LRADC_CH4_IRQ,
+	MX28_LRADC_CH5_IRQ,
+	MX28_LRADC_CH6_IRQ,
+	MX28_LRADC_CH7_IRQ,
+	MX28_LRADC_BUTTON0_IRQ,
+	MX28_LRADC_BUTTON1_IRQ,
+};
+
+static struct resource mx23_adc_resources[] = {
+	DEFINE_RES_MEM(0x0, 0x0),
+	DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH0_IRQ, "mxs-lradc-channel0"),
+	DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH1_IRQ, "mxs-lradc-channel1"),
+	DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH2_IRQ, "mxs-lradc-channel2"),
+	DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH3_IRQ, "mxs-lradc-channel3"),
+	DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH4_IRQ, "mxs-lradc-channel4"),
+	DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH5_IRQ, "mxs-lradc-channel5"),
+};
+
+static struct resource mx23_touchscreen_resources[] = {
+	DEFINE_RES_MEM(0x0, 0x0),
+	DEFINE_RES_IRQ_NAMED(MX23_LRADC_TS_IRQ, "mxs-lradc-touchscreen"),
+	DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH6_IRQ, "mxs-lradc-channel6"),
+	DEFINE_RES_IRQ_NAMED(MX23_LRADC_CH7_IRQ, "mxs-lradc-channel7"),
+};
+
+static struct resource mx28_adc_resources[] = {
+	DEFINE_RES_MEM(0x0, 0x0),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_TRESH0_IRQ, "mxs-lradc-thresh0"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_TRESH1_IRQ, "mxs-lradc-thresh1"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH0_IRQ, "mxs-lradc-channel0"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH1_IRQ, "mxs-lradc-channel1"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH2_IRQ, "mxs-lradc-channel2"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH3_IRQ, "mxs-lradc-channel3"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH4_IRQ, "mxs-lradc-channel4"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH5_IRQ, "mxs-lradc-channel5"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_BUTTON0_IRQ, "mxs-lradc-button0"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_BUTTON1_IRQ, "mxs-lradc-button1"),
+};
+
+static struct resource mx28_touchscreen_resources[] = {
+	DEFINE_RES_MEM(0x0, 0x0),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_TS_IRQ, "mxs-lradc-touchscreen"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH6_IRQ, "mxs-lradc-channel6"),
+	DEFINE_RES_IRQ_NAMED(MX28_LRADC_CH7_IRQ, "mxs-lradc-channel7"),
+};
+
+static struct mfd_cell mx23_cells[] = {
+	{
+		.name = "mxs-lradc-adc",
+		.resources = mx23_adc_resources,
+		.num_resources = ARRAY_SIZE(mx23_adc_resources),
+	},
+	{
+		.name = "mxs-lradc-ts",
+		.resources = mx23_touchscreen_resources,
+		.num_resources = ARRAY_SIZE(mx23_touchscreen_resources),
+	},
+};
+
+static struct mfd_cell mx28_cells[] = {
+	{
+		.name = "mxs-lradc-adc",
+		.resources = mx28_adc_resources,
+		.num_resources = ARRAY_SIZE(mx28_adc_resources),
+	},
+	{
+		.name = "mxs-lradc-ts",
+		.resources = mx28_touchscreen_resources,
+		.num_resources = ARRAY_SIZE(mx28_touchscreen_resources),
+	}
+};
+
+static const struct of_device_id mxs_lradc_dt_ids[] = {
+	{ .compatible = "fsl,imx23-lradc", .data = (void *)IMX23_LRADC, },
+	{ .compatible = "fsl,imx28-lradc", .data = (void *)IMX28_LRADC, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids);
+
+static int mxs_lradc_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct mxs_lradc *lradc;
+	struct mfd_cell *cells = NULL;
+	struct resource *res;
+	int ret = 0;
+	u32 ts_wires = 0;
+
+	lradc = devm_kzalloc(&pdev->dev, sizeof(*lradc), GFP_KERNEL);
+	if (!lradc)
+		return -ENOMEM;
+
+	of_id = of_match_device(mxs_lradc_dt_ids, &pdev->dev);
+	if (!of_id)
+		return -EINVAL;
+
+	lradc->soc = (enum mxs_lradc_id)of_id->data;
+
+	lradc->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(lradc->clk)) {
+		dev_err(dev, "Failed to get the delay unit clock\n");
+		return PTR_ERR(lradc->clk);
+	}
+
+	ret = clk_prepare_enable(lradc->clk);
+	if (ret) {
+		dev_err(dev, "Failed to enable the delay unit clock\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(node, "fsl,lradc-touchscreen-wires",
+					 &ts_wires);
+
+	if (!ret) {
+		lradc->buffer_vchans = BUFFER_VCHANS_LIMITED;
+
+		switch (ts_wires) {
+		case 4:
+			lradc->touchscreen_wire = MXS_LRADC_TOUCHSCREEN_4WIRE;
+			break;
+		case 5:
+			if (lradc->soc == IMX28_LRADC) {
+				lradc->touchscreen_wire =
+					MXS_LRADC_TOUCHSCREEN_5WIRE;
+				break;
+			}
+			/* fall through to an error message for i.MX23 */
+		default:
+			dev_err(&pdev->dev,
+				"Unsupported number of touchscreen wires (%d)\n"
+				, ts_wires);
+			ret = -EINVAL;
+			goto err_clk;
+		}
+	} else {
+		lradc->buffer_vchans = BUFFER_VCHANS_ALL;
+	}
+
+	platform_set_drvdata(pdev, lradc);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOMEM;
+
+	switch (lradc->soc) {
+	case IMX23_LRADC:
+		mx23_adc_resources[RES_MEM] = *res;
+		mx23_touchscreen_resources[RES_MEM] = *res;
+		cells = mx23_cells;
+		break;
+	case IMX28_LRADC:
+		mx28_adc_resources[RES_MEM] = *res;
+		mx28_touchscreen_resources[RES_MEM] = *res;
+		cells = mx28_cells;
+		break;
+	default:
+		dev_err(dev, "Unsupported SoC\n");
+		ret = -ENODEV;
+		goto err_clk;
+	}
+
+	ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+				   &cells[ADC_CELL], 1, NULL, 0, NULL);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add the ADC subdevice\n");
+		goto err_clk;
+	}
+
+	if (!lradc->touchscreen_wire)
+		return 0;
+
+	ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+				   &cells[TSC_CELL], 1, NULL, 0, NULL);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Failed to add the touchscreen subdevice\n");
+		goto err_clk;
+	}
+
+	return 0;
+
+err_clk:
+	clk_disable_unprepare(lradc->clk);
+
+	return ret;
+}
+
+static int mxs_lradc_remove(struct platform_device *pdev)
+{
+	struct mxs_lradc *lradc = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(lradc->clk);
+
+	return 0;
+}
+
+static struct platform_driver mxs_lradc_driver = {
+	.driver = {
+		.name = "mxs-lradc",
+		.of_match_table = mxs_lradc_dt_ids,
+	},
+	.probe = mxs_lradc_probe,
+	.remove = mxs_lradc_remove,
+};
+module_platform_driver(mxs_lradc_driver);
+
+MODULE_AUTHOR("Ksenija Stanojevic <ksenija.stanojevic@gmail.com>");
+MODULE_DESCRIPTION("Freescale i.MX23/i.MX28 LRADC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxs-lradc");
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c
index 1aa74c4c3ced..6f5300b0eb31 100644
--- a/drivers/mfd/omap-usb-tll.c
+++ b/drivers/mfd/omap-usb-tll.c
@@ -373,12 +373,13 @@ int omap_tll_init(struct usbhs_omap_platform_data *pdata)
 			} else if (pdata->port_mode[i] ==
 					OMAP_EHCI_PORT_MODE_TLL) {
 				/*
-				 * Disable AutoIdle, BitStuffing
-				 * and use SDR Mode
+				 * Disable UTMI AutoIdle, BitStuffing
+				 * and use SDR Mode. Enable ULPI AutoIdle.
 				 */
 				reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE
-					| OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
 					| OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE);
+				reg |= OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF;
+				reg |= OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE;
 			} else if (pdata->port_mode[i] ==
 					OMAP_EHCI_PORT_MODE_HSIC) {
 				/*
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c
index ee9e9ea10444..9103affedcbc 100644
--- a/drivers/mfd/palmas.c
+++ b/drivers/mfd/palmas.c
@@ -430,6 +430,20 @@ static void palmas_power_off(void)
 {
 	unsigned int addr;
 	int ret, slave;
+	struct device_node *np = palmas_dev->dev->of_node;
+
+	if (of_property_read_bool(np, "ti,palmas-override-powerhold")) {
+		addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
+					  PALMAS_PRIMARY_SECONDARY_PAD2);
+		slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
+
+		ret = regmap_update_bits(palmas_dev->regmap[slave], addr,
+				PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK, 0);
+		if (ret)
+			dev_err(palmas_dev->dev,
+				"Unable to write PRIMARY_SECONDARY_PAD2 %d\n",
+				ret);
+	}
 
 	slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
 	addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL);
@@ -567,7 +581,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
 			PALMAS_POLARITY_CTRL, PALMAS_POLARITY_CTRL_INT_POLARITY,
 			reg);
 	if (ret < 0) {
-		dev_err(palmas->dev, "POLARITY_CTRL updat failed: %d\n", ret);
+		dev_err(palmas->dev, "POLARITY_CTRL update failed: %d\n", ret);
 		goto err_i2c;
 	}
 
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
index 98029ee0959e..850590aac008 100644
--- a/drivers/mfd/rtsx_pcr.c
+++ b/drivers/mfd/rtsx_pcr.c
@@ -927,7 +927,7 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
 
 static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr)
 {
-	dev_info(&(pcr->pci->dev), "%s: pcr->msi_en = %d, pci->irq = %d\n",
+	pcr_dbg(pcr, "%s: pcr->msi_en = %d, pci->irq = %d\n",
 			__func__, pcr->msi_en, pcr->pci->irq);
 
 	if (request_irq(pcr->pci->irq, rtsx_pci_isr,
diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c
index 9292202039ee..3aeafa228baf 100644
--- a/drivers/mfd/sta2x11-mfd.c
+++ b/drivers/mfd/sta2x11-mfd.c
@@ -60,8 +60,8 @@ static struct sta2x11_mfd *sta2x11_mfd_find(struct pci_dev *pdev)
 	struct sta2x11_mfd *mfd;
 
 	if (!pdev && !list_empty(&sta2x11_mfd_list)) {
-		pr_warning("%s: Unspecified device, "
-			    "using first instance\n", __func__);
+		pr_warn("%s: Unspecified device, using first instance\n",
+			__func__);
 		return list_entry(sta2x11_mfd_list.next,
 				  struct sta2x11_mfd, list);
 	}
diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c
index 41bd9017f3d0..2182f00db101 100644
--- a/drivers/mfd/stm32-timers.c
+++ b/drivers/mfd/stm32-timers.c
@@ -15,7 +15,7 @@ static const struct regmap_config stm32_timers_regmap_cfg = {
 	.reg_bits = 32,
 	.val_bits = 32,
 	.reg_stride = sizeof(u32),
-	.max_register = 0x400,
+	.max_register = 0x3fc,
 };
 
 static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
@@ -61,6 +61,13 @@ static int stm32_timers_probe(struct platform_device *pdev)
 	return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
 }
 
+static int stm32_timers_remove(struct platform_device *pdev)
+{
+	of_platform_depopulate(&pdev->dev);
+
+	return 0;
+}
+
 static const struct of_device_id stm32_timers_of_match[] = {
 	{ .compatible = "st,stm32-timers", },
 	{ /* end node */ },
@@ -69,6 +76,7 @@ MODULE_DEVICE_TABLE(of, stm32_timers_of_match);
 
 static struct platform_driver stm32_timers_driver = {
 	.probe = stm32_timers_probe,
+	.remove = stm32_timers_remove,
 	.driver	= {
 		.name = "stm32-timers",
 		.of_match_table = stm32_timers_of_match,
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index b0c7bcdaf5df..566caca4efd8 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -568,6 +568,8 @@ static const u8 stmpe1600_regs[] = {
 	[STMPE_IDX_GPMR_CSB]	= STMPE1600_REG_GPMR_MSB,
 	[STMPE_IDX_GPSR_LSB]	= STMPE1600_REG_GPSR_LSB,
 	[STMPE_IDX_GPSR_CSB]	= STMPE1600_REG_GPSR_MSB,
+	[STMPE_IDX_GPCR_LSB]	= STMPE1600_REG_GPSR_LSB,
+	[STMPE_IDX_GPCR_CSB]	= STMPE1600_REG_GPSR_MSB,
 	[STMPE_IDX_GPDR_LSB]	= STMPE1600_REG_GPDR_LSB,
 	[STMPE_IDX_GPDR_CSB]	= STMPE1600_REG_GPDR_MSB,
 	[STMPE_IDX_IEGPIOR_LSB]	= STMPE1600_REG_IEGPIOR_LSB,
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 94bd89cb1f06..22c811396edc 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -69,7 +69,7 @@ static const struct resource t7l66xb_mmc_resources[] = {
 struct t7l66xb {
 	void __iomem		*scr;
 	/* Lock to protect registers requiring read/modify/write ops. */
-	spinlock_t		lock;
+	raw_spinlock_t		lock;
 
 	struct resource		rscr;
 	struct clk		*clk48m;
@@ -89,13 +89,13 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
 
 	clk_prepare_enable(t7l66xb->clk32k);
 
-	spin_lock_irqsave(&t7l66xb->lock, flags);
+	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
 
 	dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
 	dev_ctl |= SCR_DEV_CTL_MMC;
 	tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
 
-	spin_unlock_irqrestore(&t7l66xb->lock, flags);
+	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
 
 	tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
 		t7l66xb_mmc_resources[0].start & 0xfffe);
@@ -110,13 +110,13 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
 	unsigned long flags;
 	u8 dev_ctl;
 
-	spin_lock_irqsave(&t7l66xb->lock, flags);
+	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
 
 	dev_ctl = tmio_ioread8(t7l66xb->scr + SCR_DEV_CTL);
 	dev_ctl &= ~SCR_DEV_CTL_MMC;
 	tmio_iowrite8(dev_ctl, t7l66xb->scr + SCR_DEV_CTL);
 
-	spin_unlock_irqrestore(&t7l66xb->lock, flags);
+	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
 
 	clk_disable_unprepare(t7l66xb->clk32k);
 
@@ -206,11 +206,11 @@ static void t7l66xb_irq_mask(struct irq_data *data)
 	unsigned long			flags;
 	u8 imr;
 
-	spin_lock_irqsave(&t7l66xb->lock, flags);
+	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
 	imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
 	imr |= 1 << (data->irq - t7l66xb->irq_base);
 	tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
-	spin_unlock_irqrestore(&t7l66xb->lock, flags);
+	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
 }
 
 static void t7l66xb_irq_unmask(struct irq_data *data)
@@ -219,11 +219,11 @@ static void t7l66xb_irq_unmask(struct irq_data *data)
 	unsigned long flags;
 	u8 imr;
 
-	spin_lock_irqsave(&t7l66xb->lock, flags);
+	raw_spin_lock_irqsave(&t7l66xb->lock, flags);
 	imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
 	imr &= ~(1 << (data->irq - t7l66xb->irq_base));
 	tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
-	spin_unlock_irqrestore(&t7l66xb->lock, flags);
+	raw_spin_unlock_irqrestore(&t7l66xb->lock, flags);
 }
 
 static struct irq_chip t7l66xb_chip = {
@@ -321,7 +321,7 @@ static int t7l66xb_probe(struct platform_device *dev)
 	if (!t7l66xb)
 		return -ENOMEM;
 
-	spin_lock_init(&t7l66xb->lock);
+	raw_spin_lock_init(&t7l66xb->lock);
 
 	platform_set_drvdata(dev, t7l66xb);
 
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index d42d322ac7ca..d16e71bd9482 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -95,7 +95,7 @@ struct tc6393xb {
 
 	struct clk		*clk; /* 3,6 Mhz */
 
-	spinlock_t		lock; /* protects RMW cycles */
+	raw_spinlock_t		lock; /* protects RMW cycles */
 
 	struct {
 		u8		fer;
@@ -126,13 +126,13 @@ static int tc6393xb_nand_enable(struct platform_device *nand)
 	struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
 	unsigned long flags;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	/* SMD buffer on */
 	dev_dbg(&dev->dev, "SMD buffer on\n");
 	tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1));
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 
 	return 0;
 }
@@ -226,7 +226,7 @@ static int tc6393xb_ohci_enable(struct platform_device *dev)
 	u16 ccr;
 	u8 fer;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
 	ccr |= SCR_CCR_USBCK;
@@ -236,7 +236,7 @@ static int tc6393xb_ohci_enable(struct platform_device *dev)
 	fer |= SCR_FER_USBEN;
 	tmio_iowrite8(fer, tc6393xb->scr + SCR_FER);
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 
 	return 0;
 }
@@ -248,7 +248,7 @@ static int tc6393xb_ohci_disable(struct platform_device *dev)
 	u16 ccr;
 	u8 fer;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	fer = tmio_ioread8(tc6393xb->scr + SCR_FER);
 	fer &= ~SCR_FER_USBEN;
@@ -258,7 +258,7 @@ static int tc6393xb_ohci_disable(struct platform_device *dev)
 	ccr &= ~SCR_CCR_USBCK;
 	tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 
 	return 0;
 }
@@ -280,14 +280,14 @@ static int tc6393xb_fb_enable(struct platform_device *dev)
 	unsigned long flags;
 	u16 ccr;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
 	ccr &= ~SCR_CCR_MCLK_MASK;
 	ccr |= SCR_CCR_MCLK_48;
 	tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 
 	return 0;
 }
@@ -298,14 +298,14 @@ static int tc6393xb_fb_disable(struct platform_device *dev)
 	unsigned long flags;
 	u16 ccr;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	ccr = tmio_ioread16(tc6393xb->scr + SCR_CCR);
 	ccr &= ~SCR_CCR_MCLK_MASK;
 	ccr |= SCR_CCR_MCLK_OFF;
 	tmio_iowrite16(ccr, tc6393xb->scr + SCR_CCR);
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 
 	return 0;
 }
@@ -317,7 +317,7 @@ int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
 	u8 fer;
 	unsigned long flags;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	fer = ioread8(tc6393xb->scr + SCR_FER);
 	if (on)
@@ -326,7 +326,7 @@ int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
 		fer &= ~SCR_FER_SLCDEN;
 	iowrite8(fer, tc6393xb->scr + SCR_FER);
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 
 	return 0;
 }
@@ -338,12 +338,12 @@ int tc6393xb_lcd_mode(struct platform_device *fb,
 	struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
 	unsigned long flags;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	iowrite16(mode->pixclock, tc6393xb->scr + SCR_PLL1CR + 0);
 	iowrite16(mode->pixclock >> 16, tc6393xb->scr + SCR_PLL1CR + 2);
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 
 	return 0;
 }
@@ -462,11 +462,11 @@ static void tc6393xb_gpio_set(struct gpio_chip *chip,
 	struct tc6393xb *tc6393xb = gpiochip_get_data(chip);
 	unsigned long flags;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	__tc6393xb_gpio_set(chip, offset, value);
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 }
 
 static int tc6393xb_gpio_direction_input(struct gpio_chip *chip,
@@ -476,13 +476,13 @@ static int tc6393xb_gpio_direction_input(struct gpio_chip *chip,
 	unsigned long flags;
 	u8 doecr;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	doecr = tmio_ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
 	doecr &= ~TC_GPIO_BIT(offset);
 	tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 
 	return 0;
 }
@@ -494,7 +494,7 @@ static int tc6393xb_gpio_direction_output(struct gpio_chip *chip,
 	unsigned long flags;
 	u8 doecr;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 
 	__tc6393xb_gpio_set(chip, offset, value);
 
@@ -502,7 +502,7 @@ static int tc6393xb_gpio_direction_output(struct gpio_chip *chip,
 	doecr |= TC_GPIO_BIT(offset);
 	tmio_iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
 
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 
 	return 0;
 }
@@ -548,11 +548,11 @@ static void tc6393xb_irq_mask(struct irq_data *data)
 	unsigned long flags;
 	u8 imr;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 	imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
 	imr |= 1 << (data->irq - tc6393xb->irq_base);
 	tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 }
 
 static void tc6393xb_irq_unmask(struct irq_data *data)
@@ -561,11 +561,11 @@ static void tc6393xb_irq_unmask(struct irq_data *data)
 	unsigned long flags;
 	u8 imr;
 
-	spin_lock_irqsave(&tc6393xb->lock, flags);
+	raw_spin_lock_irqsave(&tc6393xb->lock, flags);
 	imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
 	imr &= ~(1 << (data->irq - tc6393xb->irq_base));
 	tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
-	spin_unlock_irqrestore(&tc6393xb->lock, flags);
+	raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
 }
 
 static struct irq_chip tc6393xb_chip = {
@@ -628,7 +628,7 @@ static int tc6393xb_probe(struct platform_device *dev)
 		goto err_kzalloc;
 	}
 
-	spin_lock_init(&tc6393xb->lock);
+	raw_spin_lock_init(&tc6393xb->lock);
 
 	platform_set_drvdata(dev, tc6393xb);
 
diff --git a/drivers/mfd/ti-lmu.c b/drivers/mfd/ti-lmu.c
new file mode 100644
index 000000000000..cfb411cde51c
--- /dev/null
+++ b/drivers/mfd/ti-lmu.c
@@ -0,0 +1,259 @@
+/*
+ * TI LMU (Lighting Management Unit) Core Driver
+ *
+ * Copyright 2017 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@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 <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+
+struct ti_lmu_data {
+	struct mfd_cell *cells;
+	int num_cells;
+	unsigned int max_register;
+};
+
+static int ti_lmu_enable_hw(struct ti_lmu *lmu, enum ti_lmu_id id)
+{
+	int ret;
+
+	if (gpio_is_valid(lmu->en_gpio)) {
+		ret = devm_gpio_request_one(lmu->dev, lmu->en_gpio,
+					    GPIOF_OUT_INIT_HIGH, "lmu_hwen");
+		if (ret) {
+			dev_err(lmu->dev, "Can not request enable GPIO: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	/* Delay about 1ms after HW enable pin control */
+	usleep_range(1000, 1500);
+
+	/* LM3631 has additional power up sequence - enable LCD_EN bit. */
+	if (id == LM3631) {
+		return regmap_update_bits(lmu->regmap, LM3631_REG_DEVCTRL,
+					  LM3631_LCD_EN_MASK,
+					  LM3631_LCD_EN_MASK);
+	}
+
+	return 0;
+}
+
+static void ti_lmu_disable_hw(struct ti_lmu *lmu)
+{
+	if (gpio_is_valid(lmu->en_gpio))
+		gpio_set_value(lmu->en_gpio, 0);
+}
+
+static struct mfd_cell lm3532_devices[] = {
+	{
+		.name          = "ti-lmu-backlight",
+		.id            = LM3532,
+		.of_compatible = "ti,lm3532-backlight",
+	},
+};
+
+#define LM363X_REGULATOR(_id)			\
+{						\
+	.name          = "lm363x-regulator",	\
+	.id            = _id,			\
+	.of_compatible = "ti,lm363x-regulator",	\
+}						\
+
+static struct mfd_cell lm3631_devices[] = {
+	LM363X_REGULATOR(LM3631_BOOST),
+	LM363X_REGULATOR(LM3631_LDO_CONT),
+	LM363X_REGULATOR(LM3631_LDO_OREF),
+	LM363X_REGULATOR(LM3631_LDO_POS),
+	LM363X_REGULATOR(LM3631_LDO_NEG),
+	{
+		.name          = "ti-lmu-backlight",
+		.id            = LM3631,
+		.of_compatible = "ti,lm3631-backlight",
+	},
+};
+
+static struct mfd_cell lm3632_devices[] = {
+	LM363X_REGULATOR(LM3632_BOOST),
+	LM363X_REGULATOR(LM3632_LDO_POS),
+	LM363X_REGULATOR(LM3632_LDO_NEG),
+	{
+		.name          = "ti-lmu-backlight",
+		.id            = LM3632,
+		.of_compatible = "ti,lm3632-backlight",
+	},
+};
+
+static struct mfd_cell lm3633_devices[] = {
+	{
+		.name          = "ti-lmu-backlight",
+		.id            = LM3633,
+		.of_compatible = "ti,lm3633-backlight",
+	},
+	{
+		.name          = "lm3633-leds",
+		.of_compatible = "ti,lm3633-leds",
+	},
+	/* Monitoring driver for open/short circuit detection */
+	{
+		.name          = "ti-lmu-fault-monitor",
+		.id            = LM3633,
+		.of_compatible = "ti,lm3633-fault-monitor",
+	},
+};
+
+static struct mfd_cell lm3695_devices[] = {
+	{
+		.name          = "ti-lmu-backlight",
+		.id            = LM3695,
+		.of_compatible = "ti,lm3695-backlight",
+	},
+};
+
+static struct mfd_cell lm3697_devices[] = {
+	{
+		.name          = "ti-lmu-backlight",
+		.id            = LM3697,
+		.of_compatible = "ti,lm3697-backlight",
+	},
+	/* Monitoring driver for open/short circuit detection */
+	{
+		.name          = "ti-lmu-fault-monitor",
+		.id            = LM3697,
+		.of_compatible = "ti,lm3697-fault-monitor",
+	},
+};
+
+#define TI_LMU_DATA(chip, max_reg)		\
+static const struct ti_lmu_data chip##_data =	\
+{						\
+	.cells = chip##_devices,		\
+	.num_cells = ARRAY_SIZE(chip##_devices),\
+	.max_register = max_reg,		\
+}						\
+
+TI_LMU_DATA(lm3532, LM3532_MAX_REG);
+TI_LMU_DATA(lm3631, LM3631_MAX_REG);
+TI_LMU_DATA(lm3632, LM3632_MAX_REG);
+TI_LMU_DATA(lm3633, LM3633_MAX_REG);
+TI_LMU_DATA(lm3695, LM3695_MAX_REG);
+TI_LMU_DATA(lm3697, LM3697_MAX_REG);
+
+static const struct of_device_id ti_lmu_of_match[] = {
+	{ .compatible = "ti,lm3532", .data = &lm3532_data },
+	{ .compatible = "ti,lm3631", .data = &lm3631_data },
+	{ .compatible = "ti,lm3632", .data = &lm3632_data },
+	{ .compatible = "ti,lm3633", .data = &lm3633_data },
+	{ .compatible = "ti,lm3695", .data = &lm3695_data },
+	{ .compatible = "ti,lm3697", .data = &lm3697_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ti_lmu_of_match);
+
+static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+	struct device *dev = &cl->dev;
+	const struct of_device_id *match;
+	const struct ti_lmu_data *data;
+	struct regmap_config regmap_cfg;
+	struct ti_lmu *lmu;
+	int ret;
+
+	match = of_match_device(ti_lmu_of_match, dev);
+	if (!match)
+		return -ENODEV;
+	/*
+	 * Get device specific data from of_match table.
+	 * This data is defined by using TI_LMU_DATA() macro.
+	 */
+	data = (struct ti_lmu_data *)match->data;
+
+	lmu = devm_kzalloc(dev, sizeof(*lmu), GFP_KERNEL);
+	if (!lmu)
+		return -ENOMEM;
+
+	lmu->dev = &cl->dev;
+
+	/* Setup regmap */
+	memset(&regmap_cfg, 0, sizeof(struct regmap_config));
+	regmap_cfg.reg_bits = 8;
+	regmap_cfg.val_bits = 8;
+	regmap_cfg.name = id->name;
+	regmap_cfg.max_register = data->max_register;
+
+	lmu->regmap = devm_regmap_init_i2c(cl, &regmap_cfg);
+	if (IS_ERR(lmu->regmap))
+		return PTR_ERR(lmu->regmap);
+
+	/* HW enable pin control and additional power up sequence if required */
+	lmu->en_gpio = of_get_named_gpio(dev->of_node, "enable-gpios", 0);
+	ret = ti_lmu_enable_hw(lmu, id->driver_data);
+	if (ret)
+		return ret;
+
+	/*
+	 * Fault circuit(open/short) can be detected by ti-lmu-fault-monitor.
+	 * After fault detection is done, some devices should re-initialize
+	 * configuration. The notifier enables such kind of handling.
+	 */
+	BLOCKING_INIT_NOTIFIER_HEAD(&lmu->notifier);
+
+	i2c_set_clientdata(cl, lmu);
+
+	return mfd_add_devices(lmu->dev, 0, data->cells,
+			       data->num_cells, NULL, 0, NULL);
+}
+
+static int ti_lmu_remove(struct i2c_client *cl)
+{
+	struct ti_lmu *lmu = i2c_get_clientdata(cl);
+
+	ti_lmu_disable_hw(lmu);
+	mfd_remove_devices(lmu->dev);
+	return 0;
+}
+
+static const struct i2c_device_id ti_lmu_ids[] = {
+	{ "lm3532", LM3532 },
+	{ "lm3631", LM3631 },
+	{ "lm3632", LM3632 },
+	{ "lm3633", LM3633 },
+	{ "lm3695", LM3695 },
+	{ "lm3697", LM3697 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ti_lmu_ids);
+
+static struct i2c_driver ti_lmu_driver = {
+	.probe = ti_lmu_probe,
+	.remove = ti_lmu_remove,
+	.driver = {
+		.name = "ti-lmu",
+		.of_match_table = ti_lmu_of_match,
+	},
+	.id_table = ti_lmu_ids,
+};
+
+module_i2c_driver(ti_lmu_driver);
+
+MODULE_DESCRIPTION("TI LMU MFD Core Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c
index 4aeba9b6942a..3bd75061f777 100644
--- a/drivers/mfd/tps65912-spi.c
+++ b/drivers/mfd/tps65912-spi.c
@@ -49,9 +49,9 @@ static int tps65912_spi_probe(struct spi_device *spi)
 	return tps65912_device_init(tps);
 }
 
-static int tps65912_spi_remove(struct spi_device *client)
+static int tps65912_spi_remove(struct spi_device *spi)
 {
-	struct tps65912 *tps = spi_get_drvdata(client);
+	struct tps65912 *tps = spi_get_drvdata(spi);
 
 	return tps65912_device_exit(tps);
 }
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 1beb722f6080..f4b2c29d77e3 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -502,9 +502,7 @@ static int load_twl4030_script(const struct twl4030_power_data *pdata,
 	}
 	if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
 		if (!order)
-			pr_warning("TWL4030: Bad order of scripts (sleep "\
-					"script before wakeup) Leads to boot"\
-					"failure on some boards\n");
+			pr_warn("TWL4030: Bad order of scripts (sleep script before wakeup) Leads to boot failure on some boards\n");
 		err = twl4030_config_sleep_sequence(address);
 	}
 out:
@@ -701,6 +699,7 @@ static struct twl4030_ins omap3_wrst_seq[] = {
 	TWL_RESOURCE_RESET(RES_MAIN_REF),
 	TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2),
 	TWL_RESOURCE_RESET(RES_VUSB_3V1),
+	TWL_RESOURCE_RESET(RES_VMMC1),
 	TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1),
 	TWL_RESOURCE_GROUP_RESET(RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0),
 	TWL_RESOURCE_ON(RES_RESET),
@@ -929,8 +928,7 @@ static int twl4030_power_probe(struct platform_device *pdev)
 		err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
 				      TWL4030_PM_MASTER_CFG_P123_TRANSITION);
 		if (err) {
-			pr_warning("TWL4030 Unable to read registers\n");
-
+			pr_warn("TWL4030 Unable to read registers\n");
 		} else if (!(val & SEQ_OFFSYNC)) {
 			val |= SEQ_OFFSYNC;
 			err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val,
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 3e0e99ec5836..13a4c1190dca 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -19,6 +19,8 @@
 #include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mfd/wm831x/core.h>
 #include <linux/mfd/wm831x/pdata.h>
@@ -1613,12 +1615,24 @@ struct regmap_config wm831x_regmap_config = {
 };
 EXPORT_SYMBOL_GPL(wm831x_regmap_config);
 
+const struct of_device_id wm831x_of_match[] = {
+	{ .compatible = "wlf,wm8310", .data = (void *)WM8310 },
+	{ .compatible = "wlf,wm8311", .data = (void *)WM8311 },
+	{ .compatible = "wlf,wm8312", .data = (void *)WM8312 },
+	{ .compatible = "wlf,wm8320", .data = (void *)WM8320 },
+	{ .compatible = "wlf,wm8321", .data = (void *)WM8321 },
+	{ .compatible = "wlf,wm8325", .data = (void *)WM8325 },
+	{ .compatible = "wlf,wm8326", .data = (void *)WM8326 },
+	{ },
+};
+EXPORT_SYMBOL_GPL(wm831x_of_match);
+
 /*
  * Instantiate the generic non-control parts of the device.
  */
-int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
+int wm831x_device_init(struct wm831x *wm831x, int irq)
 {
-	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
+	struct wm831x_pdata *pdata = &wm831x->pdata;
 	int rev, wm831x_num;
 	enum wm831x_parent parent;
 	int ret, i;
@@ -1627,8 +1641,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 	mutex_init(&wm831x->key_lock);
 	dev_set_drvdata(wm831x->dev, wm831x);
 
-	if (pdata)
-		wm831x->soft_shutdown = pdata->soft_shutdown;
+	wm831x->soft_shutdown = pdata->soft_shutdown;
 
 	ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
 	if (ret < 0) {
@@ -1663,7 +1676,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 	 */
 	if (ret == 0) {
 		dev_info(wm831x->dev, "Device is an engineering sample\n");
-		ret = id;
+		ret = wm831x->type;
 	}
 
 	switch (ret) {
@@ -1736,9 +1749,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 	/* This will need revisiting in future but is OK for all
 	 * current parts.
 	 */
-	if (parent != id)
-		dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
-			 id);
+	if (parent != wm831x->type)
+		dev_warn(wm831x->dev, "Device was registered as a WM%x\n",
+			 wm831x->type);
 
 	/* Bootstrap the user key */
 	ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c
index 824bcbaa9624..781af060f32d 100644
--- a/drivers/mfd/wm831x-i2c.c
+++ b/drivers/mfd/wm831x-i2c.c
@@ -19,6 +19,8 @@
 #include <linux/mfd/core.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/regmap.h>
 
 #include <linux/mfd/wm831x/core.h>
@@ -27,15 +29,26 @@
 static int wm831x_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
+	struct wm831x_pdata *pdata = dev_get_platdata(&i2c->dev);
+	const struct of_device_id *of_id;
 	struct wm831x *wm831x;
+	enum wm831x_parent type;
 	int ret;
 
+	if (i2c->dev.of_node) {
+		of_id = of_match_device(wm831x_of_match, &i2c->dev);
+		type = (enum wm831x_parent)of_id->data;
+	} else {
+		type = (enum wm831x_parent)id->driver_data;
+	}
+
 	wm831x = devm_kzalloc(&i2c->dev, sizeof(struct wm831x), GFP_KERNEL);
 	if (wm831x == NULL)
 		return -ENOMEM;
 
 	i2c_set_clientdata(i2c, wm831x);
 	wm831x->dev = &i2c->dev;
+	wm831x->type = type;
 
 	wm831x->regmap = devm_regmap_init_i2c(i2c, &wm831x_regmap_config);
 	if (IS_ERR(wm831x->regmap)) {
@@ -45,7 +58,10 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
 		return ret;
 	}
 
-	return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
+	if (pdata)
+		memcpy(&wm831x->pdata, pdata, sizeof(*pdata));
+
+	return wm831x_device_init(wm831x, i2c->irq);
 }
 
 static int wm831x_i2c_remove(struct i2c_client *i2c)
@@ -94,6 +110,7 @@ static struct i2c_driver wm831x_i2c_driver = {
 	.driver = {
 		.name = "wm831x",
 		.pm = &wm831x_pm_ops,
+		.of_match_table = of_match_ptr(wm831x_of_match),
 	},
 	.probe = wm831x_i2c_probe,
 	.remove = wm831x_i2c_remove,
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index dfea8b9c2fe6..c01239a600db 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -564,7 +564,7 @@ static const struct irq_domain_ops wm831x_irq_domain_ops = {
 
 int wm831x_irq_init(struct wm831x *wm831x, int irq)
 {
-	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
+	struct wm831x_pdata *pdata = &wm831x->pdata;
 	struct irq_domain *domain;
 	int i, ret, irq_base;
 
@@ -579,7 +579,7 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
 	}
 
 	/* Try to dynamically allocate IRQs if no base is specified */
-	if (pdata && pdata->irq_base) {
+	if (pdata->irq_base) {
 		irq_base = irq_alloc_descs(pdata->irq_base, 0,
 					   WM831X_NUM_IRQS, 0);
 		if (irq_base < 0) {
@@ -608,7 +608,7 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
 		return -EINVAL;
 	}
 
-	if (pdata && pdata->irq_cmos)
+	if (pdata->irq_cmos)
 		i = 0;
 	else
 		i = WM831X_IRQ_OD;
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 80482aeb246a..c332e2885b26 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -14,6 +14,8 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/pm.h>
 #include <linux/spi/spi.h>
 #include <linux/regmap.h>
@@ -23,12 +25,19 @@
 
 static int wm831x_spi_probe(struct spi_device *spi)
 {
+	struct wm831x_pdata *pdata = dev_get_platdata(&spi->dev);
 	const struct spi_device_id *id = spi_get_device_id(spi);
+	const struct of_device_id *of_id;
 	struct wm831x *wm831x;
 	enum wm831x_parent type;
 	int ret;
 
-	type = (enum wm831x_parent)id->driver_data;
+	if (spi->dev.of_node) {
+		of_id = of_match_device(wm831x_of_match, &spi->dev);
+		type = (enum wm831x_parent)of_id->data;
+	} else {
+		type = (enum wm831x_parent)id->driver_data;
+	}
 
 	wm831x = devm_kzalloc(&spi->dev, sizeof(struct wm831x), GFP_KERNEL);
 	if (wm831x == NULL)
@@ -38,6 +47,7 @@ static int wm831x_spi_probe(struct spi_device *spi)
 
 	spi_set_drvdata(spi, wm831x);
 	wm831x->dev = &spi->dev;
+	wm831x->type = type;
 
 	wm831x->regmap = devm_regmap_init_spi(spi, &wm831x_regmap_config);
 	if (IS_ERR(wm831x->regmap)) {
@@ -47,7 +57,10 @@ static int wm831x_spi_probe(struct spi_device *spi)
 		return ret;
 	}
 
-	return wm831x_device_init(wm831x, type, spi->irq);
+	if (pdata)
+		memcpy(&wm831x->pdata, pdata, sizeof(*pdata));
+
+	return wm831x_device_init(wm831x, spi->irq);
 }
 
 static int wm831x_spi_remove(struct spi_device *spi)
@@ -97,6 +110,7 @@ static struct spi_driver wm831x_spi_driver = {
 	.driver = {
 		.name	= "wm831x",
 		.pm	= &wm831x_spi_pm,
+		.of_match_table = of_match_ptr(wm831x_of_match),
 	},
 	.id_table	= wm831x_spi_ids,
 	.probe		= wm831x_spi_probe,
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index e1bffc9bb194..883fbe7a2466 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1019,7 +1019,7 @@ config INTEL_PMC_IPC
 config INTEL_BXTWC_PMIC_TMU
 	tristate "Intel BXT Whiskey Cove TMU Driver"
 	depends on REGMAP
-	depends on INTEL_SOC_PMIC && INTEL_PMC_IPC
+	depends on INTEL_SOC_PMIC_BXTWC && INTEL_PMC_IPC
 	---help---
 	  Select this driver to use Intel BXT Whiskey Cove PMIC TMU feature.
 	  This driver enables the alarm wakeup functionality in the TMU unit
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 0a16cf4bed39..6871ecc5b951 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -353,7 +353,7 @@ endmenu
 
 config INTEL_BXT_PMIC_THERMAL
 	tristate "Intel Broxton PMIC thermal driver"
-	depends on X86 && INTEL_SOC_PMIC && REGMAP
+	depends on X86 && INTEL_SOC_PMIC_BXTWC && REGMAP
 	help
 	  Select this driver for Intel Broxton PMIC with ADC channels monitoring
 	  system temperature measurements and alerts.