--- /dev/null
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_AMBA_PL08X is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MULTIPLATFORM=y
+CONFIG_ARCH_MULTI_CPU_AUTO=y
+# CONFIG_ARCH_MULTI_V4 is not set
+# CONFIG_ARCH_MULTI_V4T is not set
+CONFIG_ARCH_MULTI_V4_V5=y
+CONFIG_ARCH_MULTI_V5=y
+CONFIG_ARCH_MXS=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y
+# CONFIG_ARM_CPUIDLE is not set
+CONFIG_ARM_CPU_SUSPEND=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_THUMB=y
+CONFIG_ATAGS=y
+CONFIG_AUTO_ZRELADDR=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="console=ttyAMA0,115200 root=/dev/mmcblk0p2 rw rootwait"
+CONFIG_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_COMMON_CLK=y
+CONFIG_COREDUMP=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_ARM926T=y
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_USE_DOMAINS=y
+CONFIG_CRC16=y
+CONFIG_CROSS_MEMORY_ATTACH=y
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_DEV_MXS_DCP is not set
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HW=y
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DMADEVICES=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DTC=y
+CONFIG_EXT4_FS=y
+CONFIG_FEC=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_FSL_PQ_MDIO is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_GENERIC=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_GPIO_MXS=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HZ_FIXED=0
+CONFIG_HZ_PERIODIC=y
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_ALGOPCA=y
+CONFIG_I2C_ALGOPCF=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_MUX=y
+# CONFIG_I2C_MUX_GPIO is not set
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+CONFIG_I2C_MUX_PINCTRL=y
+# CONFIG_I2C_MXS is not set
+CONFIG_IIO=y
+CONFIG_IIO_BUFFER=y
+CONFIG_IIO_KFIFO_BUF=y
+CONFIG_IIO_PERIODIC_RTC_TRIGGER=y
+CONFIG_IIO_SYSFS_TRIGGER=y
+CONFIG_IIO_TRIGGER=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INPUT=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+# CONFIG_ISDN is not set
+CONFIG_JBD2=y
+# CONFIG_LEDS_REGULATOR is not set
+CONFIG_LIBFDT=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_MXS=y
+CONFIG_MODULES_USE_ELF_REL=y
+# CONFIG_MTD_PHYSMAP_OF is not set
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MXS_DMA=y
+# CONFIG_MXS_LRADC is not set
+CONFIG_MXS_POWER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_KUSER_HELPERS=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_PTP_CLASSIFY=y
+CONFIG_NLS=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+# CONFIG_PCI_SYSCALL is not set
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_IMX23=y
+CONFIG_PINCTRL_IMX28=y
+CONFIG_PINCTRL_MXS=y
+# CONFIG_PINCTRL_SINGLE is not set
+# CONFIG_PL330_DMA is not set
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPS=y
+CONFIG_PTP_1588_CLOCK=y
+# CONFIG_RCU_STALL_COMMON is not set
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGMAP_SPI=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_MXS=y
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_STMP is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCSI_DMA is not set
+CONFIG_SERIAL_AMBA_PL010=y
+CONFIG_SERIAL_AMBA_PL010_CONSOLE=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_MXS_AUART=y
+CONFIG_SERIAL_MXS_AUART_CONSOLE=y
+CONFIG_SMSC_PHY=y
+CONFIG_SOC_BUS=y
+CONFIG_SOC_IMX23=y
+CONFIG_SOC_IMX28=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+# CONFIG_SPI_MXS is not set
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+CONFIG_SRCU=y
+CONFIG_STMP_DEVICE=y
+CONFIG_SWIOTLB=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_UID16=y
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+# CONFIG_USB_MXS_PHY is not set
+CONFIG_USB_OTG=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+# CONFIG_VFP is not set
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZONE_DMA_FLAG=0
--- /dev/null
+diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
+index 4091fb0..0fcc158 100644
+--- a/drivers/power/Kconfig
++++ b/drivers/power/Kconfig
+@@ -43,6 +43,14 @@ config MAX8925_POWER
+ Say Y here to enable support for the battery charger in the Maxim
+ MAX8925 PMIC.
+
++config MXS_POWER
++ tristate "Freescale MXS power subsystem support"
++ depends on ARCH_MXS || COMPILE_TEST
++ help
++ Say Y here to enable support for the Freescale i.MX23/i.MX28
++ power subsystem. This is a requirement to get access to on-chip
++ regulators, battery charger and many more.
++
+ config WM831X_BACKUP
+ tristate "WM831X backup battery charger support"
+ depends on MFD_WM831X
+diff --git a/drivers/power/Makefile b/drivers/power/Makefile
+index b7b0181..8edcad7 100644
+--- a/drivers/power/Makefile
++++ b/drivers/power/Makefile
+@@ -10,6 +10,7 @@ obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
+ obj-$(CONFIG_PDA_POWER) += pda_power.o
+ obj-$(CONFIG_APM_POWER) += apm_power.o
+ obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
++obj-$(CONFIG_MXS_POWER) += mxs_power.o
+ obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
+ obj-$(CONFIG_WM831X_POWER) += wm831x_power.o
+ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
+diff --git a/drivers/power/mxs_power.c b/drivers/power/mxs_power.c
+new file mode 100644
+index 0000000..669bfb1
+--- /dev/null
++++ b/drivers/power/mxs_power.c
+@@ -0,0 +1,136 @@
++/*
++ * Freescale MXS power subsystem
++ *
++ * Copyright (C) 2014 Stefan Wahren
++ *
++ * Inspired by imx-bootlets
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/power_supply.h>
++#include <linux/stmp_device.h>
++#include <linux/types.h>
++
++#define BM_POWER_CTRL_POLARITY_VBUSVALID BIT(5)
++#define BM_POWER_CTRL_VBUSVALID_IRQ BIT(4)
++#define BM_POWER_CTRL_ENIRQ_VBUS_VALID BIT(3)
++
++#define HW_POWER_5VCTRL_OFFSET 0x10
++
++#define BM_POWER_5VCTRL_VBUSVALID_THRESH (7 << 8)
++#define BM_POWER_5VCTRL_PWDN_5VBRNOUT BIT(7)
++#define BM_POWER_5VCTRL_ENABLE_LINREG_ILIMIT BIT(6)
++#define BM_POWER_5VCTRL_VBUSVALID_5VDETECT BIT(4)
++
++#define HW_POWER_5VCTRL_VBUSVALID_THRESH_4_40V (5 << 8)
++
++struct mxs_power_data {
++ void __iomem *base_addr;
++ struct power_supply *ac;
++};
++
++static enum power_supply_property mxs_power_ac_props[] = {
++ POWER_SUPPLY_PROP_ONLINE,
++};
++
++static int mxs_power_ac_get_property(struct power_supply *psy,
++ enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ int ret = 0;
++
++ switch (psp) {
++ case POWER_SUPPLY_PROP_ONLINE:
++ val->intval = 1;
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
++static const struct of_device_id of_mxs_power_match[] = {
++ { .compatible = "fsl,imx23-power" },
++ { .compatible = "fsl,imx28-power" },
++ { /* end */ }
++};
++MODULE_DEVICE_TABLE(of, of_mxs_power_match);
++
++static const struct power_supply_desc ac_desc = {
++ .properties = mxs_power_ac_props,
++ .num_properties = ARRAY_SIZE(mxs_power_ac_props),
++ .get_property = mxs_power_ac_get_property,
++ .name = "ac",
++ .type = POWER_SUPPLY_TYPE_MAINS,
++};
++
++static int mxs_power_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ struct resource *res;
++ struct mxs_power_data *data;
++ struct power_supply_config psy_cfg = {};
++ void __iomem *v5ctrl_addr;
++
++ if (!np) {
++ dev_err(dev, "missing device tree\n");
++ return -EINVAL;
++ }
++
++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ data->base_addr = devm_ioremap_resource(dev, res);
++ if (IS_ERR(data->base_addr))
++ return PTR_ERR(data->base_addr);
++
++ psy_cfg.drv_data = data;
++
++ data->ac = devm_power_supply_register(dev, &ac_desc, &psy_cfg);
++ if (IS_ERR(data->ac))
++ return PTR_ERR(data->ac);
++
++ platform_set_drvdata(pdev, data);
++
++ v5ctrl_addr = data->base_addr + HW_POWER_5VCTRL_OFFSET;
++
++ /* Make sure the current limit of the linregs are disabled. */
++ writel(BM_POWER_5VCTRL_ENABLE_LINREG_ILIMIT,
++ v5ctrl_addr + STMP_OFFSET_REG_CLR);
++
++ return of_platform_populate(np, NULL, NULL, dev);
++}
++
++static struct platform_driver mxs_power_driver = {
++ .driver = {
++ .name = "mxs_power",
++ .of_match_table = of_mxs_power_match,
++ },
++ .probe = mxs_power_probe,
++};
++
++module_platform_driver(mxs_power_driver);
++
++MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
++MODULE_DESCRIPTION("Freescale MXS power subsystem");
++MODULE_LICENSE("GPL v2");
--- /dev/null
+diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
+index a6f116a..7b525f5 100644
+--- a/drivers/regulator/Kconfig
++++ b/drivers/regulator/Kconfig
+@@ -450,6 +450,14 @@ config REGULATOR_MT6397
+ This driver supports the control of different power rails of device
+ through regulator interface.
+
++config REGULATOR_MXS
++ tristate "Freescale MXS on-chip regulators"
++ depends on (MXS_POWER || COMPILE_TEST)
++ help
++ Say y here to support Freescale MXS on-chip regulators.
++ It is recommended that this option be enabled on i.MX23,
++ i.MX28 platform.
++
+ config REGULATOR_PALMAS
+ tristate "TI Palmas PMIC Regulators"
+ depends on MFD_PALMAS
+diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
+index 2c4da15..a3ebf23 100644
+--- a/drivers/regulator/Makefile
++++ b/drivers/regulator/Makefile
+@@ -60,6 +60,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
+ obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
+ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
+ obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
++obj-$(CONFIG_REGULATOR_MXS) += mxs-regulator.o
+ obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
+ obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
+ obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
+diff --git a/drivers/regulator/mxs-regulator.c b/drivers/regulator/mxs-regulator.c
+new file mode 100644
+index 0000000..e53707b
+--- /dev/null
++++ b/drivers/regulator/mxs-regulator.c
+@@ -0,0 +1,540 @@
++/*
++ * Freescale MXS on-chip regulators
++ *
++ * Embedded Alley Solutions, Inc <source@embeddedalley.com>
++ *
++ * Copyright (C) 2014 Stefan Wahren
++ * Copyright (C) 2010 Freescale Semiconductor, Inc.
++ * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
++ *
++ * Inspired by imx-bootlets
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/regulator/driver.h>
++#include <linux/regulator/machine.h>
++#include <linux/regulator/of_regulator.h>
++#include <linux/slab.h>
++
++/* Powered by linear regulator. DCDC output is gated off and
++ the linreg output is equal to the target. */
++#define HW_POWER_LINREG_DCDC_OFF 1
++
++/* Powered by linear regulator. DCDC output is not gated off
++ and is ready for the automatic hardware transistion after a 5V
++ event. The converters are not enabled when 5V is present. LinReg output
++ is 25mV below target. */
++#define HW_POWER_LINREG_DCDC_READY 2
++
++/* Powered by DCDC converter and the LinReg is on. LinReg output
++ is 25mV below target. */
++#define HW_POWER_DCDC_LINREG_ON 3
++
++/* Powered by DCDC converter and the LinReg is off. LinReg output
++ is 25mV below target. */
++#define HW_POWER_DCDC_LINREG_OFF 4
++
++/* Powered by DCDC converter and the LinReg is ready for the
++ automatic hardware transfer. The LinReg output is not enabled and
++ depends on the 5V presence to enable the LinRegs. LinReg offset is 25mV
++ below target. */
++#define HW_POWER_DCDC_LINREG_READY 5
++
++/* Powered by an external source when 5V is present. This does not
++ necessarily mean the external source is powered by 5V,but the chip needs
++ to be aware that 5V is present. */
++#define HW_POWER_EXTERNAL_SOURCE_5V 6
++
++/* Powered by an external source when 5V is not present.This doesn't
++ necessarily mean the external source is powered by the battery, but the
++ chip needs to be aware that the battery is present */
++#define HW_POWER_EXTERNAL_SOURCE_BATTERY 7
++
++/* Unknown configuration. This is an error. */
++#define HW_POWER_UNKNOWN_SOURCE 8
++
++/* TODO: Move power register offsets into header file */
++#define HW_POWER_5VCTRL 0x00000010
++#define HW_POWER_VDDDCTRL 0x00000040
++#define HW_POWER_VDDACTRL 0x00000050
++#define HW_POWER_VDDIOCTRL 0x00000060
++#define HW_POWER_MISC 0x00000090
++#define HW_POWER_STS 0x000000c0
++
++#define BM_POWER_STS_VBUSVALID0_STATUS BIT(15)
++#define BM_POWER_STS_DC_OK BIT(9)
++
++#define BM_POWER_5VCTRL_ILIMIT_EQ_ZERO BIT(2)
++#define BM_POWER_5VCTRL_ENABLE_DCDC BIT(0)
++
++#define BM_POWER_LINREG_OFFSET_DCDC_MODE BIT(1)
++
++#define SHIFT_FREQSEL 4
++
++#define BM_POWER_MISC_FREQSEL (7 << SHIFT_FREQSEL)
++
++/* Recommended DC-DC clock source values */
++#define HW_POWER_MISC_FREQSEL_20000_KHZ 1
++#define HW_POWER_MISC_FREQSEL_24000_KHZ 2
++#define HW_POWER_MISC_FREQSEL_19200_KHZ 3
++
++#define HW_POWER_MISC_SEL_PLLCLK BIT(0)
++
++/* Regulator IDs */
++#define MXS_DCDC 1
++#define MXS_VDDIO 2
++#define MXS_VDDA 3
++#define MXS_VDDD 4
++
++struct mxs_reg_info {
++ /* regulator descriptor */
++ struct regulator_desc desc;
++
++ /* regulator control register */
++ int ctrl_reg;
++
++ /* disable DC-DC output */
++ unsigned int disable_fet_mask;
++
++ /* steps between linreg output and DC-DC target */
++ unsigned int linreg_offset_mask;
++ u8 linreg_offset_shift;
++
++ /* function which determine power source */
++ u8 (*get_power_source)(struct regulator_dev *);
++};
++
++static inline u8 get_linreg_offset(struct mxs_reg_info *ldo, u32 regs)
++{
++ return (regs & ldo->linreg_offset_mask) >> ldo->linreg_offset_shift;
++}
++
++static u8 get_vddio_power_source(struct regulator_dev *reg)
++{
++ struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
++ u32 v5ctrl, status, base;
++ u8 offset;
++
++ if (regmap_read(reg->regmap, HW_POWER_5VCTRL, &v5ctrl))
++ return HW_POWER_UNKNOWN_SOURCE;
++
++ if (regmap_read(reg->regmap, HW_POWER_STS, &status))
++ return HW_POWER_UNKNOWN_SOURCE;
++
++ if (regmap_read(reg->regmap, ldo->ctrl_reg, &base))
++ return HW_POWER_UNKNOWN_SOURCE;
++
++ offset = get_linreg_offset(ldo, base);
++
++ /* If VBUS valid then 5 V power supply present */
++ if (status & BM_POWER_STS_VBUSVALID0_STATUS) {
++ /* Powered by Linreg, DC-DC is off */
++ if ((base & ldo->disable_fet_mask) &&
++ !(offset & BM_POWER_LINREG_OFFSET_DCDC_MODE)) {
++ return HW_POWER_LINREG_DCDC_OFF;
++ }
++
++ if (v5ctrl & BM_POWER_5VCTRL_ENABLE_DCDC) {
++ /* Powered by DC-DC, Linreg is on */
++ if (offset & BM_POWER_LINREG_OFFSET_DCDC_MODE)
++ return HW_POWER_DCDC_LINREG_ON;
++ } else {
++ /* Powered by Linreg, DC-DC is off */
++ if (!(offset & BM_POWER_LINREG_OFFSET_DCDC_MODE))
++ return HW_POWER_LINREG_DCDC_OFF;
++ }
++ } else {
++ /* Powered by DC-DC, Linreg is on */
++ if (offset & BM_POWER_LINREG_OFFSET_DCDC_MODE)
++ return HW_POWER_DCDC_LINREG_ON;
++ }
++
++ return HW_POWER_UNKNOWN_SOURCE;
++}
++
++static u8 get_vdda_vddd_power_source(struct regulator_dev *reg)
++{
++ struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
++ struct regulator_desc *desc = &ldo->desc;
++ u32 v5ctrl, status, base;
++ u8 offset;
++
++ if (regmap_read(reg->regmap, HW_POWER_5VCTRL, &v5ctrl))
++ return HW_POWER_UNKNOWN_SOURCE;
++
++ if (regmap_read(reg->regmap, HW_POWER_STS, &status))
++ return HW_POWER_UNKNOWN_SOURCE;
++
++ if (regmap_read(reg->regmap, ldo->ctrl_reg, &base))
++ return HW_POWER_UNKNOWN_SOURCE;
++
++ offset = get_linreg_offset(ldo, base);
++
++ /* DC-DC output is disabled */
++ if (base & ldo->disable_fet_mask) {
++ /* Powered by 5 V supply */
++ if (status & BM_POWER_STS_VBUSVALID0_STATUS)
++ return HW_POWER_EXTERNAL_SOURCE_5V;
++
++ /* Powered by Linreg, DC-DC is off */
++ if (!(offset & BM_POWER_LINREG_OFFSET_DCDC_MODE))
++ return HW_POWER_LINREG_DCDC_OFF;
++ }
++
++ /* If VBUS valid then 5 V power supply present */
++ if (status & BM_POWER_STS_VBUSVALID0_STATUS) {
++ /* Powered by DC-DC, Linreg is on */
++ if (v5ctrl & BM_POWER_5VCTRL_ENABLE_DCDC)
++ return HW_POWER_DCDC_LINREG_ON;
++
++ /* Powered by Linreg, DC-DC is off */
++ return HW_POWER_LINREG_DCDC_OFF;
++ }
++
++ /* DC-DC is on */
++ if (offset & BM_POWER_LINREG_OFFSET_DCDC_MODE) {
++ /* Powered by DC-DC, Linreg is on */
++ if (base & desc->enable_mask)
++ return HW_POWER_DCDC_LINREG_ON;
++
++ /* Powered by DC-DC, Linreg is off */
++ return HW_POWER_DCDC_LINREG_OFF;
++ }
++
++ return HW_POWER_UNKNOWN_SOURCE;
++}
++
++static int mxs_set_dcdc_freq(struct regulator_dev *reg, u32 hz)
++{
++ struct mxs_reg_info *dcdc = rdev_get_drvdata(reg);
++ u32 val;
++ int ret;
++
++ if (dcdc->desc.id != MXS_DCDC) {
++ dev_warn(®->dev, "Setting switching freq is not supported\n");
++ return -EINVAL;
++ }
++
++ ret = regmap_read(reg->regmap, HW_POWER_MISC, &val);
++ if (ret)
++ return ret;
++
++ val &= ~BM_POWER_MISC_FREQSEL;
++ val &= ~HW_POWER_MISC_SEL_PLLCLK;
++
++ /*
++ * Select the PLL/PFD based frequency that the DC-DC converter uses.
++ * The actual switching frequency driving the power inductor is
++ * DCDC_CLK/16. Accept only values recommend by Freescale.
++ */
++ switch (hz) {
++ case 1200000:
++ val |= HW_POWER_MISC_FREQSEL_19200_KHZ << SHIFT_FREQSEL;
++ break;
++ case 1250000:
++ val |= HW_POWER_MISC_FREQSEL_20000_KHZ << SHIFT_FREQSEL;
++ break;
++ case 1500000:
++ val |= HW_POWER_MISC_FREQSEL_24000_KHZ << SHIFT_FREQSEL;
++ break;
++ default:
++ dev_warn(®->dev, "Switching freq: %u Hz not supported\n",
++ hz);
++ return -EINVAL;
++ }
++
++ /* First program FREQSEL */
++ ret = regmap_write(reg->regmap, HW_POWER_MISC, val);
++ if (ret)
++ return ret;
++
++ /* then set PLL as clock for DC-DC converter */
++ val |= HW_POWER_MISC_SEL_PLLCLK;
++
++ return regmap_write(reg->regmap, HW_POWER_MISC, val);
++}
++
++static int mxs_ldo_set_voltage_sel(struct regulator_dev *reg, unsigned sel)
++{
++ struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
++ struct regulator_desc *desc = &ldo->desc;
++ u32 status = 0;
++ int timeout;
++ int ret;
++
++ ret = regmap_update_bits(reg->regmap, desc->vsel_reg, desc->vsel_mask,
++ sel);
++ if (ret)
++ return ret;
++
++ if (ldo->get_power_source) {
++ switch (ldo->get_power_source(reg)) {
++ case HW_POWER_LINREG_DCDC_OFF:
++ case HW_POWER_LINREG_DCDC_READY:
++ case HW_POWER_EXTERNAL_SOURCE_5V:
++ /*
++ * Since the DC-DC converter is off we can't
++ * trigger on DC_OK. So wait at least 1 ms
++ * for stabilization.
++ */
++ usleep_range(1000, 2000);
++ return 0;
++ }
++ }
++
++ /* Make sure DC_OK has changed */
++ usleep_range(15, 20);
++
++ for (timeout = 0; timeout < 20; timeout++) {
++ ret = regmap_read(reg->regmap, HW_POWER_STS, &status);
++
++ if (ret)
++ break;
++
++ /* DC-DC converter control loop has stabilized */
++ if (status & BM_POWER_STS_DC_OK)
++ return 0;
++
++ udelay(1);
++ }
++
++ if (!ret)
++ dev_warn_ratelimited(®->dev, "%s: timeout status=0x%08x\n",
++ __func__, status);
++
++ msleep(20);
++
++ return -ETIMEDOUT;
++}
++
++static int mxs_ldo_is_enabled(struct regulator_dev *reg)
++{
++ struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
++
++ if (ldo->get_power_source) {
++ switch (ldo->get_power_source(reg)) {
++ case HW_POWER_LINREG_DCDC_OFF:
++ case HW_POWER_LINREG_DCDC_READY:
++ case HW_POWER_DCDC_LINREG_ON:
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++static struct regulator_ops mxs_dcdc_ops = {
++ .is_enabled = regulator_is_enabled_regmap,
++};
++
++static struct regulator_ops mxs_ldo_ops = {
++ .list_voltage = regulator_list_voltage_linear,
++ .map_voltage = regulator_map_voltage_linear,
++ .set_voltage_sel = mxs_ldo_set_voltage_sel,
++ .get_voltage_sel = regulator_get_voltage_sel_regmap,
++ .is_enabled = mxs_ldo_is_enabled,
++};
++
++static const struct mxs_reg_info mxs_info_dcdc = {
++ .desc = {
++ .name = "dcdc",
++ .id = MXS_DCDC,
++ .type = REGULATOR_VOLTAGE,
++ .owner = THIS_MODULE,
++ .ops = &mxs_dcdc_ops,
++ .enable_reg = HW_POWER_STS,
++ .enable_mask = (1 << 0),
++ },
++};
++
++static const struct mxs_reg_info imx23_info_vddio = {
++ .desc = {
++ .name = "vddio",
++ .id = MXS_VDDIO,
++ .type = REGULATOR_VOLTAGE,
++ .owner = THIS_MODULE,
++ .n_voltages = 0x20,
++ .uV_step = 25000,
++ .linear_min_sel = 0,
++ .min_uV = 2800000,
++ .vsel_reg = HW_POWER_VDDIOCTRL,
++ .vsel_mask = 0x1f,
++ .ops = &mxs_ldo_ops,
++ },
++ .ctrl_reg = HW_POWER_VDDIOCTRL,
++ .disable_fet_mask = 1 << 16,
++ .linreg_offset_mask = 3 << 12,
++ .linreg_offset_shift = 12,
++ .get_power_source = get_vddio_power_source,
++};
++
++static const struct mxs_reg_info imx28_info_vddio = {
++ .desc = {
++ .name = "vddio",
++ .id = MXS_VDDIO,
++ .type = REGULATOR_VOLTAGE,
++ .owner = THIS_MODULE,
++ .n_voltages = 0x11,
++ .uV_step = 50000,
++ .linear_min_sel = 0,
++ .min_uV = 2800000,
++ .vsel_reg = HW_POWER_VDDIOCTRL,
++ .vsel_mask = 0x1f,
++ .ops = &mxs_ldo_ops,
++ },
++ .ctrl_reg = HW_POWER_VDDIOCTRL,
++ .disable_fet_mask = 1 << 16,
++ .linreg_offset_mask = 3 << 12,
++ .linreg_offset_shift = 12,
++ .get_power_source = get_vddio_power_source,
++};
++
++static const struct mxs_reg_info mxs_info_vdda = {
++ .desc = {
++ .name = "vdda",
++ .id = MXS_VDDA,
++ .type = REGULATOR_VOLTAGE,
++ .owner = THIS_MODULE,
++ .n_voltages = 0x20,
++ .uV_step = 25000,
++ .linear_min_sel = 0,
++ .min_uV = 1500000,
++ .vsel_reg = HW_POWER_VDDACTRL,
++ .vsel_mask = 0x1f,
++ .ops = &mxs_ldo_ops,
++ .enable_mask = (1 << 17),
++ },
++ .ctrl_reg = HW_POWER_VDDACTRL,
++ .disable_fet_mask = 1 << 16,
++ .linreg_offset_mask = 3 << 12,
++ .linreg_offset_shift = 12,
++ .get_power_source = get_vdda_vddd_power_source,
++};
++
++static const struct mxs_reg_info mxs_info_vddd = {
++ .desc = {
++ .name = "vddd",
++ .id = MXS_VDDD,
++ .type = REGULATOR_VOLTAGE,
++ .owner = THIS_MODULE,
++ .n_voltages = 0x20,
++ .uV_step = 25000,
++ .linear_min_sel = 0,
++ .min_uV = 800000,
++ .vsel_reg = HW_POWER_VDDDCTRL,
++ .vsel_mask = 0x1f,
++ .ops = &mxs_ldo_ops,
++ .enable_mask = (1 << 21),
++ },
++ .ctrl_reg = HW_POWER_VDDDCTRL,
++ .disable_fet_mask = 1 << 20,
++ .linreg_offset_mask = 3 << 16,
++ .linreg_offset_shift = 16,
++ .get_power_source = get_vdda_vddd_power_source,
++};
++
++static const struct of_device_id of_mxs_regulator_match[] = {
++ { .compatible = "fsl,imx23-dcdc", .data = &mxs_info_dcdc },
++ { .compatible = "fsl,imx28-dcdc", .data = &mxs_info_dcdc },
++ { .compatible = "fsl,imx23-vddio", .data = &imx23_info_vddio },
++ { .compatible = "fsl,imx23-vdda", .data = &mxs_info_vdda },
++ { .compatible = "fsl,imx23-vddd", .data = &mxs_info_vddd },
++ { .compatible = "fsl,imx28-vddio", .data = &imx28_info_vddio },
++ { .compatible = "fsl,imx28-vdda", .data = &mxs_info_vdda },
++ { .compatible = "fsl,imx28-vddd", .data = &mxs_info_vddd },
++ { /* end */ }
++};
++MODULE_DEVICE_TABLE(of, of_mxs_regulator_match);
++
++static int mxs_regulator_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ const struct of_device_id *match;
++ struct device_node *parent_np;
++ struct regulator_dev *rdev = NULL;
++ struct mxs_reg_info *info;
++ struct regulator_init_data *initdata;
++ struct regulator_config config = { };
++ u32 switch_freq;
++
++ match = of_match_device(of_mxs_regulator_match, dev);
++ if (!match) {
++ /* We do not expect this to happen */
++ dev_err(dev, "%s: Unable to match device\n", __func__);
++ return -ENODEV;
++ }
++
++ info = devm_kmemdup(dev, match->data, sizeof(struct mxs_reg_info),
++ GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ initdata = of_get_regulator_init_data(dev, dev->of_node, &info->desc);
++ if (!initdata) {
++ dev_err(dev, "missing regulator init data\n");
++ return -EINVAL;
++ }
++
++ parent_np = of_get_parent(dev->of_node);
++ if (!parent_np)
++ return -ENODEV;
++ config.regmap = syscon_node_to_regmap(parent_np);
++ of_node_put(parent_np);
++ if (IS_ERR(config.regmap))
++ return PTR_ERR(config.regmap);
++
++ config.dev = dev;
++ config.init_data = initdata;
++ config.driver_data = info;
++ config.of_node = dev->of_node;
++
++ rdev = devm_regulator_register(dev, &info->desc, &config);
++ if (IS_ERR(rdev)) {
++ int ret = PTR_ERR(rdev);
++
++ dev_err(dev, "%s: failed to register regulator(%d)\n",
++ __func__, ret);
++ return ret;
++ }
++
++ if (!of_property_read_u32(dev->of_node, "switching-frequency",
++ &switch_freq))
++ mxs_set_dcdc_freq(rdev, switch_freq);
++
++ platform_set_drvdata(pdev, rdev);
++
++ return 0;
++}
++
++static struct platform_driver mxs_regulator_driver = {
++ .driver = {
++ .name = "mxs_regulator",
++ .of_match_table = of_mxs_regulator_match,
++ },
++ .probe = mxs_regulator_probe,
++};
++
++module_platform_driver(mxs_regulator_driver);
++
++MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
++MODULE_DESCRIPTION("Freescale MXS regulators");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:mxs_regulator");