zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/88pm8607.c b/ap/os/linux/linux-3.4.x/drivers/regulator/88pm8607.c
new file mode 100644
index 0000000..28b81ae
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/88pm8607.c
@@ -0,0 +1,474 @@
+/*
+ * Regulators driver for Marvell 88PM8607
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * 	Haojian Zhuang <haojian.zhuang@marvell.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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/module.h>
+
+struct pm8607_regulator_info {
+	struct regulator_desc	desc;
+	struct pm860x_chip	*chip;
+	struct regulator_dev	*regulator;
+	struct i2c_client	*i2c;
+
+	unsigned int	*vol_table;
+	unsigned int	*vol_suspend;
+
+	int	vol_reg;
+	int	vol_shift;
+	int	vol_nbits;
+	int	update_reg;
+	int	update_bit;
+	int	enable_reg;
+	int	enable_bit;
+	int	slope_double;
+};
+
+static const unsigned int BUCK1_table[] = {
+	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
+	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+	1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
+	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
+	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
+	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
+};
+
+static const unsigned int BUCK1_suspend_table[] = {
+	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
+	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
+	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
+	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
+	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
+	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
+};
+
+static const unsigned int BUCK2_table[] = {
+	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
+	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
+	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
+	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
+	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
+	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
+	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
+	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
+};
+
+static const unsigned int BUCK2_suspend_table[] = {
+	      0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
+	 400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
+	 800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
+	1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
+	1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
+	2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
+	2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
+	2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
+};
+
+static const unsigned int BUCK3_table[] = {
+              0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
+	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
+	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
+	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
+	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
+	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
+};
+
+static const unsigned int BUCK3_suspend_table[] = {
+              0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
+	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
+	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
+	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
+	 800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
+	1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
+	1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
+};
+
+static const unsigned int LDO1_table[] = {
+	1800000, 1200000, 2800000, 0,
+};
+
+static const unsigned int LDO1_suspend_table[] = {
+	1800000, 1200000, 0, 0,
+};
+
+static const unsigned int LDO2_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
+};
+
+static const unsigned int LDO2_suspend_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO3_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
+};
+
+static const unsigned int LDO3_suspend_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO4_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
+};
+
+static const unsigned int LDO4_suspend_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
+};
+
+static const unsigned int LDO5_table[] = {
+	2900000, 3000000, 3100000, 3300000,
+};
+
+static const unsigned int LDO5_suspend_table[] = {
+	2900000, 0, 0, 0,
+};
+
+static const unsigned int LDO6_table[] = {
+	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
+};
+
+static const unsigned int LDO6_suspend_table[] = {
+	1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
+};
+
+static const unsigned int LDO7_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO7_suspend_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO8_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO8_suspend_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO9_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
+};
+
+static const unsigned int LDO9_suspend_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+};
+
+static const unsigned int LDO10_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
+	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
+};
+
+static const unsigned int LDO10_suspend_table[] = {
+	1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
+	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
+};
+
+static const unsigned int LDO12_table[] = {
+	1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
+	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
+};
+
+static const unsigned int LDO12_suspend_table[] = {
+	1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
+	1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
+};
+
+static const unsigned int LDO13_table[] = {
+	1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0,
+};
+
+static const unsigned int LDO13_suspend_table[] = {
+	0,
+};
+
+static const unsigned int LDO14_table[] = {
+	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
+};
+
+static const unsigned int LDO14_suspend_table[] = {
+	1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
+};
+
+static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret = -EINVAL;
+
+	if (info->vol_table && (index < (1 << info->vol_nbits))) {
+		ret = info->vol_table[index];
+		if (info->slope_double)
+			ret <<= 1;
+	}
+	return ret;
+}
+
+static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+	int i, ret = -ENOENT;
+
+	if (info->slope_double) {
+		min_uV = min_uV >> 1;
+		max_uV = max_uV >> 1;
+	}
+	if (info->vol_table) {
+		for (i = 0; i < (1 << info->vol_nbits); i++) {
+			if (!info->vol_table[i])
+				break;
+			if ((min_uV <= info->vol_table[i])
+				&& (max_uV >= info->vol_table[i])) {
+				ret = i;
+				break;
+			}
+		}
+	}
+	if (ret < 0)
+		pr_err("invalid voltage range (%d %d) uV\n", min_uV, max_uV);
+	return ret;
+}
+
+static int pm8607_set_voltage(struct regulator_dev *rdev,
+			      int min_uV, int max_uV, unsigned *selector)
+{
+	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+	uint8_t val, mask;
+	int ret;
+
+	if (min_uV > max_uV) {
+		pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	ret = choose_voltage(rdev, min_uV, max_uV);
+	if (ret < 0)
+		return -EINVAL;
+	*selector = ret;
+	val = (uint8_t)(ret << info->vol_shift);
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+	ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val);
+	if (ret)
+		return ret;
+	switch (info->desc.id) {
+	case PM8607_ID_BUCK1:
+	case PM8607_ID_BUCK3:
+		ret = pm860x_set_bits(info->i2c, info->update_reg,
+				      1 << info->update_bit,
+				      1 << info->update_bit);
+		break;
+	}
+	return ret;
+}
+
+static int pm8607_get_voltage(struct regulator_dev *rdev)
+{
+	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+	uint8_t val, mask;
+	int ret;
+
+	ret = pm860x_reg_read(info->i2c, info->vol_reg);
+	if (ret < 0)
+		return ret;
+
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+	val = ((unsigned char)ret & mask) >> info->vol_shift;
+
+	return pm8607_list_voltage(rdev, val);
+}
+
+static int pm8607_enable(struct regulator_dev *rdev)
+{
+	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+
+	return pm860x_set_bits(info->i2c, info->enable_reg,
+			       1 << info->enable_bit,
+			       1 << info->enable_bit);
+}
+
+static int pm8607_disable(struct regulator_dev *rdev)
+{
+	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+
+	return pm860x_set_bits(info->i2c, info->enable_reg,
+			       1 << info->enable_bit, 0);
+}
+
+static int pm8607_is_enabled(struct regulator_dev *rdev)
+{
+	struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret;
+
+	ret = pm860x_reg_read(info->i2c, info->enable_reg);
+	if (ret < 0)
+		return ret;
+
+	return !!((unsigned char)ret & (1 << info->enable_bit));
+}
+
+static struct regulator_ops pm8607_regulator_ops = {
+	.set_voltage	= pm8607_set_voltage,
+	.get_voltage	= pm8607_get_voltage,
+	.enable		= pm8607_enable,
+	.disable	= pm8607_disable,
+	.is_enabled	= pm8607_is_enabled,
+};
+
+#define PM8607_DVC(vreg, nbits, ureg, ubit, ereg, ebit)			\
+{									\
+	.desc	= {							\
+		.name	= #vreg,					\
+		.ops	= &pm8607_regulator_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= PM8607_ID_##vreg,				\
+		.owner	= THIS_MODULE,					\
+	},								\
+	.vol_reg	= PM8607_##vreg,				\
+	.vol_shift	= (0),						\
+	.vol_nbits	= (nbits),					\
+	.update_reg	= PM8607_##ureg,				\
+	.update_bit	= (ubit),					\
+	.enable_reg	= PM8607_##ereg,				\
+	.enable_bit	= (ebit),					\
+	.slope_double	= (0),						\
+	.vol_table	= (unsigned int *)&vreg##_table,		\
+	.vol_suspend	= (unsigned int *)&vreg##_suspend_table,	\
+}
+
+#define PM8607_LDO(_id, vreg, shift, nbits, ereg, ebit)			\
+{									\
+	.desc	= {							\
+		.name	= "LDO" #_id,					\
+		.ops	= &pm8607_regulator_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= PM8607_ID_LDO##_id,				\
+		.owner	= THIS_MODULE,					\
+	},								\
+	.vol_reg	= PM8607_##vreg,				\
+	.vol_shift	= (shift),					\
+	.vol_nbits	= (nbits),					\
+	.enable_reg	= PM8607_##ereg,				\
+	.enable_bit	= (ebit),					\
+	.slope_double	= (0),						\
+	.vol_table	= (unsigned int *)&LDO##_id##_table,		\
+	.vol_suspend	= (unsigned int *)&LDO##_id##_suspend_table,	\
+}
+
+static struct pm8607_regulator_info pm8607_regulator_info[] = {
+	PM8607_DVC(BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
+	PM8607_DVC(BUCK2, 6, GO, 1, SUPPLIES_EN11, 1),
+	PM8607_DVC(BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
+
+	PM8607_LDO( 1,         LDO1, 0, 2, SUPPLIES_EN11, 3),
+	PM8607_LDO( 2,         LDO2, 0, 3, SUPPLIES_EN11, 4),
+	PM8607_LDO( 3,         LDO3, 0, 3, SUPPLIES_EN11, 5),
+	PM8607_LDO( 4,         LDO4, 0, 3, SUPPLIES_EN11, 6),
+	PM8607_LDO( 5,         LDO5, 0, 2, SUPPLIES_EN11, 7),
+	PM8607_LDO( 6,         LDO6, 0, 3, SUPPLIES_EN12, 0),
+	PM8607_LDO( 7,         LDO7, 0, 3, SUPPLIES_EN12, 1),
+	PM8607_LDO( 8,         LDO8, 0, 3, SUPPLIES_EN12, 2),
+	PM8607_LDO( 9,         LDO9, 0, 3, SUPPLIES_EN12, 3),
+	PM8607_LDO(10,        LDO10, 0, 4, SUPPLIES_EN12, 4),
+	PM8607_LDO(12,        LDO12, 0, 4, SUPPLIES_EN12, 5),
+	PM8607_LDO(13, VIBRATOR_SET, 1, 3,  VIBRATOR_SET, 0),
+	PM8607_LDO(14,        LDO14, 0, 3, SUPPLIES_EN12, 6),
+};
+
+static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
+{
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+	struct pm8607_regulator_info *info = NULL;
+	struct regulator_init_data *pdata = pdev->dev.platform_data;
+	struct resource *res;
+	int i;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No I/O resource!\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
+		info = &pm8607_regulator_info[i];
+		if (info->desc.id == res->start)
+			break;
+	}
+	if (i == ARRAY_SIZE(pm8607_regulator_info)) {
+		dev_err(&pdev->dev, "Failed to find regulator %llu\n",
+			(unsigned long long)res->start);
+		return -EINVAL;
+	}
+	info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+	info->chip = chip;
+
+	/* check DVC ramp slope double */
+	if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
+		info->slope_double = 1;
+
+	/* replace driver_data with info */
+	info->regulator = regulator_register(&info->desc, &pdev->dev,
+					     pdata, info, NULL);
+	if (IS_ERR(info->regulator)) {
+		dev_err(&pdev->dev, "failed to register regulator %s\n",
+			info->desc.name);
+		return PTR_ERR(info->regulator);
+	}
+
+	platform_set_drvdata(pdev, info);
+	return 0;
+}
+
+static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
+{
+	struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	regulator_unregister(info->regulator);
+	return 0;
+}
+
+static struct platform_driver pm8607_regulator_driver = {
+	.driver		= {
+		.name	= "88pm860x-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pm8607_regulator_probe,
+	.remove		= __devexit_p(pm8607_regulator_remove),
+};
+
+static int __init pm8607_regulator_init(void)
+{
+	return platform_driver_register(&pm8607_regulator_driver);
+}
+subsys_initcall(pm8607_regulator_init);
+
+static void __exit pm8607_regulator_exit(void)
+{
+	platform_driver_unregister(&pm8607_regulator_driver);
+}
+module_exit(pm8607_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
+MODULE_ALIAS("platform:88pm8607-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/Kconfig b/ap/os/linux/linux-3.4.x/drivers/regulator/Kconfig
new file mode 100644
index 0000000..229f776
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/Kconfig
@@ -0,0 +1,376 @@
+menuconfig REGULATOR
+	bool "Voltage and Current Regulator Support"
+	help
+	  Generic Voltage and Current Regulator support.
+
+	  This framework is designed to provide a generic interface to voltage
+	  and current regulators within the Linux kernel. It's intended to
+	  provide voltage and current control to client or consumer drivers and
+	  also provide status information to user space applications through a
+	  sysfs interface.
+
+	  The intention is to allow systems to dynamically control regulator
+	  output in order to save power and prolong battery life. This applies
+	  to both voltage regulators (where voltage output is controllable) and
+	  current sinks (where current output is controllable).
+
+	  This framework safely compiles out if not selected so that client
+	  drivers can still be used in systems with no software controllable
+	  regulators.
+
+	  If unsure, say no.
+
+if REGULATOR
+
+config REGULATOR_DEBUG
+	bool "Regulator debug support"
+	help
+	  Say yes here to enable debugging support.
+
+config REGULATOR_DUMMY
+	bool "Provide a dummy regulator if regulator lookups fail"
+	help
+	  If this option is enabled then when a regulator lookup fails
+	  and the board has not specified that it has provided full
+	  constraints then the regulator core will provide an always
+	  enabled dummy regulator will be provided, allowing consumer
+	  drivers to continue.
+
+	  A warning will be generated when this substitution is done.
+
+config REGULATOR_FIXED_VOLTAGE
+	tristate "Fixed voltage regulator support"
+	help
+	  This driver provides support for fixed voltage regulators,
+	  useful for systems which use a combination of software
+	  managed regulators and simple non-configurable regulators.
+
+config REGULATOR_VIRTUAL_CONSUMER
+	tristate "Virtual regulator consumer support"
+	help
+	  This driver provides a virtual consumer for the voltage and
+          current regulator API which provides sysfs controls for
+          configuring the supplies requested.  This is mainly useful
+          for test purposes.
+
+          If unsure, say no.
+
+config REGULATOR_USERSPACE_CONSUMER
+	tristate "Userspace regulator consumer support"
+	help
+	  There are some classes of devices that are controlled entirely
+	  from user space. Userspace consumer driver provides ability to
+	  control power supplies for such devices.
+
+          If unsure, say no.
+
+config REGULATOR_GPIO
+	tristate "GPIO regulator support"
+	depends on GENERIC_GPIO
+	help
+	  This driver provides support for regulators that can be
+	  controlled via gpios.
+	  It is capable of supporting current and voltage regulators
+	  and the platform has to provide a mapping of GPIO-states
+	  to target volts/amps.
+
+config REGULATOR_AD5398
+	tristate "Analog Devices AD5398/AD5821 regulators"
+	depends on I2C
+	help
+	  This driver supports AD5398 and AD5821 current regulator chips.
+	  If building into module, its name is ad5398.ko.
+
+config REGULATOR_AAT2870
+	tristate "AnalogicTech AAT2870 Regulators"
+	depends on MFD_AAT2870_CORE
+	help
+	  If you have a AnalogicTech AAT2870 say Y to enable the
+	  regulator driver.
+
+config REGULATOR_DA903X
+	tristate "Dialog Semiconductor DA9030/DA9034 regulators"
+	depends on PMIC_DA903X
+	help
+	  Say y here to support the BUCKs and LDOs regulators found on
+	  Dialog Semiconductor DA9030/DA9034 PMIC.
+
+config REGULATOR_DA9052
+	tristate "Dialog Semiconductor DA9052/DA9053 regulators"
+	depends on PMIC_DA9052
+	help
+	  This driver supports the voltage regulators of DA9052-BC and
+	  DA9053-AA/Bx PMIC.
+
+config REGULATOR_ANATOP
+	tristate "Freescale i.MX on-chip ANATOP LDO regulators"
+	depends on MFD_ANATOP
+	help
+	  Say y here to support Freescale i.MX on-chip ANATOP LDOs
+	  regulators. It is recommended that this option be
+	  enabled on i.MX6 platform.
+
+config REGULATOR_MC13XXX_CORE
+	tristate
+
+config REGULATOR_MC13783
+	tristate "Freescale MC13783 regulator driver"
+	depends on MFD_MC13783
+	select REGULATOR_MC13XXX_CORE
+	help
+	  Say y here to support the regulators found on the Freescale MC13783
+	  PMIC.
+
+config REGULATOR_MC13892
+	tristate "Freescale MC13892 regulator driver"
+	depends on MFD_MC13XXX
+	select REGULATOR_MC13XXX_CORE
+	help
+	  Say y here to support the regulators found on the Freescale MC13892
+	  PMIC.
+
+config REGULATOR_ISL6271A
+	tristate "Intersil ISL6271A Power regulator"
+	depends on I2C
+	help
+	  This driver supports ISL6271A voltage regulator chip.
+
+config REGULATOR_88PM8607
+	bool "Marvell 88PM8607 Power regulators"
+	depends on MFD_88PM860X=y
+	help
+	  This driver supports 88PM8607 voltage regulator chips.
+
+config REGULATOR_MAX1586
+	tristate "Maxim 1586/1587 voltage regulator"
+	depends on I2C
+	help
+	  This driver controls a Maxim 1586 or 1587 voltage output
+	  regulator via I2C bus. The provided regulator is suitable
+	  for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
+
+config REGULATOR_MAX8649
+	tristate "Maxim 8649 voltage regulator"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This driver controls a Maxim 8649 voltage output regulator via
+	  I2C bus.
+
+config REGULATOR_MAX8660
+	tristate "Maxim 8660/8661 voltage regulator"
+	depends on I2C
+	help
+	  This driver controls a Maxim 8660/8661 voltage output
+	  regulator via I2C bus.
+
+config REGULATOR_MAX8925
+	tristate "Maxim MAX8925 Power Management IC"
+	depends on MFD_MAX8925
+	help
+	  Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC.
+
+config REGULATOR_MAX8952
+	tristate "Maxim MAX8952 Power Management IC"
+	depends on I2C
+	help
+	  This driver controls a Maxim 8952 voltage output regulator
+	  via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS
+	  modes ranging from 0.77V to 1.40V by 0.01V steps.
+
+config REGULATOR_MAX8997
+	tristate "Maxim 8997/8966 regulator"
+	depends on MFD_MAX8997
+	help
+	  This driver controls a Maxim 8997/8966 regulator
+	  via I2C bus. The provided regulator is suitable for S5PC110,
+	  S5PV210, and Exynos-4 chips to control VCC_CORE and
+	  VCC_USIM voltages.
+
+config REGULATOR_MAX8998
+	tristate "Maxim 8998 voltage regulator"
+	depends on MFD_MAX8998
+	help
+	  This driver controls a Maxim 8998 voltage output regulator
+	  via I2C bus. The provided regulator is suitable for S3C6410
+	  and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
+
+config REGULATOR_PCAP
+	tristate "Motorola PCAP2 regulator driver"
+	depends on EZX_PCAP
+	help
+	 This driver provides support for the voltage regulators of the
+	 PCAP2 PMIC.
+
+config REGULATOR_LP3971
+	tristate "National Semiconductors LP3971 PMIC regulator driver"
+	depends on I2C
+	help
+	 Say Y here to support the voltage regulators and convertors
+	 on National Semiconductors LP3971 PMIC
+
+config REGULATOR_LP3972
+	tristate "National Semiconductors LP3972 PMIC regulator driver"
+	depends on I2C
+	help
+	 Say Y here to support the voltage regulators and convertors
+	 on National Semiconductors LP3972 PMIC
+
+config REGULATOR_PCF50633
+	tristate "NXP PCF50633 regulator driver"
+        depends on MFD_PCF50633
+	help
+	 Say Y here to support the voltage regulators and convertors
+	 on PCF50633
+
+config REGULATOR_S5M8767
+	tristate "Samsung S5M8767A voltage regulator"
+	depends on MFD_S5M_CORE
+	help
+	 This driver supports a Samsung S5M8767A voltage output regulator
+	 via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
+	 supports DVS mode with 8bits of output voltage control.
+
+config REGULATOR_AB3100
+	tristate "ST-Ericsson AB3100 Regulator functions"
+	depends on AB3100_CORE
+	default y if AB3100_CORE
+	help
+	 These regulators correspond to functionality in the
+	 AB3100 analog baseband dealing with power regulators
+	 for the system.
+
+config REGULATOR_AB8500
+	bool "ST-Ericsson AB8500 Power Regulators"
+	depends on AB8500_CORE
+	help
+	  This driver supports the regulators found on the ST-Ericsson mixed
+	  signal AB8500 PMIC
+
+config REGULATOR_DBX500_PRCMU
+	bool
+
+config REGULATOR_DB8500_PRCMU
+	bool "ST-Ericsson DB8500 Voltage Domain Regulators"
+	depends on MFD_DB8500_PRCMU
+	select REGULATOR_DBX500_PRCMU
+	help
+	  This driver supports the voltage domain regulators controlled by the
+	  DB8500 PRCMU
+
+config REGULATOR_TPS6105X
+	tristate "TI TPS6105X Power regulators"
+	depends on TPS6105X
+	default y if TPS6105X
+	help
+	  This driver supports TPS61050/TPS61052 voltage regulator chips.
+	  It is a single boost converter primarily for white LEDs and
+	  audio amplifiers.
+
+config REGULATOR_TPS62360
+	tristate "TI TPS62360 Power Regulator"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This driver supports TPS62360 voltage regulator chip. This
+	  regulator is meant for processor core supply. This chip is
+	  high-frequency synchronous step down dc-dc converter optimized
+	  for battery-powered portable applications.
+
+config REGULATOR_TPS65023
+	tristate "TI TPS65023 Power regulators"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This driver supports TPS65023 voltage regulator chips. TPS65023 provides
+	  three step-down converters and two general-purpose LDO voltage regulators.
+	  It supports TI's software based Class-2 SmartReflex implementation.
+
+config REGULATOR_TPS6507X
+	tristate "TI TPS6507X Power regulators"
+	depends on I2C
+	help
+	  This driver supports TPS6507X voltage regulator chips. TPS6507X provides
+	  three step-down converters and two general-purpose LDO voltage regulators.
+	  It supports TI's software based Class-2 SmartReflex implementation.
+
+config REGULATOR_TPS65217
+	tristate "TI TPS65217 Power regulators"
+	depends on MFD_TPS65217
+	help
+	  This driver supports TPS65217 voltage regulator chips. TPS65217
+	  provides three step-down converters and four general-purpose LDO
+	  voltage regulators. It supports software based voltage control
+	  for different voltage domains
+
+config REGULATOR_TPS6524X
+	tristate "TI TPS6524X Power regulators"
+	depends on SPI
+	help
+	  This driver supports TPS6524X voltage regulator chips. TPS6524X
+	  provides three step-down converters and two general-purpose LDO
+	  voltage regulators.  This device is interfaced using a customized
+	  serial interface currently supported on the sequencer serial
+	  port controller.
+
+config REGULATOR_TPS6586X
+	tristate "TI TPS6586X Power regulators"
+	depends on MFD_TPS6586X
+	help
+	  This driver supports TPS6586X voltage regulator chips.
+
+config REGULATOR_TPS65910
+	tristate "TI TPS65910/TPS65911 Power Regulators"
+	depends on MFD_TPS65910
+	help
+	  This driver supports TPS65910/TPS65911 voltage regulator chips.
+
+config REGULATOR_TPS65912
+	tristate "TI TPS65912 Power regulator"
+	depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
+	help
+	    This driver supports TPS65912 voltage regulator chip.
+
+config REGULATOR_ZX234290
+	tristate "Sanechips ZX234290 Power regulator"
+	depends on (MFD_ZX234290_I2C)
+	help
+	    This driver supports ZX234290 voltage regulator chip.
+
+config REGULATOR_TWL4030
+	bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
+	depends on TWL4030_CORE
+	help
+	  This driver supports the voltage regulators provided by
+	  this family of companion chips.
+
+config REGULATOR_WM831X
+	tristate "Wolfson Microelectronics WM831x PMIC regulators"
+	depends on MFD_WM831X
+	help
+	  Support the voltage and current regulators of the WM831x series
+	  of PMIC devices.
+
+config REGULATOR_WM8350
+	tristate "Wolfson Microelectronics WM8350 AudioPlus PMIC"
+	depends on MFD_WM8350
+	help
+	  This driver provides support for the voltage and current regulators
+          of the WM8350 AudioPlus PMIC.
+
+config REGULATOR_WM8400
+	tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC"
+	depends on MFD_WM8400
+	help
+	  This driver provides support for the voltage regulators of the
+	  WM8400 AudioPlus PMIC.
+
+config REGULATOR_WM8994
+	tristate "Wolfson Microelectronics WM8994 CODEC"
+	depends on MFD_WM8994
+	help
+	  This driver provides support for the voltage regulators on the
+	  WM8994 CODEC.
+
+endif
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/Makefile b/ap/os/linux/linux-3.4.x/drivers/regulator/Makefile
new file mode 100644
index 0000000..2b790b9
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/Makefile
@@ -0,0 +1,57 @@
+#
+# Makefile for regulator drivers.
+#
+
+
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o
+obj-$(CONFIG_OF) += of_regulator.o
+obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
+obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
+obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
+
+obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
+obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
+obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
+obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
+obj-$(CONFIG_REGULATOR_AB8500)	+= ab8500.o
+obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
+obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
+obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
+obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
+obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
+obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
+obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
+obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
+obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
+obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
+obj-$(CONFIG_REGULATOR_MAX8649)	+= max8649.o
+obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
+obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
+obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
+obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
+obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
+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_PCAP) += pcap-regulator.o
+obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
+obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
+obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o
+obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
+obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
+obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
+obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
+obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
+obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
+obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
+obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
+obj-$(CONFIG_REGULATOR_ZX234290) += zx234290-regulator.o
+
+ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/aat2870-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/aat2870-regulator.c
new file mode 100644
index 0000000..9ed5c5d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/aat2870-regulator.c
@@ -0,0 +1,233 @@
+/*
+ * linux/drivers/regulator/aat2870-regulator.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ * Author: Jin Park <jinyoungp@nvidia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/aat2870.h>
+
+struct aat2870_regulator {
+	struct aat2870_data *aat2870;
+	struct regulator_desc desc;
+
+	const int *voltages; /* uV */
+
+	int min_uV;
+	int max_uV;
+
+	u8 enable_addr;
+	u8 enable_shift;
+	u8 enable_mask;
+
+	u8 voltage_addr;
+	u8 voltage_shift;
+	u8 voltage_mask;
+};
+
+static int aat2870_ldo_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+
+	return ri->voltages[selector];
+}
+
+static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev,
+				       unsigned selector)
+{
+	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+	struct aat2870_data *aat2870 = ri->aat2870;
+
+	return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask,
+			       selector << ri->voltage_shift);
+}
+
+static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+	struct aat2870_data *aat2870 = ri->aat2870;
+	u8 val;
+	int ret;
+
+	ret = aat2870->read(aat2870, ri->voltage_addr, &val);
+	if (ret)
+		return ret;
+
+	return (val & ri->voltage_mask) >> ri->voltage_shift;
+}
+
+static int aat2870_ldo_enable(struct regulator_dev *rdev)
+{
+	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+	struct aat2870_data *aat2870 = ri->aat2870;
+
+	return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask,
+			       ri->enable_mask);
+}
+
+static int aat2870_ldo_disable(struct regulator_dev *rdev)
+{
+	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+	struct aat2870_data *aat2870 = ri->aat2870;
+
+	return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0);
+}
+
+static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
+{
+	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+	struct aat2870_data *aat2870 = ri->aat2870;
+	u8 val;
+	int ret;
+
+	ret = aat2870->read(aat2870, ri->enable_addr, &val);
+	if (ret)
+		return ret;
+
+	return val & ri->enable_mask ? 1 : 0;
+}
+
+static struct regulator_ops aat2870_ldo_ops = {
+	.list_voltage = aat2870_ldo_list_voltage,
+	.set_voltage_sel = aat2870_ldo_set_voltage_sel,
+	.get_voltage_sel = aat2870_ldo_get_voltage_sel,
+	.enable = aat2870_ldo_enable,
+	.disable = aat2870_ldo_disable,
+	.is_enabled = aat2870_ldo_is_enabled,
+};
+
+static const int aat2870_ldo_voltages[] = {
+	1200000, 1300000, 1500000, 1600000,
+	1800000, 2000000, 2200000, 2500000,
+	2600000, 2700000, 2800000, 2900000,
+	3000000, 3100000, 3200000, 3300000,
+};
+
+#define AAT2870_LDO(ids)				\
+	{						\
+		.desc = {				\
+			.name = #ids,			\
+			.id = AAT2870_ID_##ids,		\
+			.n_voltages = ARRAY_SIZE(aat2870_ldo_voltages),	\
+			.ops = &aat2870_ldo_ops,	\
+			.type = REGULATOR_VOLTAGE,	\
+			.owner = THIS_MODULE,		\
+		},					\
+		.voltages = aat2870_ldo_voltages,	\
+		.min_uV = 1200000,			\
+		.max_uV = 3300000,			\
+	}
+
+static struct aat2870_regulator aat2870_regulators[] = {
+	AAT2870_LDO(LDOA),
+	AAT2870_LDO(LDOB),
+	AAT2870_LDO(LDOC),
+	AAT2870_LDO(LDOD),
+};
+
+static struct aat2870_regulator *aat2870_get_regulator(int id)
+{
+	struct aat2870_regulator *ri = NULL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) {
+		ri = &aat2870_regulators[i];
+		if (ri->desc.id == id)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(aat2870_regulators))
+		return NULL;
+
+	ri->enable_addr = AAT2870_LDO_EN;
+	ri->enable_shift = id - AAT2870_ID_LDOA;
+	ri->enable_mask = 0x1 << ri->enable_shift;
+
+	ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ?
+			   AAT2870_LDO_CD : AAT2870_LDO_AB;
+	ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4;
+	ri->voltage_mask = 0xF << ri->voltage_shift;
+
+	return ri;
+}
+
+static int aat2870_regulator_probe(struct platform_device *pdev)
+{
+	struct aat2870_regulator *ri;
+	struct regulator_dev *rdev;
+
+	ri = aat2870_get_regulator(pdev->id);
+	if (!ri) {
+		dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);
+		return -EINVAL;
+	}
+	ri->aat2870 = dev_get_drvdata(pdev->dev.parent);
+
+	rdev = regulator_register(&ri->desc, &pdev->dev,
+				  pdev->dev.platform_data, ri, NULL);
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "Failed to register regulator %s\n",
+			ri->desc.name);
+		return PTR_ERR(rdev);
+	}
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+}
+
+static int __devexit aat2870_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	regulator_unregister(rdev);
+	return 0;
+}
+
+static struct platform_driver aat2870_regulator_driver = {
+	.driver = {
+		.name	= "aat2870-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= aat2870_regulator_probe,
+	.remove	= __devexit_p(aat2870_regulator_remove),
+};
+
+static int __init aat2870_regulator_init(void)
+{
+	return platform_driver_register(&aat2870_regulator_driver);
+}
+subsys_initcall(aat2870_regulator_init);
+
+static void __exit aat2870_regulator_exit(void)
+{
+	platform_driver_unregister(&aat2870_regulator_driver);
+}
+module_exit(aat2870_regulator_exit);
+
+MODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/ab3100.c b/ap/os/linux/linux-3.4.x/drivers/regulator/ab3100.c
new file mode 100644
index 0000000..042271a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/ab3100.c
@@ -0,0 +1,695 @@
+/*
+ * drivers/regulator/ab3100.c
+ *
+ * Copyright (C) 2008-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Low-level control of the AB3100 IC Low Dropout (LDO)
+ * regulators, external regulator and buck converter
+ * Author: Mattias Wallin <mattias.wallin@stericsson.com>
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/abx500.h>
+
+/* LDO registers and some handy masking definitions for AB3100 */
+#define AB3100_LDO_A		0x40
+#define AB3100_LDO_C		0x41
+#define AB3100_LDO_D		0x42
+#define AB3100_LDO_E		0x43
+#define AB3100_LDO_E_SLEEP	0x44
+#define AB3100_LDO_F		0x45
+#define AB3100_LDO_G		0x46
+#define AB3100_LDO_H		0x47
+#define AB3100_LDO_H_SLEEP_MODE	0
+#define AB3100_LDO_H_SLEEP_EN	2
+#define AB3100_LDO_ON		4
+#define AB3100_LDO_H_VSEL_AC	5
+#define AB3100_LDO_K		0x48
+#define AB3100_LDO_EXT		0x49
+#define AB3100_BUCK		0x4A
+#define AB3100_BUCK_SLEEP	0x4B
+#define AB3100_REG_ON_MASK	0x10
+
+/**
+ * struct ab3100_regulator
+ * A struct passed around the individual regulator functions
+ * @platform_device: platform device holding this regulator
+ * @dev: handle to the device
+ * @plfdata: AB3100 platform data passed in at probe time
+ * @regreg: regulator register number in the AB3100
+ * @fixed_voltage: a fixed voltage for this regulator, if this
+ *          0 the voltages array is used instead.
+ * @typ_voltages: an array of available typical voltages for
+ *          this regulator
+ * @voltages_len: length of the array of available voltages
+ */
+struct ab3100_regulator {
+	struct regulator_dev *rdev;
+	struct device *dev;
+	struct ab3100_platform_data *plfdata;
+	u8 regreg;
+	int fixed_voltage;
+	int const *typ_voltages;
+	u8 voltages_len;
+};
+
+/* The order in which registers are initialized */
+static const u8 ab3100_reg_init_order[AB3100_NUM_REGULATORS+2] = {
+	AB3100_LDO_A,
+	AB3100_LDO_C,
+	AB3100_LDO_E,
+	AB3100_LDO_E_SLEEP,
+	AB3100_LDO_F,
+	AB3100_LDO_G,
+	AB3100_LDO_H,
+	AB3100_LDO_K,
+	AB3100_LDO_EXT,
+	AB3100_BUCK,
+	AB3100_BUCK_SLEEP,
+	AB3100_LDO_D,
+};
+
+/* Preset (hardware defined) voltages for these regulators */
+#define LDO_A_VOLTAGE 2750000
+#define LDO_C_VOLTAGE 2650000
+#define LDO_D_VOLTAGE 2650000
+
+static const int ldo_e_buck_typ_voltages[] = {
+	1800000,
+	1400000,
+	1300000,
+	1200000,
+	1100000,
+	1050000,
+	900000,
+};
+
+static const int ldo_f_typ_voltages[] = {
+	1800000,
+	1400000,
+	1300000,
+	1200000,
+	1100000,
+	1050000,
+	2500000,
+	2650000,
+};
+
+static const int ldo_g_typ_voltages[] = {
+	2850000,
+	2750000,
+	1800000,
+	1500000,
+};
+
+static const int ldo_h_typ_voltages[] = {
+	2750000,
+	1800000,
+	1500000,
+	1200000,
+};
+
+static const int ldo_k_typ_voltages[] = {
+	2750000,
+	1800000,
+};
+
+
+/* The regulator devices */
+static struct ab3100_regulator
+ab3100_regulators[AB3100_NUM_REGULATORS] = {
+	{
+		.regreg = AB3100_LDO_A,
+		.fixed_voltage = LDO_A_VOLTAGE,
+	},
+	{
+		.regreg = AB3100_LDO_C,
+		.fixed_voltage = LDO_C_VOLTAGE,
+	},
+	{
+		.regreg = AB3100_LDO_D,
+		.fixed_voltage = LDO_D_VOLTAGE,
+	},
+	{
+		.regreg = AB3100_LDO_E,
+		.typ_voltages = ldo_e_buck_typ_voltages,
+		.voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages),
+	},
+	{
+		.regreg = AB3100_LDO_F,
+		.typ_voltages = ldo_f_typ_voltages,
+		.voltages_len = ARRAY_SIZE(ldo_f_typ_voltages),
+	},
+	{
+		.regreg = AB3100_LDO_G,
+		.typ_voltages = ldo_g_typ_voltages,
+		.voltages_len = ARRAY_SIZE(ldo_g_typ_voltages),
+	},
+	{
+		.regreg = AB3100_LDO_H,
+		.typ_voltages = ldo_h_typ_voltages,
+		.voltages_len = ARRAY_SIZE(ldo_h_typ_voltages),
+	},
+	{
+		.regreg = AB3100_LDO_K,
+		.typ_voltages = ldo_k_typ_voltages,
+		.voltages_len = ARRAY_SIZE(ldo_k_typ_voltages),
+	},
+	{
+		.regreg = AB3100_LDO_EXT,
+		/* No voltages for the external regulator */
+	},
+	{
+		.regreg = AB3100_BUCK,
+		.typ_voltages = ldo_e_buck_typ_voltages,
+		.voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages),
+	},
+};
+
+/*
+ * General functions for enable, disable and is_enabled used for
+ * LDO: A,C,E,F,G,H,K,EXT and BUCK
+ */
+static int ab3100_enable_regulator(struct regulator_dev *reg)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+	int err;
+	u8 regval;
+
+	err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg,
+						&regval);
+	if (err) {
+		dev_warn(&reg->dev, "failed to get regid %d value\n",
+			 abreg->regreg);
+		return err;
+	}
+
+	/* The regulator is already on, no reason to go further */
+	if (regval & AB3100_REG_ON_MASK)
+		return 0;
+
+	regval |= AB3100_REG_ON_MASK;
+
+	err = abx500_set_register_interruptible(abreg->dev, 0, abreg->regreg,
+						regval);
+	if (err) {
+		dev_warn(&reg->dev, "failed to set regid %d value\n",
+			 abreg->regreg);
+		return err;
+	}
+
+	return 0;
+}
+
+static int ab3100_disable_regulator(struct regulator_dev *reg)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+	int err;
+	u8 regval;
+
+	/*
+	 * LDO D is a special regulator. When it is disabled, the entire
+	 * system is shut down. So this is handled specially.
+	 */
+	pr_info("Called ab3100_disable_regulator\n");
+	if (abreg->regreg == AB3100_LDO_D) {
+		dev_info(&reg->dev, "disabling LDO D - shut down system\n");
+		/* Setting LDO D to 0x00 cuts the power to the SoC */
+		return abx500_set_register_interruptible(abreg->dev, 0,
+							 AB3100_LDO_D, 0x00U);
+	}
+
+	/*
+	 * All other regulators are handled here
+	 */
+	err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg,
+						&regval);
+	if (err) {
+		dev_err(&reg->dev, "unable to get register 0x%x\n",
+			abreg->regreg);
+		return err;
+	}
+	regval &= ~AB3100_REG_ON_MASK;
+	return abx500_set_register_interruptible(abreg->dev, 0, abreg->regreg,
+						 regval);
+}
+
+static int ab3100_is_enabled_regulator(struct regulator_dev *reg)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+	u8 regval;
+	int err;
+
+	err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg,
+						&regval);
+	if (err) {
+		dev_err(&reg->dev, "unable to get register 0x%x\n",
+			abreg->regreg);
+		return err;
+	}
+
+	return regval & AB3100_REG_ON_MASK;
+}
+
+static int ab3100_list_voltage_regulator(struct regulator_dev *reg,
+					 unsigned selector)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+
+	if (selector >= abreg->voltages_len)
+		return -EINVAL;
+	return abreg->typ_voltages[selector];
+}
+
+static int ab3100_get_voltage_regulator(struct regulator_dev *reg)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+	u8 regval;
+	int err;
+
+	/* Return the voltage for fixed regulators immediately */
+	if (abreg->fixed_voltage)
+		return abreg->fixed_voltage;
+
+	/*
+	 * For variable types, read out setting and index into
+	 * supplied voltage list.
+	 */
+	err = abx500_get_register_interruptible(abreg->dev, 0,
+						abreg->regreg, &regval);
+	if (err) {
+		dev_warn(&reg->dev,
+			 "failed to get regulator value in register %02x\n",
+			 abreg->regreg);
+		return err;
+	}
+
+	/* The 3 highest bits index voltages */
+	regval &= 0xE0;
+	regval >>= 5;
+
+	if (regval >= abreg->voltages_len) {
+		dev_err(&reg->dev,
+			"regulator register %02x contains an illegal voltage setting\n",
+			abreg->regreg);
+		return -EINVAL;
+	}
+
+	return abreg->typ_voltages[regval];
+}
+
+static int ab3100_get_best_voltage_index(struct regulator_dev *reg,
+				   int min_uV, int max_uV)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+	int i;
+	int bestmatch;
+	int bestindex;
+
+	/*
+	 * Locate the minimum voltage fitting the criteria on
+	 * this regulator. The switchable voltages are not
+	 * in strict falling order so we need to check them
+	 * all for the best match.
+	 */
+	bestmatch = INT_MAX;
+	bestindex = -1;
+	for (i = 0; i < abreg->voltages_len; i++) {
+		if (abreg->typ_voltages[i] <= max_uV &&
+		    abreg->typ_voltages[i] >= min_uV &&
+		    abreg->typ_voltages[i] < bestmatch) {
+			bestmatch = abreg->typ_voltages[i];
+			bestindex = i;
+		}
+	}
+
+	if (bestindex < 0) {
+		dev_warn(&reg->dev, "requested %d<=x<=%d uV, out of range!\n",
+			 min_uV, max_uV);
+		return -EINVAL;
+	}
+	return bestindex;
+}
+
+static int ab3100_set_voltage_regulator(struct regulator_dev *reg,
+					int min_uV, int max_uV,
+					unsigned *selector)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+	u8 regval;
+	int err;
+	int bestindex;
+
+	bestindex = ab3100_get_best_voltage_index(reg, min_uV, max_uV);
+	if (bestindex < 0)
+		return bestindex;
+
+	*selector = bestindex;
+
+	err = abx500_get_register_interruptible(abreg->dev, 0,
+						abreg->regreg, &regval);
+	if (err) {
+		dev_warn(&reg->dev,
+			 "failed to get regulator register %02x\n",
+			 abreg->regreg);
+		return err;
+	}
+
+	/* The highest three bits control the variable regulators */
+	regval &= ~0xE0;
+	regval |= (bestindex << 5);
+
+	err = abx500_set_register_interruptible(abreg->dev, 0,
+						abreg->regreg, regval);
+	if (err)
+		dev_warn(&reg->dev, "failed to set regulator register %02x\n",
+			abreg->regreg);
+
+	return err;
+}
+
+static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg,
+						int uV)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+	u8 regval;
+	int err;
+	int bestindex;
+	u8 targetreg;
+
+	if (abreg->regreg == AB3100_LDO_E)
+		targetreg = AB3100_LDO_E_SLEEP;
+	else if (abreg->regreg == AB3100_BUCK)
+		targetreg = AB3100_BUCK_SLEEP;
+	else
+		return -EINVAL;
+
+	/* LDO E and BUCK have special suspend voltages you can set */
+	bestindex = ab3100_get_best_voltage_index(reg, uV, uV);
+
+	err = abx500_get_register_interruptible(abreg->dev, 0,
+						targetreg, &regval);
+	if (err) {
+		dev_warn(&reg->dev,
+			 "failed to get regulator register %02x\n",
+			 targetreg);
+		return err;
+	}
+
+	/* The highest three bits control the variable regulators */
+	regval &= ~0xE0;
+	regval |= (bestindex << 5);
+
+	err = abx500_set_register_interruptible(abreg->dev, 0,
+						targetreg, regval);
+	if (err)
+		dev_warn(&reg->dev, "failed to set regulator register %02x\n",
+			abreg->regreg);
+
+	return err;
+}
+
+/*
+ * The external regulator can just define a fixed voltage.
+ */
+static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+
+	return abreg->plfdata->external_voltage;
+}
+
+static int ab3100_enable_time_regulator(struct regulator_dev *reg)
+{
+	struct ab3100_regulator *abreg = reg->reg_data;
+
+	/* Per-regulator power on delay from spec */
+	switch (abreg->regreg) {
+	case AB3100_LDO_A: /* Fallthrough */
+	case AB3100_LDO_C: /* Fallthrough */
+	case AB3100_LDO_D: /* Fallthrough */
+	case AB3100_LDO_E: /* Fallthrough */
+	case AB3100_LDO_H: /* Fallthrough */
+	case AB3100_LDO_K:
+		return 200;
+	case AB3100_LDO_F:
+		return 600;
+	case AB3100_LDO_G:
+		return 400;
+	case AB3100_BUCK:
+		return 1000;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static struct regulator_ops regulator_ops_fixed = {
+	.enable      = ab3100_enable_regulator,
+	.disable     = ab3100_disable_regulator,
+	.is_enabled  = ab3100_is_enabled_regulator,
+	.get_voltage = ab3100_get_voltage_regulator,
+	.enable_time = ab3100_enable_time_regulator,
+};
+
+static struct regulator_ops regulator_ops_variable = {
+	.enable      = ab3100_enable_regulator,
+	.disable     = ab3100_disable_regulator,
+	.is_enabled  = ab3100_is_enabled_regulator,
+	.get_voltage = ab3100_get_voltage_regulator,
+	.set_voltage = ab3100_set_voltage_regulator,
+	.list_voltage = ab3100_list_voltage_regulator,
+	.enable_time = ab3100_enable_time_regulator,
+};
+
+static struct regulator_ops regulator_ops_variable_sleepable = {
+	.enable      = ab3100_enable_regulator,
+	.disable     = ab3100_disable_regulator,
+	.is_enabled  = ab3100_is_enabled_regulator,
+	.get_voltage = ab3100_get_voltage_regulator,
+	.set_voltage = ab3100_set_voltage_regulator,
+	.set_suspend_voltage = ab3100_set_suspend_voltage_regulator,
+	.list_voltage = ab3100_list_voltage_regulator,
+	.enable_time = ab3100_enable_time_regulator,
+};
+
+/*
+ * LDO EXT is an external regulator so it is really
+ * not possible to set any voltage locally here, AB3100
+ * is an on/off switch plain an simple. The external
+ * voltage is defined in the board set-up if any.
+ */
+static struct regulator_ops regulator_ops_external = {
+	.enable      = ab3100_enable_regulator,
+	.disable     = ab3100_disable_regulator,
+	.is_enabled  = ab3100_is_enabled_regulator,
+	.get_voltage = ab3100_get_voltage_regulator_external,
+};
+
+static struct regulator_desc
+ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
+	{
+		.name = "LDO_A",
+		.id   = AB3100_LDO_A,
+		.ops  = &regulator_ops_fixed,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO_C",
+		.id   = AB3100_LDO_C,
+		.ops  = &regulator_ops_fixed,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO_D",
+		.id   = AB3100_LDO_D,
+		.ops  = &regulator_ops_fixed,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO_E",
+		.id   = AB3100_LDO_E,
+		.ops  = &regulator_ops_variable_sleepable,
+		.n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO_F",
+		.id   = AB3100_LDO_F,
+		.ops  = &regulator_ops_variable,
+		.n_voltages = ARRAY_SIZE(ldo_f_typ_voltages),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO_G",
+		.id   = AB3100_LDO_G,
+		.ops  = &regulator_ops_variable,
+		.n_voltages = ARRAY_SIZE(ldo_g_typ_voltages),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO_H",
+		.id   = AB3100_LDO_H,
+		.ops  = &regulator_ops_variable,
+		.n_voltages = ARRAY_SIZE(ldo_h_typ_voltages),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO_K",
+		.id   = AB3100_LDO_K,
+		.ops  = &regulator_ops_variable,
+		.n_voltages = ARRAY_SIZE(ldo_k_typ_voltages),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO_EXT",
+		.id   = AB3100_LDO_EXT,
+		.ops  = &regulator_ops_external,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "BUCK",
+		.id   = AB3100_BUCK,
+		.ops  = &regulator_ops_variable_sleepable,
+		.n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+};
+
+/*
+ * NOTE: the following functions are regulators pluralis - it is the
+ * binding to the AB3100 core driver and the parent platform device
+ * for all the different regulators.
+ */
+
+static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
+{
+	struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
+	int err = 0;
+	u8 data;
+	int i;
+
+	/* Check chip state */
+	err = abx500_get_register_interruptible(&pdev->dev, 0,
+						AB3100_LDO_D, &data);
+	if (err) {
+		dev_err(&pdev->dev, "could not read initial status of LDO_D\n");
+		return err;
+	}
+	if (data & 0x10)
+		dev_notice(&pdev->dev,
+			   "chip is already in active mode (Warm start)\n");
+	else
+		dev_notice(&pdev->dev,
+			   "chip is in inactive mode (Cold start)\n");
+
+	/* Set up regulators */
+	for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) {
+		err = abx500_set_register_interruptible(&pdev->dev, 0,
+					ab3100_reg_init_order[i],
+					plfdata->reg_initvals[i]);
+		if (err) {
+			dev_err(&pdev->dev, "regulator initialization failed with error %d\n",
+				err);
+			return err;
+		}
+	}
+
+	/* Register the regulators */
+	for (i = 0; i < AB3100_NUM_REGULATORS; i++) {
+		struct ab3100_regulator *reg = &ab3100_regulators[i];
+		struct regulator_dev *rdev;
+
+		/*
+		 * Initialize per-regulator struct.
+		 * Inherit platform data, this comes down from the
+		 * i2c boarddata, from the machine. So if you want to
+		 * see what it looks like for a certain machine, go
+		 * into the machine I2C setup.
+		 */
+		reg->dev = &pdev->dev;
+		reg->plfdata = plfdata;
+
+		/*
+		 * Register the regulator, pass around
+		 * the ab3100_regulator struct
+		 */
+		rdev = regulator_register(&ab3100_regulator_desc[i],
+					  &pdev->dev,
+					  &plfdata->reg_constraints[i],
+					  reg, NULL);
+
+		if (IS_ERR(rdev)) {
+			err = PTR_ERR(rdev);
+			dev_err(&pdev->dev,
+				"%s: failed to register regulator %s err %d\n",
+				__func__, ab3100_regulator_desc[i].name,
+				err);
+			/* remove the already registered regulators */
+			while (--i >= 0)
+				regulator_unregister(ab3100_regulators[i].rdev);
+			return err;
+		}
+
+		/* Then set a pointer back to the registered regulator */
+		reg->rdev = rdev;
+	}
+
+	return 0;
+}
+
+static int __devexit ab3100_regulators_remove(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < AB3100_NUM_REGULATORS; i++) {
+		struct ab3100_regulator *reg = &ab3100_regulators[i];
+
+		regulator_unregister(reg->rdev);
+	}
+	return 0;
+}
+
+static struct platform_driver ab3100_regulators_driver = {
+	.driver = {
+		.name  = "ab3100-regulators",
+		.owner = THIS_MODULE,
+	},
+	.probe = ab3100_regulators_probe,
+	.remove = __devexit_p(ab3100_regulators_remove),
+};
+
+static __init int ab3100_regulators_init(void)
+{
+	return platform_driver_register(&ab3100_regulators_driver);
+}
+
+static __exit void ab3100_regulators_exit(void)
+{
+	platform_driver_unregister(&ab3100_regulators_driver);
+}
+
+subsys_initcall(ab3100_regulators_init);
+module_exit(ab3100_regulators_exit);
+
+MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
+MODULE_DESCRIPTION("AB3100 Regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ab3100-regulators");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/ab8500.c b/ap/os/linux/linux-3.4.x/drivers/regulator/ab8500.c
new file mode 100644
index 0000000..c7ee4c1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/ab8500.c
@@ -0,0 +1,890 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *          Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * AB8500 peripheral regulators
+ *
+ * AB8500 supports the following regulators:
+ *   VAUX1/2/3, VINTCORE, VTVOUT, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/ab8500.h>
+
+/**
+ * struct ab8500_regulator_info - ab8500 regulator information
+ * @dev: device pointer
+ * @desc: regulator description
+ * @regulator_dev: regulator device
+ * @max_uV: maximum voltage (for variable voltage supplies)
+ * @min_uV: minimum voltage (for variable voltage supplies)
+ * @fixed_uV: typical voltage (for fixed voltage supplies)
+ * @update_bank: bank to control on/off
+ * @update_reg: register to control on/off
+ * @update_mask: mask to enable/disable regulator
+ * @update_val_enable: bits to enable the regulator in normal (high power) mode
+ * @voltage_bank: bank to control regulator voltage
+ * @voltage_reg: register to control regulator voltage
+ * @voltage_mask: mask to control regulator voltage
+ * @voltages: supported voltage table
+ * @voltages_len: number of supported voltages for the regulator
+ * @delay: startup/set voltage delay in us
+ */
+struct ab8500_regulator_info {
+	struct device		*dev;
+	struct regulator_desc	desc;
+	struct regulator_dev	*regulator;
+	int max_uV;
+	int min_uV;
+	int fixed_uV;
+	u8 update_bank;
+	u8 update_reg;
+	u8 update_mask;
+	u8 update_val_enable;
+	u8 voltage_bank;
+	u8 voltage_reg;
+	u8 voltage_mask;
+	int const *voltages;
+	int voltages_len;
+	unsigned int delay;
+};
+
+/* voltage tables for the vauxn/vintcore supplies */
+static const int ldo_vauxn_voltages[] = {
+	1100000,
+	1200000,
+	1300000,
+	1400000,
+	1500000,
+	1800000,
+	1850000,
+	1900000,
+	2500000,
+	2650000,
+	2700000,
+	2750000,
+	2800000,
+	2900000,
+	3000000,
+	3300000,
+};
+
+static const int ldo_vaux3_voltages[] = {
+	1200000,
+	1500000,
+	1800000,
+	2100000,
+	2500000,
+	2750000,
+	2790000,
+	2910000,
+};
+
+static const int ldo_vintcore_voltages[] = {
+	1200000,
+	1225000,
+	1250000,
+	1275000,
+	1300000,
+	1325000,
+	1350000,
+};
+
+static int ab8500_regulator_enable(struct regulator_dev *rdev)
+{
+	int ret;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (info == NULL) {
+		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+		return -EINVAL;
+	}
+
+	ret = abx500_mask_and_set_register_interruptible(info->dev,
+		info->update_bank, info->update_reg,
+		info->update_mask, info->update_val_enable);
+	if (ret < 0)
+		dev_err(rdev_get_dev(rdev),
+			"couldn't set enable bits for regulator\n");
+
+	dev_vdbg(rdev_get_dev(rdev),
+		"%s-enable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+		info->desc.name, info->update_bank, info->update_reg,
+		info->update_mask, info->update_val_enable);
+
+	return ret;
+}
+
+static int ab8500_regulator_disable(struct regulator_dev *rdev)
+{
+	int ret;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (info == NULL) {
+		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+		return -EINVAL;
+	}
+
+	ret = abx500_mask_and_set_register_interruptible(info->dev,
+		info->update_bank, info->update_reg,
+		info->update_mask, 0x0);
+	if (ret < 0)
+		dev_err(rdev_get_dev(rdev),
+			"couldn't set disable bits for regulator\n");
+
+	dev_vdbg(rdev_get_dev(rdev),
+		"%s-disable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+		info->desc.name, info->update_bank, info->update_reg,
+		info->update_mask, 0x0);
+
+	return ret;
+}
+
+static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	int ret;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+	u8 regval;
+
+	if (info == NULL) {
+		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+		return -EINVAL;
+	}
+
+	ret = abx500_get_register_interruptible(info->dev,
+		info->update_bank, info->update_reg, &regval);
+	if (ret < 0) {
+		dev_err(rdev_get_dev(rdev),
+			"couldn't read 0x%x register\n", info->update_reg);
+		return ret;
+	}
+
+	dev_vdbg(rdev_get_dev(rdev),
+		"%s-is_enabled (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
+		" 0x%x\n",
+		info->desc.name, info->update_bank, info->update_reg,
+		info->update_mask, regval);
+
+	if (regval & info->update_mask)
+		return true;
+	else
+		return false;
+}
+
+static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (info == NULL) {
+		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+		return -EINVAL;
+	}
+
+	/* return the uV for the fixed regulators */
+	if (info->fixed_uV)
+		return info->fixed_uV;
+
+	if (selector >= info->voltages_len)
+		return -EINVAL;
+
+	return info->voltages[selector];
+}
+
+static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+	int ret, val;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+	u8 regval;
+
+	if (info == NULL) {
+		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+		return -EINVAL;
+	}
+
+	ret = abx500_get_register_interruptible(info->dev,
+			info->voltage_bank, info->voltage_reg, &regval);
+	if (ret < 0) {
+		dev_err(rdev_get_dev(rdev),
+			"couldn't read voltage reg for regulator\n");
+		return ret;
+	}
+
+	dev_vdbg(rdev_get_dev(rdev),
+		"%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
+		" 0x%x\n",
+		info->desc.name, info->voltage_bank, info->voltage_reg,
+		info->voltage_mask, regval);
+
+	/* vintcore has a different layout */
+	val = regval & info->voltage_mask;
+	if (info->desc.id == AB8500_LDO_INTCORE)
+		return val >> 0x3;
+	else
+		return val;
+}
+
+static int ab8500_get_best_voltage_index(struct regulator_dev *rdev,
+		int min_uV, int max_uV)
+{
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+	int i;
+
+	/* check the supported voltage */
+	for (i = 0; i < info->voltages_len; i++) {
+		if ((info->voltages[i] >= min_uV) &&
+		    (info->voltages[i] <= max_uV))
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
+					int min_uV, int max_uV,
+					unsigned *selector)
+{
+	int ret;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+	u8 regval;
+
+	if (info == NULL) {
+		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+		return -EINVAL;
+	}
+
+	/* get the appropriate voltages within the range */
+	ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
+	if (ret < 0) {
+		dev_err(rdev_get_dev(rdev),
+				"couldn't get best voltage for regulator\n");
+		return ret;
+	}
+
+	*selector = ret;
+
+	/* set the registers for the request */
+	regval = (u8)ret;
+	ret = abx500_mask_and_set_register_interruptible(info->dev,
+			info->voltage_bank, info->voltage_reg,
+			info->voltage_mask, regval);
+	if (ret < 0)
+		dev_err(rdev_get_dev(rdev),
+		"couldn't set voltage reg for regulator\n");
+
+	dev_vdbg(rdev_get_dev(rdev),
+		"%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
+		" 0x%x\n",
+		info->desc.name, info->voltage_bank, info->voltage_reg,
+		info->voltage_mask, regval);
+
+	return ret;
+}
+
+static int ab8500_regulator_enable_time(struct regulator_dev *rdev)
+{
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	return info->delay;
+}
+
+static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+					     unsigned int old_sel,
+					     unsigned int new_sel)
+{
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret;
+
+	/* If the regulator isn't on, it won't take time here */
+	ret = ab8500_regulator_is_enabled(rdev);
+	if (ret < 0)
+		return ret;
+	if (!ret)
+		return 0;
+	return info->delay;
+}
+
+static struct regulator_ops ab8500_regulator_ops = {
+	.enable		= ab8500_regulator_enable,
+	.disable	= ab8500_regulator_disable,
+	.is_enabled	= ab8500_regulator_is_enabled,
+	.get_voltage_sel = ab8500_regulator_get_voltage_sel,
+	.set_voltage	= ab8500_regulator_set_voltage,
+	.list_voltage	= ab8500_list_voltage,
+	.enable_time	= ab8500_regulator_enable_time,
+	.set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
+};
+
+static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
+{
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (info == NULL) {
+		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+		return -EINVAL;
+	}
+
+	return info->fixed_uV;
+}
+
+static struct regulator_ops ab8500_regulator_fixed_ops = {
+	.enable		= ab8500_regulator_enable,
+	.disable	= ab8500_regulator_disable,
+	.is_enabled	= ab8500_regulator_is_enabled,
+	.get_voltage	= ab8500_fixed_get_voltage,
+	.list_voltage	= ab8500_list_voltage,
+	.enable_time	= ab8500_regulator_enable_time,
+	.set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
+};
+
+static struct ab8500_regulator_info
+		ab8500_regulator_info[AB8500_NUM_REGULATORS] = {
+	/*
+	 * Variable Voltage Regulators
+	 *   name, min mV, max mV,
+	 *   update bank, reg, mask, enable val
+	 *   volt bank, reg, mask, table, table length
+	 */
+	[AB8500_LDO_AUX1] = {
+		.desc = {
+			.name		= "LDO-AUX1",
+			.ops		= &ab8500_regulator_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_AUX1,
+			.owner		= THIS_MODULE,
+			.n_voltages	= ARRAY_SIZE(ldo_vauxn_voltages),
+		},
+		.min_uV			= 1100000,
+		.max_uV			= 3300000,
+		.update_bank		= 0x04,
+		.update_reg		= 0x09,
+		.update_mask		= 0x03,
+		.update_val_enable	= 0x01,
+		.voltage_bank		= 0x04,
+		.voltage_reg		= 0x1f,
+		.voltage_mask		= 0x0f,
+		.voltages		= ldo_vauxn_voltages,
+		.voltages_len		= ARRAY_SIZE(ldo_vauxn_voltages),
+	},
+	[AB8500_LDO_AUX2] = {
+		.desc = {
+			.name		= "LDO-AUX2",
+			.ops		= &ab8500_regulator_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_AUX2,
+			.owner		= THIS_MODULE,
+			.n_voltages	= ARRAY_SIZE(ldo_vauxn_voltages),
+		},
+		.min_uV			= 1100000,
+		.max_uV			= 3300000,
+		.update_bank		= 0x04,
+		.update_reg		= 0x09,
+		.update_mask		= 0x0c,
+		.update_val_enable	= 0x04,
+		.voltage_bank		= 0x04,
+		.voltage_reg		= 0x20,
+		.voltage_mask		= 0x0f,
+		.voltages		= ldo_vauxn_voltages,
+		.voltages_len		= ARRAY_SIZE(ldo_vauxn_voltages),
+	},
+	[AB8500_LDO_AUX3] = {
+		.desc = {
+			.name		= "LDO-AUX3",
+			.ops		= &ab8500_regulator_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_AUX3,
+			.owner		= THIS_MODULE,
+			.n_voltages	= ARRAY_SIZE(ldo_vaux3_voltages),
+		},
+		.min_uV			= 1100000,
+		.max_uV			= 3300000,
+		.update_bank		= 0x04,
+		.update_reg		= 0x0a,
+		.update_mask		= 0x03,
+		.update_val_enable	= 0x01,
+		.voltage_bank		= 0x04,
+		.voltage_reg		= 0x21,
+		.voltage_mask		= 0x07,
+		.voltages		= ldo_vaux3_voltages,
+		.voltages_len		= ARRAY_SIZE(ldo_vaux3_voltages),
+	},
+	[AB8500_LDO_INTCORE] = {
+		.desc = {
+			.name		= "LDO-INTCORE",
+			.ops		= &ab8500_regulator_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_INTCORE,
+			.owner		= THIS_MODULE,
+			.n_voltages	= ARRAY_SIZE(ldo_vintcore_voltages),
+		},
+		.min_uV			= 1100000,
+		.max_uV			= 3300000,
+		.update_bank		= 0x03,
+		.update_reg		= 0x80,
+		.update_mask		= 0x44,
+		.update_val_enable	= 0x04,
+		.voltage_bank		= 0x03,
+		.voltage_reg		= 0x80,
+		.voltage_mask		= 0x38,
+		.voltages		= ldo_vintcore_voltages,
+		.voltages_len		= ARRAY_SIZE(ldo_vintcore_voltages),
+	},
+
+	/*
+	 * Fixed Voltage Regulators
+	 *   name, fixed mV,
+	 *   update bank, reg, mask, enable val
+	 */
+	[AB8500_LDO_TVOUT] = {
+		.desc = {
+			.name		= "LDO-TVOUT",
+			.ops		= &ab8500_regulator_fixed_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_TVOUT,
+			.owner		= THIS_MODULE,
+			.n_voltages	= 1,
+		},
+		.delay			= 10000,
+		.fixed_uV		= 2000000,
+		.update_bank		= 0x03,
+		.update_reg		= 0x80,
+		.update_mask		= 0x82,
+		.update_val_enable	= 0x02,
+	},
+	[AB8500_LDO_USB] = {
+		.desc = {
+			.name           = "LDO-USB",
+			.ops            = &ab8500_regulator_fixed_ops,
+			.type           = REGULATOR_VOLTAGE,
+			.id             = AB8500_LDO_USB,
+			.owner          = THIS_MODULE,
+			.n_voltages     = 1,
+		},
+		.fixed_uV               = 3300000,
+		.update_bank            = 0x03,
+		.update_reg             = 0x82,
+		.update_mask            = 0x03,
+		.update_val_enable      = 0x01,
+	},
+	[AB8500_LDO_AUDIO] = {
+		.desc = {
+			.name		= "LDO-AUDIO",
+			.ops		= &ab8500_regulator_fixed_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_AUDIO,
+			.owner		= THIS_MODULE,
+			.n_voltages	= 1,
+		},
+		.fixed_uV		= 2000000,
+		.update_bank		= 0x03,
+		.update_reg		= 0x83,
+		.update_mask		= 0x02,
+		.update_val_enable	= 0x02,
+	},
+	[AB8500_LDO_ANAMIC1] = {
+		.desc = {
+			.name		= "LDO-ANAMIC1",
+			.ops		= &ab8500_regulator_fixed_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_ANAMIC1,
+			.owner		= THIS_MODULE,
+			.n_voltages	= 1,
+		},
+		.fixed_uV		= 2050000,
+		.update_bank		= 0x03,
+		.update_reg		= 0x83,
+		.update_mask		= 0x08,
+		.update_val_enable	= 0x08,
+	},
+	[AB8500_LDO_ANAMIC2] = {
+		.desc = {
+			.name		= "LDO-ANAMIC2",
+			.ops		= &ab8500_regulator_fixed_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_ANAMIC2,
+			.owner		= THIS_MODULE,
+			.n_voltages	= 1,
+		},
+		.fixed_uV		= 2050000,
+		.update_bank		= 0x03,
+		.update_reg		= 0x83,
+		.update_mask		= 0x10,
+		.update_val_enable	= 0x10,
+	},
+	[AB8500_LDO_DMIC] = {
+		.desc = {
+			.name		= "LDO-DMIC",
+			.ops		= &ab8500_regulator_fixed_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_DMIC,
+			.owner		= THIS_MODULE,
+			.n_voltages	= 1,
+		},
+		.fixed_uV		= 1800000,
+		.update_bank		= 0x03,
+		.update_reg		= 0x83,
+		.update_mask		= 0x04,
+		.update_val_enable	= 0x04,
+	},
+	[AB8500_LDO_ANA] = {
+		.desc = {
+			.name		= "LDO-ANA",
+			.ops		= &ab8500_regulator_fixed_ops,
+			.type		= REGULATOR_VOLTAGE,
+			.id		= AB8500_LDO_ANA,
+			.owner		= THIS_MODULE,
+			.n_voltages	= 1,
+		},
+		.fixed_uV		= 1200000,
+		.update_bank		= 0x04,
+		.update_reg		= 0x06,
+		.update_mask		= 0x0c,
+		.update_val_enable	= 0x04,
+	},
+
+
+};
+
+struct ab8500_reg_init {
+	u8 bank;
+	u8 addr;
+	u8 mask;
+};
+
+#define REG_INIT(_id, _bank, _addr, _mask)	\
+	[_id] = {				\
+		.bank = _bank,			\
+		.addr = _addr,			\
+		.mask = _mask,			\
+	}
+
+static struct ab8500_reg_init ab8500_reg_init[] = {
+	/*
+	 * 0x30, VanaRequestCtrl
+	 * 0x0C, VpllRequestCtrl
+	 * 0xc0, VextSupply1RequestCtrl
+	 */
+	REG_INIT(AB8500_REGUREQUESTCTRL2,	0x03, 0x04, 0xfc),
+	/*
+	 * 0x03, VextSupply2RequestCtrl
+	 * 0x0c, VextSupply3RequestCtrl
+	 * 0x30, Vaux1RequestCtrl
+	 * 0xc0, Vaux2RequestCtrl
+	 */
+	REG_INIT(AB8500_REGUREQUESTCTRL3,	0x03, 0x05, 0xff),
+	/*
+	 * 0x03, Vaux3RequestCtrl
+	 * 0x04, SwHPReq
+	 */
+	REG_INIT(AB8500_REGUREQUESTCTRL4,	0x03, 0x06, 0x07),
+	/*
+	 * 0x08, VanaSysClkReq1HPValid
+	 * 0x20, Vaux1SysClkReq1HPValid
+	 * 0x40, Vaux2SysClkReq1HPValid
+	 * 0x80, Vaux3SysClkReq1HPValid
+	 */
+	REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1,	0x03, 0x07, 0xe8),
+	/*
+	 * 0x10, VextSupply1SysClkReq1HPValid
+	 * 0x20, VextSupply2SysClkReq1HPValid
+	 * 0x40, VextSupply3SysClkReq1HPValid
+	 */
+	REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2,	0x03, 0x08, 0x70),
+	/*
+	 * 0x08, VanaHwHPReq1Valid
+	 * 0x20, Vaux1HwHPReq1Valid
+	 * 0x40, Vaux2HwHPReq1Valid
+	 * 0x80, Vaux3HwHPReq1Valid
+	 */
+	REG_INIT(AB8500_REGUHWHPREQ1VALID1,	0x03, 0x09, 0xe8),
+	/*
+	 * 0x01, VextSupply1HwHPReq1Valid
+	 * 0x02, VextSupply2HwHPReq1Valid
+	 * 0x04, VextSupply3HwHPReq1Valid
+	 */
+	REG_INIT(AB8500_REGUHWHPREQ1VALID2,	0x03, 0x0a, 0x07),
+	/*
+	 * 0x08, VanaHwHPReq2Valid
+	 * 0x20, Vaux1HwHPReq2Valid
+	 * 0x40, Vaux2HwHPReq2Valid
+	 * 0x80, Vaux3HwHPReq2Valid
+	 */
+	REG_INIT(AB8500_REGUHWHPREQ2VALID1,	0x03, 0x0b, 0xe8),
+	/*
+	 * 0x01, VextSupply1HwHPReq2Valid
+	 * 0x02, VextSupply2HwHPReq2Valid
+	 * 0x04, VextSupply3HwHPReq2Valid
+	 */
+	REG_INIT(AB8500_REGUHWHPREQ2VALID2,	0x03, 0x0c, 0x07),
+	/*
+	 * 0x20, VanaSwHPReqValid
+	 * 0x80, Vaux1SwHPReqValid
+	 */
+	REG_INIT(AB8500_REGUSWHPREQVALID1,	0x03, 0x0d, 0xa0),
+	/*
+	 * 0x01, Vaux2SwHPReqValid
+	 * 0x02, Vaux3SwHPReqValid
+	 * 0x04, VextSupply1SwHPReqValid
+	 * 0x08, VextSupply2SwHPReqValid
+	 * 0x10, VextSupply3SwHPReqValid
+	 */
+	REG_INIT(AB8500_REGUSWHPREQVALID2,	0x03, 0x0e, 0x1f),
+	/*
+	 * 0x02, SysClkReq2Valid1
+	 * ...
+	 * 0x80, SysClkReq8Valid1
+	 */
+	REG_INIT(AB8500_REGUSYSCLKREQVALID1,	0x03, 0x0f, 0xfe),
+	/*
+	 * 0x02, SysClkReq2Valid2
+	 * ...
+	 * 0x80, SysClkReq8Valid2
+	 */
+	REG_INIT(AB8500_REGUSYSCLKREQVALID2,	0x03, 0x10, 0xfe),
+	/*
+	 * 0x02, VTVoutEna
+	 * 0x04, Vintcore12Ena
+	 * 0x38, Vintcore12Sel
+	 * 0x40, Vintcore12LP
+	 * 0x80, VTVoutLP
+	 */
+	REG_INIT(AB8500_REGUMISC1,		0x03, 0x80, 0xfe),
+	/*
+	 * 0x02, VaudioEna
+	 * 0x04, VdmicEna
+	 * 0x08, Vamic1Ena
+	 * 0x10, Vamic2Ena
+	 */
+	REG_INIT(AB8500_VAUDIOSUPPLY,		0x03, 0x83, 0x1e),
+	/*
+	 * 0x01, Vamic1_dzout
+	 * 0x02, Vamic2_dzout
+	 */
+	REG_INIT(AB8500_REGUCTRL1VAMIC,		0x03, 0x84, 0x03),
+	/*
+	 * 0x0c, VanaRegu
+	 * 0x03, VpllRegu
+	 */
+	REG_INIT(AB8500_VPLLVANAREGU,		0x04, 0x06, 0x0f),
+	/*
+	 * 0x01, VrefDDREna
+	 * 0x02, VrefDDRSleepMode
+	 */
+	REG_INIT(AB8500_VREFDDR,		0x04, 0x07, 0x03),
+	/*
+	 * 0x03, VextSupply1Regu
+	 * 0x0c, VextSupply2Regu
+	 * 0x30, VextSupply3Regu
+	 * 0x40, ExtSupply2Bypass
+	 * 0x80, ExtSupply3Bypass
+	 */
+	REG_INIT(AB8500_EXTSUPPLYREGU,		0x04, 0x08, 0xff),
+	/*
+	 * 0x03, Vaux1Regu
+	 * 0x0c, Vaux2Regu
+	 */
+	REG_INIT(AB8500_VAUX12REGU,		0x04, 0x09, 0x0f),
+	/*
+	 * 0x03, Vaux3Regu
+	 */
+	REG_INIT(AB8500_VRF1VAUX3REGU,		0x04, 0x0a, 0x03),
+	/*
+	 * 0x3f, Vsmps1Sel1
+	 */
+	REG_INIT(AB8500_VSMPS1SEL1,		0x04, 0x13, 0x3f),
+	/*
+	 * 0x0f, Vaux1Sel
+	 */
+	REG_INIT(AB8500_VAUX1SEL,		0x04, 0x1f, 0x0f),
+	/*
+	 * 0x0f, Vaux2Sel
+	 */
+	REG_INIT(AB8500_VAUX2SEL,		0x04, 0x20, 0x0f),
+	/*
+	 * 0x07, Vaux3Sel
+	 */
+	REG_INIT(AB8500_VRF1VAUX3SEL,		0x04, 0x21, 0x07),
+	/*
+	 * 0x01, VextSupply12LP
+	 */
+	REG_INIT(AB8500_REGUCTRL2SPARE,		0x04, 0x22, 0x01),
+	/*
+	 * 0x04, Vaux1Disch
+	 * 0x08, Vaux2Disch
+	 * 0x10, Vaux3Disch
+	 * 0x20, Vintcore12Disch
+	 * 0x40, VTVoutDisch
+	 * 0x80, VaudioDisch
+	 */
+	REG_INIT(AB8500_REGUCTRLDISCH,		0x04, 0x43, 0xfc),
+	/*
+	 * 0x02, VanaDisch
+	 * 0x04, VdmicPullDownEna
+	 * 0x10, VdmicDisch
+	 */
+	REG_INIT(AB8500_REGUCTRLDISCH2,		0x04, 0x44, 0x16),
+};
+
+static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
+{
+	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+	struct ab8500_platform_data *pdata;
+	int i, err;
+
+	if (!ab8500) {
+		dev_err(&pdev->dev, "null mfd parent\n");
+		return -EINVAL;
+	}
+	pdata = dev_get_platdata(ab8500->dev);
+	if (!pdata) {
+		dev_err(&pdev->dev, "null pdata\n");
+		return -EINVAL;
+	}
+
+	/* make sure the platform data has the correct size */
+	if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) {
+		dev_err(&pdev->dev, "Configuration error: size mismatch.\n");
+		return -EINVAL;
+	}
+
+	/* initialize registers */
+	for (i = 0; i < pdata->num_regulator_reg_init; i++) {
+		int id;
+		u8 value;
+
+		id = pdata->regulator_reg_init[i].id;
+		value = pdata->regulator_reg_init[i].value;
+
+		/* check for configuration errors */
+		if (id >= AB8500_NUM_REGULATOR_REGISTERS) {
+			dev_err(&pdev->dev,
+				"Configuration error: id outside range.\n");
+			return -EINVAL;
+		}
+		if (value & ~ab8500_reg_init[id].mask) {
+			dev_err(&pdev->dev,
+				"Configuration error: value outside mask.\n");
+			return -EINVAL;
+		}
+
+		/* initialize register */
+		err = abx500_mask_and_set_register_interruptible(&pdev->dev,
+			ab8500_reg_init[id].bank,
+			ab8500_reg_init[id].addr,
+			ab8500_reg_init[id].mask,
+			value);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+				"Failed to initialize 0x%02x, 0x%02x.\n",
+				ab8500_reg_init[id].bank,
+				ab8500_reg_init[id].addr);
+			return err;
+		}
+		dev_vdbg(&pdev->dev,
+			"  init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
+			ab8500_reg_init[id].bank,
+			ab8500_reg_init[id].addr,
+			ab8500_reg_init[id].mask,
+			value);
+	}
+
+	/* register all regulators */
+	for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+		struct ab8500_regulator_info *info = NULL;
+
+		/* assign per-regulator data */
+		info = &ab8500_regulator_info[i];
+		info->dev = &pdev->dev;
+
+		/* fix for hardware before ab8500v2.0 */
+		if (abx500_get_chip_id(info->dev) < 0x20) {
+			if (info->desc.id == AB8500_LDO_AUX3) {
+				info->desc.n_voltages =
+					ARRAY_SIZE(ldo_vauxn_voltages);
+				info->voltages = ldo_vauxn_voltages;
+				info->voltages_len =
+					ARRAY_SIZE(ldo_vauxn_voltages);
+				info->voltage_mask = 0xf;
+			}
+		}
+
+		/* register regulator with framework */
+		info->regulator = regulator_register(&info->desc, &pdev->dev,
+				&pdata->regulator[i], info, NULL);
+		if (IS_ERR(info->regulator)) {
+			err = PTR_ERR(info->regulator);
+			dev_err(&pdev->dev, "failed to register regulator %s\n",
+					info->desc.name);
+			/* when we fail, un-register all earlier regulators */
+			while (--i >= 0) {
+				info = &ab8500_regulator_info[i];
+				regulator_unregister(info->regulator);
+			}
+			return err;
+		}
+
+		dev_vdbg(rdev_get_dev(info->regulator),
+			"%s-probed\n", info->desc.name);
+	}
+
+	return 0;
+}
+
+static __devexit int ab8500_regulator_remove(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+		struct ab8500_regulator_info *info = NULL;
+		info = &ab8500_regulator_info[i];
+
+		dev_vdbg(rdev_get_dev(info->regulator),
+			"%s-remove\n", info->desc.name);
+
+		regulator_unregister(info->regulator);
+	}
+
+	return 0;
+}
+
+static struct platform_driver ab8500_regulator_driver = {
+	.probe = ab8500_regulator_probe,
+	.remove = __devexit_p(ab8500_regulator_remove),
+	.driver         = {
+		.name   = "ab8500-regulator",
+		.owner  = THIS_MODULE,
+	},
+};
+
+static int __init ab8500_regulator_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&ab8500_regulator_driver);
+	if (ret != 0)
+		pr_err("Failed to register ab8500 regulator: %d\n", ret);
+
+	return ret;
+}
+subsys_initcall(ab8500_regulator_init);
+
+static void __exit ab8500_regulator_exit(void)
+{
+	platform_driver_unregister(&ab8500_regulator_driver);
+}
+module_exit(ab8500_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC");
+MODULE_ALIAS("platform:ab8500-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/ad5398.c b/ap/os/linux/linux-3.4.x/drivers/regulator/ad5398.c
new file mode 100644
index 0000000..26d23ad
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/ad5398.c
@@ -0,0 +1,287 @@
+/*
+ * Voltage and current regulation for AD5398 and AD5821
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define AD5398_CURRENT_EN_MASK	0x8000
+
+struct ad5398_chip_info {
+	struct i2c_client *client;
+	int min_uA;
+	int max_uA;
+	unsigned int current_level;
+	unsigned int current_mask;
+	unsigned int current_offset;
+	struct regulator_dev *rdev;
+};
+
+static int ad5398_calc_current(struct ad5398_chip_info *chip,
+	unsigned selector)
+{
+	unsigned range_uA = chip->max_uA - chip->min_uA;
+
+	return chip->min_uA + (selector * range_uA / chip->current_level);
+}
+
+static int ad5398_read_reg(struct i2c_client *client, unsigned short *data)
+{
+	unsigned short val;
+	int ret;
+
+	ret = i2c_master_recv(client, (char *)&val, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "I2C read error\n");
+		return ret;
+	}
+	*data = be16_to_cpu(val);
+
+	return ret;
+}
+
+static int ad5398_write_reg(struct i2c_client *client, const unsigned short data)
+{
+	unsigned short val;
+	int ret;
+
+	val = cpu_to_be16(data);
+	ret = i2c_master_send(client, (char *)&val, 2);
+	if (ret < 0)
+		dev_err(&client->dev, "I2C write error\n");
+
+	return ret;
+}
+
+static int ad5398_get_current_limit(struct regulator_dev *rdev)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned short data;
+	int ret;
+
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	ret = (data & chip->current_mask) >> chip->current_offset;
+
+	return ad5398_calc_current(chip, ret);
+}
+
+static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned range_uA = chip->max_uA - chip->min_uA;
+	unsigned selector;
+	unsigned short data;
+	int ret;
+
+	if (min_uA > chip->max_uA || min_uA < chip->min_uA)
+		return -EINVAL;
+	if (max_uA > chip->max_uA || max_uA < chip->min_uA)
+		return -EINVAL;
+
+	selector = DIV_ROUND_UP((min_uA - chip->min_uA) * chip->current_level,
+				range_uA);
+	if (ad5398_calc_current(chip, selector) > max_uA)
+		return -EINVAL;
+
+	dev_dbg(&client->dev, "changing current %dmA\n",
+		ad5398_calc_current(chip, selector) / 1000);
+
+	/* read chip enable bit */
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	/* prepare register data */
+	selector = (selector << chip->current_offset) & chip->current_mask;
+	data = (unsigned short)selector | (data & AD5398_CURRENT_EN_MASK);
+
+	/* write the new current value back as well as enable bit */
+	ret = ad5398_write_reg(client, data);
+
+	return ret;
+}
+
+static int ad5398_is_enabled(struct regulator_dev *rdev)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned short data;
+	int ret;
+
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	if (data & AD5398_CURRENT_EN_MASK)
+		return 1;
+	else
+		return 0;
+}
+
+static int ad5398_enable(struct regulator_dev *rdev)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned short data;
+	int ret;
+
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	if (data & AD5398_CURRENT_EN_MASK)
+		return 0;
+
+	data |= AD5398_CURRENT_EN_MASK;
+
+	ret = ad5398_write_reg(client, data);
+
+	return ret;
+}
+
+static int ad5398_disable(struct regulator_dev *rdev)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned short data;
+	int ret;
+
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	if (!(data & AD5398_CURRENT_EN_MASK))
+		return 0;
+
+	data &= ~AD5398_CURRENT_EN_MASK;
+
+	ret = ad5398_write_reg(client, data);
+
+	return ret;
+}
+
+static struct regulator_ops ad5398_ops = {
+	.get_current_limit = ad5398_get_current_limit,
+	.set_current_limit = ad5398_set_current_limit,
+	.enable = ad5398_enable,
+	.disable = ad5398_disable,
+	.is_enabled = ad5398_is_enabled,
+};
+
+static struct regulator_desc ad5398_reg = {
+	.name = "isink",
+	.id = 0,
+	.ops = &ad5398_ops,
+	.type = REGULATOR_CURRENT,
+	.owner = THIS_MODULE,
+};
+
+struct ad5398_current_data_format {
+	int current_bits;
+	int current_offset;
+	int min_uA;
+	int max_uA;
+};
+
+static const struct ad5398_current_data_format df_10_4_120 = {10, 4, 0, 120000};
+
+static const struct i2c_device_id ad5398_id[] = {
+	{ "ad5398", (kernel_ulong_t)&df_10_4_120 },
+	{ "ad5821", (kernel_ulong_t)&df_10_4_120 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad5398_id);
+
+static int __devinit ad5398_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct regulator_init_data *init_data = client->dev.platform_data;
+	struct ad5398_chip_info *chip;
+	const struct ad5398_current_data_format *df =
+			(struct ad5398_current_data_format *)id->driver_data;
+	int ret;
+
+	if (!init_data)
+		return -EINVAL;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->client = client;
+
+	chip->min_uA = df->min_uA;
+	chip->max_uA = df->max_uA;
+	chip->current_level = 1 << df->current_bits;
+	chip->current_offset = df->current_offset;
+	chip->current_mask = (chip->current_level - 1) << chip->current_offset;
+
+	chip->rdev = regulator_register(&ad5398_reg, &client->dev,
+					init_data, chip, NULL);
+	if (IS_ERR(chip->rdev)) {
+		ret = PTR_ERR(chip->rdev);
+		dev_err(&client->dev, "failed to register %s %s\n",
+			id->name, ad5398_reg.name);
+		goto err;
+	}
+
+	i2c_set_clientdata(client, chip);
+	dev_dbg(&client->dev, "%s regulator driver is registered.\n", id->name);
+	return 0;
+
+err:
+	kfree(chip);
+	return ret;
+}
+
+static int __devexit ad5398_remove(struct i2c_client *client)
+{
+	struct ad5398_chip_info *chip = i2c_get_clientdata(client);
+
+	regulator_unregister(chip->rdev);
+	kfree(chip);
+
+	return 0;
+}
+
+static struct i2c_driver ad5398_driver = {
+	.probe = ad5398_probe,
+	.remove = __devexit_p(ad5398_remove),
+	.driver		= {
+		.name	= "ad5398",
+	},
+	.id_table	= ad5398_id,
+};
+
+static int __init ad5398_init(void)
+{
+	return i2c_add_driver(&ad5398_driver);
+}
+subsys_initcall(ad5398_init);
+
+static void __exit ad5398_exit(void)
+{
+	i2c_del_driver(&ad5398_driver);
+}
+module_exit(ad5398_exit);
+
+MODULE_DESCRIPTION("AD5398 and AD5821 current regulator driver");
+MODULE_AUTHOR("Sonic Zhang");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:ad5398-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/anatop-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/anatop-regulator.c
new file mode 100644
index 0000000..81fd606
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/anatop-regulator.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/mfd/anatop.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+struct anatop_regulator {
+	const char *name;
+	u32 control_reg;
+	struct anatop *mfd;
+	int vol_bit_shift;
+	int vol_bit_width;
+	int min_bit_val;
+	int min_voltage;
+	int max_voltage;
+	struct regulator_desc rdesc;
+	struct regulator_init_data *initdata;
+};
+
+static int anatop_set_voltage(struct regulator_dev *reg, int min_uV,
+				  int max_uV, unsigned *selector)
+{
+	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+	u32 val, sel;
+	int uv;
+
+	uv = min_uV;
+	dev_dbg(&reg->dev, "%s: uv %d, min %d, max %d\n", __func__,
+		uv, anatop_reg->min_voltage,
+		anatop_reg->max_voltage);
+
+	if (uv < anatop_reg->min_voltage) {
+		if (max_uV > anatop_reg->min_voltage)
+			uv = anatop_reg->min_voltage;
+		else
+			return -EINVAL;
+	}
+
+	if (!anatop_reg->control_reg)
+		return -ENOTSUPP;
+
+	sel = DIV_ROUND_UP(uv - anatop_reg->min_voltage, 25000);
+	if (sel * 25000 + anatop_reg->min_voltage > anatop_reg->max_voltage)
+		return -EINVAL;
+	val = anatop_reg->min_bit_val + sel;
+	*selector = sel;
+	dev_dbg(&reg->dev, "%s: calculated val %d\n", __func__, val);
+	anatop_set_bits(anatop_reg->mfd,
+			anatop_reg->control_reg,
+			anatop_reg->vol_bit_shift,
+			anatop_reg->vol_bit_width,
+			val);
+
+	return 0;
+}
+
+static int anatop_get_voltage_sel(struct regulator_dev *reg)
+{
+	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+	u32 val;
+
+	if (!anatop_reg->control_reg)
+		return -ENOTSUPP;
+
+	val = anatop_get_bits(anatop_reg->mfd,
+			      anatop_reg->control_reg,
+			      anatop_reg->vol_bit_shift,
+			      anatop_reg->vol_bit_width);
+
+	return val - anatop_reg->min_bit_val;
+}
+
+static int anatop_list_voltage(struct regulator_dev *reg, unsigned selector)
+{
+	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+	int uv;
+
+	uv = anatop_reg->min_voltage + selector * 25000;
+	dev_dbg(&reg->dev, "vddio = %d, selector = %u\n", uv, selector);
+
+	return uv;
+}
+
+static struct regulator_ops anatop_rops = {
+	.set_voltage     = anatop_set_voltage,
+	.get_voltage_sel = anatop_get_voltage_sel,
+	.list_voltage    = anatop_list_voltage,
+};
+
+static int __devinit anatop_regulator_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct regulator_desc *rdesc;
+	struct regulator_dev *rdev;
+	struct anatop_regulator *sreg;
+	struct regulator_init_data *initdata;
+	struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent);
+	int ret = 0;
+
+	initdata = of_get_regulator_init_data(dev, np);
+	sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
+	if (!sreg)
+		return -ENOMEM;
+	sreg->initdata = initdata;
+	sreg->name = kstrdup(of_get_property(np, "regulator-name", NULL),
+			     GFP_KERNEL);
+	rdesc = &sreg->rdesc;
+	memset(rdesc, 0, sizeof(*rdesc));
+	rdesc->name = sreg->name;
+	rdesc->ops = &anatop_rops;
+	rdesc->type = REGULATOR_VOLTAGE;
+	rdesc->owner = THIS_MODULE;
+	sreg->mfd = anatopmfd;
+	ret = of_property_read_u32(np, "anatop-reg-offset",
+				   &sreg->control_reg);
+	if (ret) {
+		dev_err(dev, "no anatop-reg-offset property set\n");
+		goto anatop_probe_end;
+	}
+	ret = of_property_read_u32(np, "anatop-vol-bit-width",
+				   &sreg->vol_bit_width);
+	if (ret) {
+		dev_err(dev, "no anatop-vol-bit-width property set\n");
+		goto anatop_probe_end;
+	}
+	ret = of_property_read_u32(np, "anatop-vol-bit-shift",
+				   &sreg->vol_bit_shift);
+	if (ret) {
+		dev_err(dev, "no anatop-vol-bit-shift property set\n");
+		goto anatop_probe_end;
+	}
+	ret = of_property_read_u32(np, "anatop-min-bit-val",
+				   &sreg->min_bit_val);
+	if (ret) {
+		dev_err(dev, "no anatop-min-bit-val property set\n");
+		goto anatop_probe_end;
+	}
+	ret = of_property_read_u32(np, "anatop-min-voltage",
+				   &sreg->min_voltage);
+	if (ret) {
+		dev_err(dev, "no anatop-min-voltage property set\n");
+		goto anatop_probe_end;
+	}
+	ret = of_property_read_u32(np, "anatop-max-voltage",
+				   &sreg->max_voltage);
+	if (ret) {
+		dev_err(dev, "no anatop-max-voltage property set\n");
+		goto anatop_probe_end;
+	}
+
+	rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage)
+		/ 25000 + 1;
+
+	/* register regulator */
+	rdev = regulator_register(rdesc, dev,
+				  initdata, sreg, pdev->dev.of_node);
+	if (IS_ERR(rdev)) {
+		dev_err(dev, "failed to register %s\n",
+			rdesc->name);
+		ret = PTR_ERR(rdev);
+		goto anatop_probe_end;
+	}
+
+	platform_set_drvdata(pdev, rdev);
+
+anatop_probe_end:
+	if (ret)
+		kfree(sreg->name);
+
+	return ret;
+}
+
+static int __devexit anatop_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct anatop_regulator *sreg = rdev_get_drvdata(rdev);
+	const char *name = sreg->name;
+
+	regulator_unregister(rdev);
+	kfree(name);
+
+	return 0;
+}
+
+static struct of_device_id __devinitdata of_anatop_regulator_match_tbl[] = {
+	{ .compatible = "fsl,anatop-regulator", },
+	{ /* end */ }
+};
+
+static struct platform_driver anatop_regulator_driver = {
+	.driver = {
+		.name	= "anatop_regulator",
+		.owner  = THIS_MODULE,
+		.of_match_table = of_anatop_regulator_match_tbl,
+	},
+	.probe	= anatop_regulator_probe,
+	.remove	= anatop_regulator_remove,
+};
+
+static int __init anatop_regulator_init(void)
+{
+	return platform_driver_register(&anatop_regulator_driver);
+}
+postcore_initcall(anatop_regulator_init);
+
+static void __exit anatop_regulator_exit(void)
+{
+	platform_driver_unregister(&anatop_regulator_driver);
+}
+module_exit(anatop_regulator_exit);
+
+MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>, "
+	      "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
+MODULE_DESCRIPTION("ANATOP Regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/core.c b/ap/os/linux/linux-3.4.x/drivers/regulator/core.c
new file mode 100644
index 0000000..c8f160d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/core.c
@@ -0,0 +1,3302 @@
+/*
+ * core.c  --  Voltage/Current Regulator framework.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ * Copyright 2008 SlimLogic Ltd.
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/async.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/suspend.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/module.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/regulator.h>
+
+#include "dummy.h"
+
+#define rdev_crit(rdev, fmt, ...)					\
+	pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_err(rdev, fmt, ...)					\
+	pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_warn(rdev, fmt, ...)					\
+	pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_info(rdev, fmt, ...)					\
+	pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+#define rdev_dbg(rdev, fmt, ...)					\
+	pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
+
+static DEFINE_MUTEX(regulator_list_mutex);
+static LIST_HEAD(regulator_list);
+static LIST_HEAD(regulator_map_list);
+static bool has_full_constraints;
+static bool board_wants_dummy_regulator;
+
+static struct dentry *debugfs_root;
+
+/*
+ * struct regulator_map
+ *
+ * Used to provide symbolic supply names to devices.
+ */
+struct regulator_map {
+	struct list_head list;
+	const char *dev_name;   /* The dev_name() for the consumer */
+	const char *supply;
+	struct regulator_dev *regulator;
+};
+
+/*
+ * struct regulator
+ *
+ * One for each consumer device.
+ */
+struct regulator {
+	struct device *dev;
+	struct list_head list;
+	int uA_load;
+	int min_uV;
+	int max_uV;
+	char *supply_name;
+	struct device_attribute dev_attr;
+	struct regulator_dev *rdev;
+	struct dentry *debugfs;
+};
+
+static int _regulator_is_enabled(struct regulator_dev *rdev);
+static int _regulator_disable(struct regulator_dev *rdev);
+static int _regulator_get_voltage(struct regulator_dev *rdev);
+static int _regulator_get_current_limit(struct regulator_dev *rdev);
+static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
+static void _notifier_call_chain(struct regulator_dev *rdev,
+				  unsigned long event, void *data);
+static int _regulator_do_set_voltage(struct regulator_dev *rdev,
+				     int min_uV, int max_uV);
+static struct regulator *create_regulator(struct regulator_dev *rdev,
+					  struct device *dev,
+					  const char *supply_name);
+
+static const char *rdev_get_name(struct regulator_dev *rdev)
+{
+	if (rdev->constraints && rdev->constraints->name)
+		return rdev->constraints->name;
+	else if (rdev->desc->name)
+		return rdev->desc->name;
+	else
+		return "";
+}
+
+/* gets the regulator for a given consumer device */
+static struct regulator *get_device_regulator(struct device *dev)
+{
+	struct regulator *regulator = NULL;
+	struct regulator_dev *rdev;
+
+	mutex_lock(&regulator_list_mutex);
+	list_for_each_entry(rdev, &regulator_list, list) {
+		mutex_lock(&rdev->mutex);
+		list_for_each_entry(regulator, &rdev->consumer_list, list) {
+			if (regulator->dev == dev) {
+				mutex_unlock(&rdev->mutex);
+				mutex_unlock(&regulator_list_mutex);
+				return regulator;
+			}
+		}
+		mutex_unlock(&rdev->mutex);
+	}
+	mutex_unlock(&regulator_list_mutex);
+	return NULL;
+}
+
+/**
+ * of_get_regulator - get a regulator device node based on supply name
+ * @dev: Device pointer for the consumer (of regulator) device
+ * @supply: regulator supply name
+ *
+ * Extract the regulator device node corresponding to the supply name.
+ * retruns the device node corresponding to the regulator if found, else
+ * returns NULL.
+ */
+static struct device_node *of_get_regulator(struct device *dev, const char *supply)
+{
+	struct device_node *regnode = NULL;
+	char prop_name[32]; /* 32 is max size of property name */
+
+	dev_dbg(dev, "Looking up %s-supply from device tree\n", supply);
+
+	snprintf(prop_name, 32, "%s-supply", supply);
+	regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+	if (!regnode) {
+		dev_dbg(dev, "Looking up %s property in node %s failed",
+				prop_name, dev->of_node->full_name);
+		return NULL;
+	}
+	return regnode;
+}
+
+/* Platform voltage constraint check */
+static int regulator_check_voltage(struct regulator_dev *rdev,
+				   int *min_uV, int *max_uV)
+{
+	BUG_ON(*min_uV > *max_uV);
+
+	if (!rdev->constraints) {
+		rdev_err(rdev, "no constraints\n");
+		return -ENODEV;
+	}
+	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+		rdev_err(rdev, "operation not allowed\n");
+		return -EPERM;
+	}
+
+	if (*max_uV > rdev->constraints->max_uV)
+		*max_uV = rdev->constraints->max_uV;
+	if (*min_uV < rdev->constraints->min_uV)
+		*min_uV = rdev->constraints->min_uV;
+
+	if (*min_uV > *max_uV) {
+		rdev_err(rdev, "unsupportable voltage range: %d-%duV\n",
+			 *min_uV, *max_uV);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Make sure we select a voltage that suits the needs of all
+ * regulator consumers
+ */
+static int regulator_check_consumers(struct regulator_dev *rdev,
+				     int *min_uV, int *max_uV)
+{
+	struct regulator *regulator;
+
+	list_for_each_entry(regulator, &rdev->consumer_list, list) {
+		/*
+		 * Assume consumers that didn't say anything are OK
+		 * with anything in the constraint range.
+		 */
+		if (!regulator->min_uV && !regulator->max_uV)
+			continue;
+
+		if (*max_uV > regulator->max_uV)
+			*max_uV = regulator->max_uV;
+		if (*min_uV < regulator->min_uV)
+			*min_uV = regulator->min_uV;
+	}
+
+	if (*min_uV > *max_uV)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* current constraint check */
+static int regulator_check_current_limit(struct regulator_dev *rdev,
+					int *min_uA, int *max_uA)
+{
+	BUG_ON(*min_uA > *max_uA);
+
+	if (!rdev->constraints) {
+		rdev_err(rdev, "no constraints\n");
+		return -ENODEV;
+	}
+	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
+		rdev_err(rdev, "operation not allowed\n");
+		return -EPERM;
+	}
+
+	if (*max_uA > rdev->constraints->max_uA)
+		*max_uA = rdev->constraints->max_uA;
+	if (*min_uA < rdev->constraints->min_uA)
+		*min_uA = rdev->constraints->min_uA;
+
+	if (*min_uA > *max_uA) {
+		rdev_err(rdev, "unsupportable current range: %d-%duA\n",
+			 *min_uA, *max_uA);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* operating mode constraint check */
+static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
+{
+	switch (*mode) {
+	case REGULATOR_MODE_FAST:
+	case REGULATOR_MODE_NORMAL:
+	case REGULATOR_MODE_IDLE:
+	case REGULATOR_MODE_STANDBY:
+		break;
+	default:
+		rdev_err(rdev, "invalid mode %x specified\n", *mode);
+		return -EINVAL;
+	}
+
+	if (!rdev->constraints) {
+		rdev_err(rdev, "no constraints\n");
+		return -ENODEV;
+	}
+	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
+		rdev_err(rdev, "operation not allowed\n");
+		return -EPERM;
+	}
+
+	/* The modes are bitmasks, the most power hungry modes having
+	 * the lowest values. If the requested mode isn't supported
+	 * try higher modes. */
+	while (*mode) {
+		if (rdev->constraints->valid_modes_mask & *mode)
+			return 0;
+		*mode /= 2;
+	}
+
+	return -EINVAL;
+}
+
+/* dynamic regulator mode switching constraint check */
+static int regulator_check_drms(struct regulator_dev *rdev)
+{
+	if (!rdev->constraints) {
+		rdev_err(rdev, "no constraints\n");
+		return -ENODEV;
+	}
+	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
+		rdev_err(rdev, "operation not allowed\n");
+		return -EPERM;
+	}
+	return 0;
+}
+
+static ssize_t device_requested_uA_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct regulator *regulator;
+
+	regulator = get_device_regulator(dev);
+	if (regulator == NULL)
+		return 0;
+
+	return sprintf(buf, "%d\n", regulator->uA_load);
+}
+
+static ssize_t regulator_uV_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+	ssize_t ret;
+
+	mutex_lock(&rdev->mutex);
+	ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev));
+	mutex_unlock(&rdev->mutex);
+
+	return ret;
+}
+static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL);
+
+static ssize_t regulator_uA_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
+}
+static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL);
+
+static ssize_t regulator_name_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", rdev_get_name(rdev));
+}
+
+static ssize_t regulator_print_opmode(char *buf, int mode)
+{
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		return sprintf(buf, "fast\n");
+	case REGULATOR_MODE_NORMAL:
+		return sprintf(buf, "normal\n");
+	case REGULATOR_MODE_IDLE:
+		return sprintf(buf, "idle\n");
+	case REGULATOR_MODE_STANDBY:
+		return sprintf(buf, "standby\n");
+	}
+	return sprintf(buf, "unknown\n");
+}
+
+static ssize_t regulator_opmode_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return regulator_print_opmode(buf, _regulator_get_mode(rdev));
+}
+static DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL);
+
+static ssize_t regulator_print_state(char *buf, int state)
+{
+	if (state > 0)
+		return sprintf(buf, "enabled\n");
+	else if (state == 0)
+		return sprintf(buf, "disabled\n");
+	else
+		return sprintf(buf, "unknown\n");
+}
+
+static ssize_t regulator_state_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+	ssize_t ret;
+
+	mutex_lock(&rdev->mutex);
+	ret = regulator_print_state(buf, _regulator_is_enabled(rdev));
+	mutex_unlock(&rdev->mutex);
+
+	return ret;
+}
+static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
+
+static ssize_t regulator_status_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+	int status;
+	char *label;
+
+	status = rdev->desc->ops->get_status(rdev);
+	if (status < 0)
+		return status;
+
+	switch (status) {
+	case REGULATOR_STATUS_OFF:
+		label = "off";
+		break;
+	case REGULATOR_STATUS_ON:
+		label = "on";
+		break;
+	case REGULATOR_STATUS_ERROR:
+		label = "error";
+		break;
+	case REGULATOR_STATUS_FAST:
+		label = "fast";
+		break;
+	case REGULATOR_STATUS_NORMAL:
+		label = "normal";
+		break;
+	case REGULATOR_STATUS_IDLE:
+		label = "idle";
+		break;
+	case REGULATOR_STATUS_STANDBY:
+		label = "standby";
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	return sprintf(buf, "%s\n", label);
+}
+static DEVICE_ATTR(status, 0444, regulator_status_show, NULL);
+
+static ssize_t regulator_min_uA_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	if (!rdev->constraints)
+		return sprintf(buf, "constraint not defined\n");
+
+	return sprintf(buf, "%d\n", rdev->constraints->min_uA);
+}
+static DEVICE_ATTR(min_microamps, 0444, regulator_min_uA_show, NULL);
+
+static ssize_t regulator_max_uA_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	if (!rdev->constraints)
+		return sprintf(buf, "constraint not defined\n");
+
+	return sprintf(buf, "%d\n", rdev->constraints->max_uA);
+}
+static DEVICE_ATTR(max_microamps, 0444, regulator_max_uA_show, NULL);
+
+static ssize_t regulator_min_uV_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	if (!rdev->constraints)
+		return sprintf(buf, "constraint not defined\n");
+
+	return sprintf(buf, "%d\n", rdev->constraints->min_uV);
+}
+static DEVICE_ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL);
+
+static ssize_t regulator_max_uV_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	if (!rdev->constraints)
+		return sprintf(buf, "constraint not defined\n");
+
+	return sprintf(buf, "%d\n", rdev->constraints->max_uV);
+}
+static DEVICE_ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL);
+
+static ssize_t regulator_total_uA_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+	struct regulator *regulator;
+	int uA = 0;
+
+	mutex_lock(&rdev->mutex);
+	list_for_each_entry(regulator, &rdev->consumer_list, list)
+		uA += regulator->uA_load;
+	mutex_unlock(&rdev->mutex);
+	return sprintf(buf, "%d\n", uA);
+}
+static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL);
+
+static ssize_t regulator_num_users_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", rdev->use_count);
+}
+
+static ssize_t regulator_type_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	switch (rdev->desc->type) {
+	case REGULATOR_VOLTAGE:
+		return sprintf(buf, "voltage\n");
+	case REGULATOR_CURRENT:
+		return sprintf(buf, "current\n");
+	}
+	return sprintf(buf, "unknown\n");
+}
+
+static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV);
+}
+static DEVICE_ATTR(suspend_mem_microvolts, 0444,
+		regulator_suspend_mem_uV_show, NULL);
+
+static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV);
+}
+static DEVICE_ATTR(suspend_disk_microvolts, 0444,
+		regulator_suspend_disk_uV_show, NULL);
+
+static ssize_t regulator_suspend_standby_uV_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV);
+}
+static DEVICE_ATTR(suspend_standby_microvolts, 0444,
+		regulator_suspend_standby_uV_show, NULL);
+
+static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return regulator_print_opmode(buf,
+		rdev->constraints->state_mem.mode);
+}
+static DEVICE_ATTR(suspend_mem_mode, 0444,
+		regulator_suspend_mem_mode_show, NULL);
+
+static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return regulator_print_opmode(buf,
+		rdev->constraints->state_disk.mode);
+}
+static DEVICE_ATTR(suspend_disk_mode, 0444,
+		regulator_suspend_disk_mode_show, NULL);
+
+static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return regulator_print_opmode(buf,
+		rdev->constraints->state_standby.mode);
+}
+static DEVICE_ATTR(suspend_standby_mode, 0444,
+		regulator_suspend_standby_mode_show, NULL);
+
+static ssize_t regulator_suspend_mem_state_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return regulator_print_state(buf,
+			rdev->constraints->state_mem.enabled);
+}
+static DEVICE_ATTR(suspend_mem_state, 0444,
+		regulator_suspend_mem_state_show, NULL);
+
+static ssize_t regulator_suspend_disk_state_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return regulator_print_state(buf,
+			rdev->constraints->state_disk.enabled);
+}
+static DEVICE_ATTR(suspend_disk_state, 0444,
+		regulator_suspend_disk_state_show, NULL);
+
+static ssize_t regulator_suspend_standby_state_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+	return regulator_print_state(buf,
+			rdev->constraints->state_standby.enabled);
+}
+static DEVICE_ATTR(suspend_standby_state, 0444,
+		regulator_suspend_standby_state_show, NULL);
+
+
+/*
+ * These are the only attributes are present for all regulators.
+ * Other attributes are a function of regulator functionality.
+ */
+static struct device_attribute regulator_dev_attrs[] = {
+	__ATTR(name, 0444, regulator_name_show, NULL),
+	__ATTR(num_users, 0444, regulator_num_users_show, NULL),
+	__ATTR(type, 0444, regulator_type_show, NULL),
+	__ATTR_NULL,
+};
+
+static void regulator_dev_release(struct device *dev)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+	kfree(rdev);
+}
+
+static struct class regulator_class = {
+	.name = "regulator",
+	.dev_release = regulator_dev_release,
+	.dev_attrs = regulator_dev_attrs,
+};
+
+/* Calculate the new optimum regulator operating mode based on the new total
+ * consumer load. All locks held by caller */
+static void drms_uA_update(struct regulator_dev *rdev)
+{
+	struct regulator *sibling;
+	int current_uA = 0, output_uV, input_uV, err;
+	unsigned int mode;
+
+	err = regulator_check_drms(rdev);
+	if (err < 0 || !rdev->desc->ops->get_optimum_mode ||
+	    (!rdev->desc->ops->get_voltage &&
+	     !rdev->desc->ops->get_voltage_sel) ||
+	    !rdev->desc->ops->set_mode)
+		return;
+
+	/* get output voltage */
+	output_uV = _regulator_get_voltage(rdev);
+	if (output_uV <= 0)
+		return;
+
+	/* get input voltage */
+	input_uV = 0;
+	if (rdev->supply)
+		input_uV = _regulator_get_voltage(rdev);
+	if (input_uV <= 0)
+		input_uV = rdev->constraints->input_uV;
+	if (input_uV <= 0)
+		return;
+
+	/* calc total requested load */
+	list_for_each_entry(sibling, &rdev->consumer_list, list)
+		current_uA += sibling->uA_load;
+
+	/* now get the optimum mode for our new total regulator load */
+	mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV,
+						  output_uV, current_uA);
+
+	/* check the new mode is allowed */
+	err = regulator_mode_constrain(rdev, &mode);
+	if (err == 0)
+		rdev->desc->ops->set_mode(rdev, mode);
+}
+
+static int suspend_set_state(struct regulator_dev *rdev,
+	struct regulator_state *rstate)
+{
+	int ret = 0;
+	bool can_set_state;
+
+	can_set_state = rdev->desc->ops->set_suspend_enable &&
+		rdev->desc->ops->set_suspend_disable;
+
+	/* If we have no suspend mode configration don't set anything;
+	 * only warn if the driver actually makes the suspend mode
+	 * configurable.
+	 */
+	if (!rstate->enabled && !rstate->disabled) {
+		if (can_set_state)
+			rdev_warn(rdev, "No configuration\n");
+		return 0;
+	}
+
+	if (rstate->enabled && rstate->disabled) {
+		rdev_err(rdev, "invalid configuration\n");
+		return -EINVAL;
+	}
+
+	if (!can_set_state) {
+		rdev_err(rdev, "no way to set suspend state\n");
+		return -EINVAL;
+	}
+
+	if (rstate->enabled)
+		ret = rdev->desc->ops->set_suspend_enable(rdev);
+	else
+		ret = rdev->desc->ops->set_suspend_disable(rdev);
+	if (ret < 0) {
+		rdev_err(rdev, "failed to enabled/disable\n");
+		return ret;
+	}
+
+	if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) {
+		ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV);
+		if (ret < 0) {
+			rdev_err(rdev, "failed to set voltage\n");
+			return ret;
+		}
+	}
+
+	if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) {
+		ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode);
+		if (ret < 0) {
+			rdev_err(rdev, "failed to set mode\n");
+			return ret;
+		}
+	}
+	return ret;
+}
+
+/* locks held by caller */
+static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state)
+{
+	if (!rdev->constraints)
+		return -EINVAL;
+
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		return suspend_set_state(rdev,
+			&rdev->constraints->state_standby);
+	case PM_SUSPEND_MEM:
+		return suspend_set_state(rdev,
+			&rdev->constraints->state_mem);
+	case PM_SUSPEND_MAX:
+		return suspend_set_state(rdev,
+			&rdev->constraints->state_disk);
+	default:
+		return -EINVAL;
+	}
+}
+
+static void print_constraints(struct regulator_dev *rdev)
+{
+	struct regulation_constraints *constraints = rdev->constraints;
+	char buf[160] = "";
+	int count = 0;
+	int ret;
+
+	if (constraints->min_uV && constraints->max_uV) {
+		if (constraints->min_uV == constraints->max_uV)
+			count += sprintf(buf + count, "%d mV ",
+					 constraints->min_uV / 1000);
+		else
+			count += sprintf(buf + count, "%d <--> %d mV ",
+					 constraints->min_uV / 1000,
+					 constraints->max_uV / 1000);
+	}
+
+	if (!constraints->min_uV ||
+	    constraints->min_uV != constraints->max_uV) {
+		ret = _regulator_get_voltage(rdev);
+		if (ret > 0)
+			count += sprintf(buf + count, "at %d mV ", ret / 1000);
+	}
+
+	if (constraints->uV_offset)
+		count += sprintf(buf, "%dmV offset ",
+				 constraints->uV_offset / 1000);
+
+	if (constraints->min_uA && constraints->max_uA) {
+		if (constraints->min_uA == constraints->max_uA)
+			count += sprintf(buf + count, "%d mA ",
+					 constraints->min_uA / 1000);
+		else
+			count += sprintf(buf + count, "%d <--> %d mA ",
+					 constraints->min_uA / 1000,
+					 constraints->max_uA / 1000);
+	}
+
+	if (!constraints->min_uA ||
+	    constraints->min_uA != constraints->max_uA) {
+		ret = _regulator_get_current_limit(rdev);
+		if (ret > 0)
+			count += sprintf(buf + count, "at %d mA ", ret / 1000);
+	}
+
+	if (constraints->valid_modes_mask & REGULATOR_MODE_FAST)
+		count += sprintf(buf + count, "fast ");
+	if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL)
+		count += sprintf(buf + count, "normal ");
+	if (constraints->valid_modes_mask & REGULATOR_MODE_IDLE)
+		count += sprintf(buf + count, "idle ");
+	if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
+		count += sprintf(buf + count, "standby");
+
+	rdev_info(rdev, "%s\n", buf);
+
+	if ((constraints->min_uV != constraints->max_uV) &&
+	    !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE))
+		rdev_warn(rdev,
+			  "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n");
+}
+
+static int machine_constraints_voltage(struct regulator_dev *rdev,
+	struct regulation_constraints *constraints)
+{
+	struct regulator_ops *ops = rdev->desc->ops;
+	int ret;
+
+	/* do we need to apply the constraint voltage */
+	if (rdev->constraints->apply_uV &&
+	    rdev->constraints->min_uV == rdev->constraints->max_uV) {
+		ret = _regulator_do_set_voltage(rdev,
+						rdev->constraints->min_uV,
+						rdev->constraints->max_uV);
+		if (ret < 0) {
+			rdev_err(rdev, "failed to apply %duV constraint\n",
+				 rdev->constraints->min_uV);
+			return ret;
+		}
+	}
+
+	/* constrain machine-level voltage specs to fit
+	 * the actual range supported by this regulator.
+	 */
+	if (ops->list_voltage && rdev->desc->n_voltages) {
+		int	count = rdev->desc->n_voltages;
+		int	i;
+		int	min_uV = INT_MAX;
+		int	max_uV = INT_MIN;
+		int	cmin = constraints->min_uV;
+		int	cmax = constraints->max_uV;
+
+		/* it's safe to autoconfigure fixed-voltage supplies
+		   and the constraints are used by list_voltage. */
+		if (count == 1 && !cmin) {
+			cmin = 1;
+			cmax = INT_MAX;
+			constraints->min_uV = cmin;
+			constraints->max_uV = cmax;
+		}
+
+		/* voltage constraints are optional */
+		if ((cmin == 0) && (cmax == 0))
+			return 0;
+
+		/* else require explicit machine-level constraints */
+		if (cmin <= 0 || cmax <= 0 || cmax < cmin) {
+			rdev_err(rdev, "invalid voltage constraints\n");
+			return -EINVAL;
+		}
+
+		/* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
+		for (i = 0; i < count; i++) {
+			int	value;
+
+			value = ops->list_voltage(rdev, i);
+			if (value <= 0)
+				continue;
+
+			/* maybe adjust [min_uV..max_uV] */
+			if (value >= cmin && value < min_uV)
+				min_uV = value;
+			if (value <= cmax && value > max_uV)
+				max_uV = value;
+		}
+
+		/* final: [min_uV..max_uV] valid iff constraints valid */
+		if (max_uV < min_uV) {
+			rdev_err(rdev, "unsupportable voltage constraints\n");
+			return -EINVAL;
+		}
+
+		/* use regulator's subset of machine constraints */
+		if (constraints->min_uV < min_uV) {
+			rdev_dbg(rdev, "override min_uV, %d -> %d\n",
+				 constraints->min_uV, min_uV);
+			constraints->min_uV = min_uV;
+		}
+		if (constraints->max_uV > max_uV) {
+			rdev_dbg(rdev, "override max_uV, %d -> %d\n",
+				 constraints->max_uV, max_uV);
+			constraints->max_uV = max_uV;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * set_machine_constraints - sets regulator constraints
+ * @rdev: regulator source
+ * @constraints: constraints to apply
+ *
+ * Allows platform initialisation code to define and constrain
+ * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE:
+ * Constraints *must* be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current_limit,
+ * set_mode.
+ */
+static int set_machine_constraints(struct regulator_dev *rdev,
+	const struct regulation_constraints *constraints)
+{
+	int ret = 0;
+	struct regulator_ops *ops = rdev->desc->ops;
+
+	if (constraints)
+		rdev->constraints = kmemdup(constraints, sizeof(*constraints),
+					    GFP_KERNEL);
+	else
+		rdev->constraints = kzalloc(sizeof(*constraints),
+					    GFP_KERNEL);
+	if (!rdev->constraints)
+		return -ENOMEM;
+
+	ret = machine_constraints_voltage(rdev, rdev->constraints);
+	if (ret != 0)
+		goto out;
+
+	/* do we need to setup our suspend state */
+	if (rdev->constraints->initial_state) {
+		ret = suspend_prepare(rdev, rdev->constraints->initial_state);
+		if (ret < 0) {
+			rdev_err(rdev, "failed to set suspend state\n");
+			goto out;
+		}
+	}
+
+	if (rdev->constraints->initial_mode) {
+		if (!ops->set_mode) {
+			rdev_err(rdev, "no set_mode operation\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		ret = ops->set_mode(rdev, rdev->constraints->initial_mode);
+		if (ret < 0) {
+			rdev_err(rdev, "failed to set initial mode: %d\n", ret);
+			goto out;
+		}
+	}
+
+	/* If the constraints say the regulator should be on at this point
+	 * and we have control then make sure it is enabled.
+	 */
+	if ((rdev->constraints->always_on || rdev->constraints->boot_on) &&
+	    ops->enable) {
+		ret = ops->enable(rdev);
+		if (ret < 0) {
+			rdev_err(rdev, "failed to enable\n");
+			goto out;
+		}
+	}
+
+	print_constraints(rdev);
+	return 0;
+out:
+	kfree(rdev->constraints);
+	rdev->constraints = NULL;
+	return ret;
+}
+
+/**
+ * set_supply - set regulator supply regulator
+ * @rdev: regulator name
+ * @supply_rdev: supply regulator name
+ *
+ * Called by platform initialisation code to set the supply regulator for this
+ * regulator. This ensures that a regulators supply will also be enabled by the
+ * core if it's child is enabled.
+ */
+static int set_supply(struct regulator_dev *rdev,
+		      struct regulator_dev *supply_rdev)
+{
+	int err;
+
+	rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev));
+
+	rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY");
+	if (rdev->supply == NULL) {
+		err = -ENOMEM;
+		return err;
+	}
+
+	return 0;
+}
+
+/**
+ * set_consumer_device_supply - Bind a regulator to a symbolic supply
+ * @rdev:         regulator source
+ * @consumer_dev_name: dev_name() string for device supply applies to
+ * @supply:       symbolic name for supply
+ *
+ * Allows platform initialisation code to map physical regulator
+ * sources to symbolic names for supplies for use by devices.  Devices
+ * should use these symbolic names to request regulators, avoiding the
+ * need to provide board-specific regulator names as platform data.
+ */
+static int set_consumer_device_supply(struct regulator_dev *rdev,
+				      const char *consumer_dev_name,
+				      const char *supply)
+{
+	struct regulator_map *node;
+	int has_dev;
+
+	if (supply == NULL)
+		return -EINVAL;
+
+	if (consumer_dev_name != NULL)
+		has_dev = 1;
+	else
+		has_dev = 0;
+
+	list_for_each_entry(node, &regulator_map_list, list) {
+		if (node->dev_name && consumer_dev_name) {
+			if (strcmp(node->dev_name, consumer_dev_name) != 0)
+				continue;
+		} else if (node->dev_name || consumer_dev_name) {
+			continue;
+		}
+
+		if (strcmp(node->supply, supply) != 0)
+			continue;
+
+		pr_debug("%s: %s/%s is '%s' supply; fail %s/%s\n",
+			 consumer_dev_name,
+			 dev_name(&node->regulator->dev),
+			 node->regulator->desc->name,
+			 supply,
+			 dev_name(&rdev->dev), rdev_get_name(rdev));
+		return -EBUSY;
+	}
+
+	node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
+	if (node == NULL)
+		return -ENOMEM;
+
+	node->regulator = rdev;
+	node->supply = supply;
+
+	if (has_dev) {
+		node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
+		if (node->dev_name == NULL) {
+			kfree(node);
+			return -ENOMEM;
+		}
+	}
+
+	list_add(&node->list, &regulator_map_list);
+	return 0;
+}
+
+static void unset_regulator_supplies(struct regulator_dev *rdev)
+{
+	struct regulator_map *node, *n;
+
+	list_for_each_entry_safe(node, n, &regulator_map_list, list) {
+		if (rdev == node->regulator) {
+			list_del(&node->list);
+			kfree(node->dev_name);
+			kfree(node);
+		}
+	}
+}
+
+#define REG_STR_SIZE	64
+
+static struct regulator *create_regulator(struct regulator_dev *rdev,
+					  struct device *dev,
+					  const char *supply_name)
+{
+	struct regulator *regulator;
+	char buf[REG_STR_SIZE];
+	int err, size;
+
+	regulator = kzalloc(sizeof(*regulator), GFP_KERNEL);
+	if (regulator == NULL)
+		return NULL;
+
+	mutex_lock(&rdev->mutex);
+	regulator->rdev = rdev;
+	list_add(&regulator->list, &rdev->consumer_list);
+
+	if (dev) {
+		/* create a 'requested_microamps_name' sysfs entry */
+		size = scnprintf(buf, REG_STR_SIZE,
+				 "microamps_requested_%s-%s",
+				 dev_name(dev), supply_name);
+		if (size >= REG_STR_SIZE)
+			goto overflow_err;
+
+		regulator->dev = dev;
+		sysfs_attr_init(&regulator->dev_attr.attr);
+		regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL);
+		if (regulator->dev_attr.attr.name == NULL)
+			goto attr_name_err;
+
+		regulator->dev_attr.attr.mode = 0444;
+		regulator->dev_attr.show = device_requested_uA_show;
+		err = device_create_file(dev, &regulator->dev_attr);
+		if (err < 0) {
+			rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n");
+			goto attr_name_err;
+		}
+
+		/* also add a link to the device sysfs entry */
+		size = scnprintf(buf, REG_STR_SIZE, "%s-%s",
+				 dev->kobj.name, supply_name);
+		if (size >= REG_STR_SIZE)
+			goto attr_err;
+
+		regulator->supply_name = kstrdup(buf, GFP_KERNEL);
+		if (regulator->supply_name == NULL)
+			goto attr_err;
+
+		err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj,
+					buf);
+		if (err) {
+			rdev_warn(rdev, "could not add device link %s err %d\n",
+				  dev->kobj.name, err);
+			goto link_name_err;
+		}
+	} else {
+		regulator->supply_name = kstrdup(supply_name, GFP_KERNEL);
+		if (regulator->supply_name == NULL)
+			goto attr_err;
+	}
+
+	regulator->debugfs = debugfs_create_dir(regulator->supply_name,
+						rdev->debugfs);
+	if (!regulator->debugfs) {
+		rdev_warn(rdev, "Failed to create debugfs directory\n");
+	} else {
+		debugfs_create_u32("uA_load", 0444, regulator->debugfs,
+				   &regulator->uA_load);
+		debugfs_create_u32("min_uV", 0444, regulator->debugfs,
+				   &regulator->min_uV);
+		debugfs_create_u32("max_uV", 0444, regulator->debugfs,
+				   &regulator->max_uV);
+	}
+
+	mutex_unlock(&rdev->mutex);
+	return regulator;
+link_name_err:
+	kfree(regulator->supply_name);
+attr_err:
+	device_remove_file(regulator->dev, &regulator->dev_attr);
+attr_name_err:
+	kfree(regulator->dev_attr.attr.name);
+overflow_err:
+	list_del(&regulator->list);
+	kfree(regulator);
+	mutex_unlock(&rdev->mutex);
+	return NULL;
+}
+
+static int _regulator_get_enable_time(struct regulator_dev *rdev)
+{
+	if (!rdev->desc->ops->enable_time)
+		return 0;
+	return rdev->desc->ops->enable_time(rdev);
+}
+
+static struct regulator_dev *regulator_dev_lookup(struct device *dev,
+							 const char *supply)
+{
+	struct regulator_dev *r;
+	struct device_node *node;
+
+	/* first do a dt based lookup */
+	if (dev && dev->of_node) {
+		node = of_get_regulator(dev, supply);
+		if (node)
+			list_for_each_entry(r, &regulator_list, list)
+				if (r->dev.parent &&
+					node == r->dev.of_node)
+					return r;
+	}
+
+	/* if not found, try doing it non-dt way */
+	list_for_each_entry(r, &regulator_list, list)
+		if (strcmp(rdev_get_name(r), supply) == 0)
+			return r;
+
+	return NULL;
+}
+
+/* Internal regulator request function */
+static struct regulator *_regulator_get(struct device *dev, const char *id,
+					int exclusive)
+{
+	struct regulator_dev *rdev;
+	struct regulator_map *map;
+	struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
+	const char *devname = NULL;
+	int ret;
+
+	if (id == NULL) {
+		pr_err("get() with no identifier\n");
+		return regulator;
+	}
+
+	if (dev)
+		devname = dev_name(dev);
+
+	mutex_lock(&regulator_list_mutex);
+
+	rdev = regulator_dev_lookup(dev, id);
+	if (rdev)
+		goto found;
+
+	list_for_each_entry(map, &regulator_map_list, list) {
+		/* If the mapping has a device set up it must match */
+		if (map->dev_name &&
+		    (!devname || strcmp(map->dev_name, devname)))
+			continue;
+
+		if (strcmp(map->supply, id) == 0) {
+			rdev = map->regulator;
+			goto found;
+		}
+	}
+
+	if (board_wants_dummy_regulator) {
+		rdev = dummy_regulator_rdev;
+		goto found;
+	}
+
+#ifdef CONFIG_REGULATOR_DUMMY
+	if (!devname)
+		devname = "deviceless";
+
+	/* If the board didn't flag that it was fully constrained then
+	 * substitute in a dummy regulator so consumers can continue.
+	 */
+	if (!has_full_constraints) {
+		pr_warn("%s supply %s not found, using dummy regulator\n",
+			devname, id);
+		rdev = dummy_regulator_rdev;
+		goto found;
+	}
+#endif
+
+	mutex_unlock(&regulator_list_mutex);
+	return regulator;
+
+found:
+	if (rdev->exclusive) {
+		regulator = ERR_PTR(-EPERM);
+		goto out;
+	}
+
+	if (exclusive && rdev->open_count) {
+		regulator = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	if (!try_module_get(rdev->owner))
+		goto out;
+
+	regulator = create_regulator(rdev, dev, id);
+	if (regulator == NULL) {
+		regulator = ERR_PTR(-ENOMEM);
+		module_put(rdev->owner);
+		goto out;
+	}
+
+	rdev->open_count++;
+	if (exclusive) {
+		rdev->exclusive = 1;
+
+		ret = _regulator_is_enabled(rdev);
+		if (ret > 0)
+			rdev->use_count = 1;
+		else
+			rdev->use_count = 0;
+	}
+
+out:
+	mutex_unlock(&regulator_list_mutex);
+
+	return regulator;
+}
+
+/**
+ * regulator_get - lookup and obtain a reference to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged.  It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get(struct device *dev, const char *id)
+{
+	return _regulator_get(dev, id, 0);
+}
+EXPORT_SYMBOL_GPL(regulator_get);
+
+static void devm_regulator_release(struct device *dev, void *res)
+{
+	regulator_put(*(struct regulator **)res);
+}
+
+/**
+ * devm_regulator_get - Resource managed regulator_get()
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Managed regulator_get(). Regulators returned from this function are
+ * automatically regulator_put() on driver detach. See regulator_get() for more
+ * information.
+ */
+struct regulator *devm_regulator_get(struct device *dev, const char *id)
+{
+	struct regulator **ptr, *regulator;
+
+	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	regulator = regulator_get(dev, id);
+	if (!IS_ERR(regulator)) {
+		*ptr = regulator;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return regulator;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_get);
+
+/**
+ * regulator_get_exclusive - obtain exclusive access to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno.  Other consumers will be
+ * unable to obtain this reference is held and the use count for the
+ * regulator will be initialised to reflect the current state of the
+ * regulator.
+ *
+ * This is intended for use by consumers which cannot tolerate shared
+ * use of the regulator such as those which need to force the
+ * regulator off for correct operation of the hardware they are
+ * controlling.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged.  It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
+{
+	return _regulator_get(dev, id, 1);
+}
+EXPORT_SYMBOL_GPL(regulator_get_exclusive);
+
+/**
+ * regulator_put - "free" the regulator source
+ * @regulator: regulator source
+ *
+ * Note: drivers must ensure that all regulator_enable calls made on this
+ * regulator source are balanced by regulator_disable calls prior to calling
+ * this function.
+ */
+void regulator_put(struct regulator *regulator)
+{
+	struct regulator_dev *rdev;
+
+	if (regulator == NULL || IS_ERR(regulator))
+		return;
+
+	mutex_lock(&regulator_list_mutex);
+	rdev = regulator->rdev;
+
+	debugfs_remove_recursive(regulator->debugfs);
+
+	/* remove any sysfs entries */
+	if (regulator->dev) {
+		sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
+		device_remove_file(regulator->dev, &regulator->dev_attr);
+		kfree(regulator->dev_attr.attr.name);
+	}
+	mutex_lock(&rdev->mutex);
+	kfree(regulator->supply_name);
+	list_del(&regulator->list);
+	kfree(regulator);
+
+	rdev->open_count--;
+	rdev->exclusive = 0;
+	mutex_unlock(&rdev->mutex);
+
+	module_put(rdev->owner);
+	mutex_unlock(&regulator_list_mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_put);
+
+static int devm_regulator_match(struct device *dev, void *res, void *data)
+{
+	struct regulator **r = res;
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+	return *r == data;
+}
+
+/**
+ * devm_regulator_put - Resource managed regulator_put()
+ * @regulator: regulator to free
+ *
+ * Deallocate a regulator allocated with devm_regulator_get(). Normally
+ * this function will not need to be called and the resource management
+ * code will ensure that the resource is freed.
+ */
+void devm_regulator_put(struct regulator *regulator)
+{
+	int rc;
+
+	rc = devres_destroy(regulator->dev, devm_regulator_release,
+			    devm_regulator_match, regulator);
+	if (rc == 0)
+		regulator_put(regulator);
+	else
+		WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_regulator_put);
+
+static int _regulator_can_change_status(struct regulator_dev *rdev)
+{
+	if (!rdev->constraints)
+		return 0;
+
+	if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
+		return 1;
+	else
+		return 0;
+}
+
+/* locks held by regulator_enable() */
+static int _regulator_enable(struct regulator_dev *rdev)
+{
+	int ret, delay;
+
+	/* check voltage and requested load before enabling */
+	if (rdev->constraints &&
+	    (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
+		drms_uA_update(rdev);
+
+	if (rdev->use_count == 0) {
+		/* The regulator may on if it's not switchable or left on */
+		ret = _regulator_is_enabled(rdev);
+		if (ret == -EINVAL || ret == 0) {
+			if (!_regulator_can_change_status(rdev))
+				return -EPERM;
+
+			if (!rdev->desc->ops->enable)
+				return -EINVAL;
+
+			/* Query before enabling in case configuration
+			 * dependent.  */
+			ret = _regulator_get_enable_time(rdev);
+			if (ret >= 0) {
+				delay = ret;
+			} else {
+				rdev_warn(rdev, "enable_time() failed: %d\n",
+					   ret);
+				delay = 0;
+			}
+
+			trace_regulator_enable(rdev_get_name(rdev));
+
+			/* Allow the regulator to ramp; it would be useful
+			 * to extend this for bulk operations so that the
+			 * regulators can ramp together.  */
+			ret = rdev->desc->ops->enable(rdev);
+			if (ret < 0)
+				return ret;
+
+			trace_regulator_enable_delay(rdev_get_name(rdev));
+
+			if (delay >= 1000) {
+				mdelay(delay / 1000);
+				udelay(delay % 1000);
+			} else if (delay) {
+				udelay(delay);
+			}
+
+			trace_regulator_enable_complete(rdev_get_name(rdev));
+
+		} else if (ret < 0) {
+			rdev_err(rdev, "is_enabled() failed: %d\n", ret);
+			return ret;
+		}
+		/* Fallthrough on positive return values - already enabled */
+	}
+
+	rdev->use_count++;
+
+	return 0;
+}
+
+/**
+ * regulator_enable - enable regulator output
+ * @regulator: regulator source
+ *
+ * Request that the regulator be enabled with the regulator output at
+ * the predefined voltage or current value.  Calls to regulator_enable()
+ * must be balanced with calls to regulator_disable().
+ *
+ * NOTE: the output value can be set by other drivers, boot loader or may be
+ * hardwired in the regulator.
+ */
+int regulator_enable(struct regulator *regulator)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret = 0;
+
+	if (rdev->supply) {
+		ret = regulator_enable(rdev->supply);
+		if (ret != 0)
+			return ret;
+	}
+
+	mutex_lock(&rdev->mutex);
+	ret = _regulator_enable(rdev);
+	mutex_unlock(&rdev->mutex);
+
+	if (ret != 0 && rdev->supply)
+		regulator_disable(rdev->supply);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_enable);
+
+/* locks held by regulator_disable() */
+static int _regulator_disable(struct regulator_dev *rdev)
+{
+	int ret = 0;
+
+	if (WARN(rdev->use_count <= 0,
+		 "unbalanced disables for %s\n", rdev_get_name(rdev)))
+		return -EIO;
+
+	/* are we the last user and permitted to disable ? */
+	if (rdev->use_count == 1 &&
+	    (rdev->constraints && !rdev->constraints->always_on)) {
+
+		/* we are last user */
+		if (_regulator_can_change_status(rdev) &&
+		    rdev->desc->ops->disable) {
+			trace_regulator_disable(rdev_get_name(rdev));
+
+			ret = rdev->desc->ops->disable(rdev);
+			if (ret < 0) {
+				rdev_err(rdev, "failed to disable\n");
+				return ret;
+			}
+
+			trace_regulator_disable_complete(rdev_get_name(rdev));
+
+			_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+					     NULL);
+		}
+
+		rdev->use_count = 0;
+	} else if (rdev->use_count > 1) {
+
+		if (rdev->constraints &&
+			(rdev->constraints->valid_ops_mask &
+			REGULATOR_CHANGE_DRMS))
+			drms_uA_update(rdev);
+
+		rdev->use_count--;
+	}
+
+	return ret;
+}
+
+/**
+ * regulator_disable - disable regulator output
+ * @regulator: regulator source
+ *
+ * Disable the regulator output voltage or current.  Calls to
+ * regulator_enable() must be balanced with calls to
+ * regulator_disable().
+ *
+ * NOTE: this will only disable the regulator output if no other consumer
+ * devices have it enabled, the regulator device supports disabling and
+ * machine constraints permit this operation.
+ */
+int regulator_disable(struct regulator *regulator)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret = 0;
+
+	mutex_lock(&rdev->mutex);
+	ret = _regulator_disable(rdev);
+	mutex_unlock(&rdev->mutex);
+
+	if (ret == 0 && rdev->supply)
+		regulator_disable(rdev->supply);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_disable);
+
+/* locks held by regulator_force_disable() */
+static int _regulator_force_disable(struct regulator_dev *rdev)
+{
+	int ret = 0;
+
+	/* force disable */
+	if (rdev->desc->ops->disable) {
+		/* ah well, who wants to live forever... */
+		ret = rdev->desc->ops->disable(rdev);
+		if (ret < 0) {
+			rdev_err(rdev, "failed to force disable\n");
+			return ret;
+		}
+		/* notify other consumers that power has been forced off */
+		_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
+			REGULATOR_EVENT_DISABLE, NULL);
+	}
+
+	return ret;
+}
+
+/**
+ * regulator_force_disable - force disable regulator output
+ * @regulator: regulator source
+ *
+ * Forcibly disable the regulator output voltage or current.
+ * NOTE: this *will* disable the regulator output even if other consumer
+ * devices have it enabled. This should be used for situations when device
+ * damage will likely occur if the regulator is not disabled (e.g. over temp).
+ */
+int regulator_force_disable(struct regulator *regulator)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret;
+
+	mutex_lock(&rdev->mutex);
+	regulator->uA_load = 0;
+	ret = _regulator_force_disable(regulator->rdev);
+	mutex_unlock(&rdev->mutex);
+
+	if (rdev->supply)
+		while (rdev->open_count--)
+			regulator_disable(rdev->supply);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_force_disable);
+
+static void regulator_disable_work(struct work_struct *work)
+{
+	struct regulator_dev *rdev = container_of(work, struct regulator_dev,
+						  disable_work.work);
+	int count, i, ret;
+
+	mutex_lock(&rdev->mutex);
+
+	BUG_ON(!rdev->deferred_disables);
+
+	count = rdev->deferred_disables;
+	rdev->deferred_disables = 0;
+
+	for (i = 0; i < count; i++) {
+		ret = _regulator_disable(rdev);
+		if (ret != 0)
+			rdev_err(rdev, "Deferred disable failed: %d\n", ret);
+	}
+
+	mutex_unlock(&rdev->mutex);
+
+	if (rdev->supply) {
+		for (i = 0; i < count; i++) {
+			ret = regulator_disable(rdev->supply);
+			if (ret != 0) {
+				rdev_err(rdev,
+					 "Supply disable failed: %d\n", ret);
+			}
+		}
+	}
+}
+
+/**
+ * regulator_disable_deferred - disable regulator output with delay
+ * @regulator: regulator source
+ * @ms: miliseconds until the regulator is disabled
+ *
+ * Execute regulator_disable() on the regulator after a delay.  This
+ * is intended for use with devices that require some time to quiesce.
+ *
+ * NOTE: this will only disable the regulator output if no other consumer
+ * devices have it enabled, the regulator device supports disabling and
+ * machine constraints permit this operation.
+ */
+int regulator_disable_deferred(struct regulator *regulator, int ms)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret;
+
+	mutex_lock(&rdev->mutex);
+	rdev->deferred_disables++;
+	mutex_unlock(&rdev->mutex);
+
+	ret = schedule_delayed_work(&rdev->disable_work,
+				    msecs_to_jiffies(ms));
+	if (ret < 0)
+		return ret;
+	else
+		return 0;
+}
+EXPORT_SYMBOL_GPL(regulator_disable_deferred);
+
+static int _regulator_is_enabled(struct regulator_dev *rdev)
+{
+	/* If we don't know then assume that the regulator is always on */
+	if (!rdev->desc->ops->is_enabled)
+		return 1;
+
+	return rdev->desc->ops->is_enabled(rdev);
+}
+
+/**
+ * regulator_is_enabled - is the regulator output enabled
+ * @regulator: regulator source
+ *
+ * Returns positive if the regulator driver backing the source/client
+ * has requested that the device be enabled, zero if it hasn't, else a
+ * negative errno code.
+ *
+ * Note that the device backing this regulator handle can have multiple
+ * users, so it might be enabled even if regulator_enable() was never
+ * called for this particular source.
+ */
+int regulator_is_enabled(struct regulator *regulator)
+{
+	int ret;
+
+	mutex_lock(&regulator->rdev->mutex);
+	ret = _regulator_is_enabled(regulator->rdev);
+	mutex_unlock(&regulator->rdev->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_is_enabled);
+
+/**
+ * regulator_count_voltages - count regulator_list_voltage() selectors
+ * @regulator: regulator source
+ *
+ * Returns number of selectors, or negative errno.  Selectors are
+ * numbered starting at zero, and typically correspond to bitfields
+ * in hardware registers.
+ */
+int regulator_count_voltages(struct regulator *regulator)
+{
+	struct regulator_dev	*rdev = regulator->rdev;
+
+	return rdev->desc->n_voltages ? : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_count_voltages);
+
+/**
+ * regulator_list_voltage - enumerate supported voltages
+ * @regulator: regulator source
+ * @selector: identify voltage to list
+ * Context: can sleep
+ *
+ * Returns a voltage that can be passed to @regulator_set_voltage(),
+ * zero if this selector code can't be used on this system, or a
+ * negative errno.
+ */
+int regulator_list_voltage(struct regulator *regulator, unsigned selector)
+{
+	struct regulator_dev	*rdev = regulator->rdev;
+	struct regulator_ops	*ops = rdev->desc->ops;
+	int			ret;
+
+	if (!ops->list_voltage || selector >= rdev->desc->n_voltages)
+		return -EINVAL;
+
+	mutex_lock(&rdev->mutex);
+	ret = ops->list_voltage(rdev, selector);
+	mutex_unlock(&rdev->mutex);
+
+	if (ret > 0) {
+		if (ret < rdev->constraints->min_uV)
+			ret = 0;
+		else if (ret > rdev->constraints->max_uV)
+			ret = 0;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage);
+
+/**
+ * regulator_is_supported_voltage - check if a voltage range can be supported
+ *
+ * @regulator: Regulator to check.
+ * @min_uV: Minimum required voltage in uV.
+ * @max_uV: Maximum required voltage in uV.
+ *
+ * Returns a boolean or a negative error code.
+ */
+int regulator_is_supported_voltage(struct regulator *regulator,
+				   int min_uV, int max_uV)
+{
+	int i, voltages, ret;
+
+	ret = regulator_count_voltages(regulator);
+	if (ret < 0)
+		return ret;
+	voltages = ret;
+
+	for (i = 0; i < voltages; i++) {
+		ret = regulator_list_voltage(regulator, i);
+
+		if (ret >= min_uV && ret <= max_uV)
+			return 1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(regulator_is_supported_voltage);
+
+static int _regulator_do_set_voltage(struct regulator_dev *rdev,
+				     int min_uV, int max_uV)
+{
+	int ret;
+	int delay = 0;
+	unsigned int selector;
+
+	trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
+
+	min_uV += rdev->constraints->uV_offset;
+	max_uV += rdev->constraints->uV_offset;
+
+	if (rdev->desc->ops->set_voltage) {
+		ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
+						   &selector);
+
+		if (rdev->desc->ops->list_voltage)
+			selector = rdev->desc->ops->list_voltage(rdev,
+								 selector);
+		else
+			selector = -1;
+	} else if (rdev->desc->ops->set_voltage_sel) {
+		int best_val = INT_MAX;
+		int i;
+
+		selector = 0;
+
+		/* Find the smallest voltage that falls within the specified
+		 * range.
+		 */
+		for (i = 0; i < rdev->desc->n_voltages; i++) {
+			ret = rdev->desc->ops->list_voltage(rdev, i);
+			if (ret < 0)
+				continue;
+
+			if (ret < best_val && ret >= min_uV && ret <= max_uV) {
+				best_val = ret;
+				selector = i;
+			}
+		}
+
+		/*
+		 * If we can't obtain the old selector there is not enough
+		 * info to call set_voltage_time_sel().
+		 */
+		if (rdev->desc->ops->set_voltage_time_sel &&
+		    rdev->desc->ops->get_voltage_sel) {
+			unsigned int old_selector = 0;
+
+			ret = rdev->desc->ops->get_voltage_sel(rdev);
+			if (ret < 0)
+				return ret;
+			old_selector = ret;
+			ret = rdev->desc->ops->set_voltage_time_sel(rdev,
+						old_selector, selector);
+			if (ret < 0)
+				rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", ret);
+			else
+				delay = ret;
+		}
+
+		if (best_val != INT_MAX) {
+			ret = rdev->desc->ops->set_voltage_sel(rdev, selector);
+			selector = best_val;
+		} else {
+			ret = -EINVAL;
+		}
+	} else {
+		ret = -EINVAL;
+	}
+
+	/* Insert any necessary delays */
+	if (delay >= 1000) {
+		mdelay(delay / 1000);
+		udelay(delay % 1000);
+	} else if (delay) {
+		udelay(delay);
+	}
+
+	if (ret == 0)
+		_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
+				     NULL);
+
+	trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector);
+
+	return ret;
+}
+
+/**
+ * regulator_set_voltage - set regulator output voltage
+ * @regulator: regulator source
+ * @min_uV: Minimum required voltage in uV
+ * @max_uV: Maximum acceptable voltage in uV
+ *
+ * Sets a voltage regulator to the desired output voltage. This can be set
+ * during any regulator state. IOW, regulator can be disabled or enabled.
+ *
+ * If the regulator is enabled then the voltage will change to the new value
+ * immediately otherwise if the regulator is disabled the regulator will
+ * output at the new voltage when enabled.
+ *
+ * NOTE: If the regulator is shared between several devices then the lowest
+ * request voltage that meets the system constraints will be used.
+ * Regulator system constraints must be set for this regulator before
+ * calling this function otherwise this call will fail.
+ */
+int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret = 0;
+
+	mutex_lock(&rdev->mutex);
+
+	/* If we're setting the same range as last time the change
+	 * should be a noop (some cpufreq implementations use the same
+	 * voltage for multiple frequencies, for example).
+	 */
+	if (regulator->min_uV == min_uV && regulator->max_uV == max_uV)
+		goto out;
+
+	/* sanity check */
+	if (!rdev->desc->ops->set_voltage &&
+	    !rdev->desc->ops->set_voltage_sel) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* constraints check */
+	ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
+	if (ret < 0)
+		goto out;
+	regulator->min_uV = min_uV;
+	regulator->max_uV = max_uV;
+
+	ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
+	if (ret < 0)
+		goto out;
+
+	ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
+
+out:
+	mutex_unlock(&rdev->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage);
+
+/**
+ * regulator_set_voltage_time - get raise/fall time
+ * @regulator: regulator source
+ * @old_uV: starting voltage in microvolts
+ * @new_uV: target voltage in microvolts
+ *
+ * Provided with the starting and ending voltage, this function attempts to
+ * calculate the time in microseconds required to rise or fall to this new
+ * voltage.
+ */
+int regulator_set_voltage_time(struct regulator *regulator,
+			       int old_uV, int new_uV)
+{
+	struct regulator_dev	*rdev = regulator->rdev;
+	struct regulator_ops	*ops = rdev->desc->ops;
+	int old_sel = -1;
+	int new_sel = -1;
+	int voltage;
+	int i;
+
+	/* Currently requires operations to do this */
+	if (!ops->list_voltage || !ops->set_voltage_time_sel
+	    || !rdev->desc->n_voltages)
+		return -EINVAL;
+
+	for (i = 0; i < rdev->desc->n_voltages; i++) {
+		/* We only look for exact voltage matches here */
+		voltage = regulator_list_voltage(regulator, i);
+		if (voltage < 0)
+			return -EINVAL;
+		if (voltage == 0)
+			continue;
+		if (voltage == old_uV)
+			old_sel = i;
+		if (voltage == new_uV)
+			new_sel = i;
+	}
+
+	if (old_sel < 0 || new_sel < 0)
+		return -EINVAL;
+
+	return ops->set_voltage_time_sel(rdev, old_sel, new_sel);
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
+
+/**
+ * regulator_sync_voltage - re-apply last regulator output voltage
+ * @regulator: regulator source
+ *
+ * Re-apply the last configured voltage.  This is intended to be used
+ * where some external control source the consumer is cooperating with
+ * has caused the configured voltage to change.
+ */
+int regulator_sync_voltage(struct regulator *regulator)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret, min_uV, max_uV;
+
+	mutex_lock(&rdev->mutex);
+
+	if (!rdev->desc->ops->set_voltage &&
+	    !rdev->desc->ops->set_voltage_sel) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* This is only going to work if we've had a voltage configured. */
+	if (!regulator->min_uV && !regulator->max_uV) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	min_uV = regulator->min_uV;
+	max_uV = regulator->max_uV;
+
+	/* This should be a paranoia check... */
+	ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
+	if (ret < 0)
+		goto out;
+
+	ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
+	if (ret < 0)
+		goto out;
+
+	ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
+
+out:
+	mutex_unlock(&rdev->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_sync_voltage);
+
+static int _regulator_get_voltage(struct regulator_dev *rdev)
+{
+	int sel, ret;
+
+	if (rdev->desc->ops->get_voltage_sel) {
+		sel = rdev->desc->ops->get_voltage_sel(rdev);
+		if (sel < 0)
+			return sel;
+		ret = rdev->desc->ops->list_voltage(rdev, sel);
+	} else if (rdev->desc->ops->get_voltage) {
+		ret = rdev->desc->ops->get_voltage(rdev);
+	} else {
+		return -EINVAL;
+	}
+
+	if (ret < 0)
+		return ret;
+	return ret - rdev->constraints->uV_offset;
+}
+
+/**
+ * regulator_get_voltage - get regulator output voltage
+ * @regulator: regulator source
+ *
+ * This returns the current regulator voltage in uV.
+ *
+ * NOTE: If the regulator is disabled it will return the voltage value. This
+ * function should not be used to determine regulator state.
+ */
+int regulator_get_voltage(struct regulator *regulator)
+{
+	int ret;
+
+	mutex_lock(&regulator->rdev->mutex);
+
+	ret = _regulator_get_voltage(regulator->rdev);
+
+	mutex_unlock(&regulator->rdev->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage);
+
+/**
+ * regulator_set_current_limit - set regulator output current limit
+ * @regulator: regulator source
+ * @min_uA: Minimuum supported current in uA
+ * @max_uA: Maximum supported current in uA
+ *
+ * Sets current sink to the desired output current. This can be set during
+ * any regulator state. IOW, regulator can be disabled or enabled.
+ *
+ * If the regulator is enabled then the current will change to the new value
+ * immediately otherwise if the regulator is disabled the regulator will
+ * output at the new current when enabled.
+ *
+ * NOTE: Regulator system constraints must be set for this regulator before
+ * calling this function otherwise this call will fail.
+ */
+int regulator_set_current_limit(struct regulator *regulator,
+			       int min_uA, int max_uA)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret;
+
+	mutex_lock(&rdev->mutex);
+
+	/* sanity check */
+	if (!rdev->desc->ops->set_current_limit) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* constraints check */
+	ret = regulator_check_current_limit(rdev, &min_uA, &max_uA);
+	if (ret < 0)
+		goto out;
+
+	ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA);
+out:
+	mutex_unlock(&rdev->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_current_limit);
+
+static int _regulator_get_current_limit(struct regulator_dev *rdev)
+{
+	int ret;
+
+	mutex_lock(&rdev->mutex);
+
+	/* sanity check */
+	if (!rdev->desc->ops->get_current_limit) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = rdev->desc->ops->get_current_limit(rdev);
+out:
+	mutex_unlock(&rdev->mutex);
+	return ret;
+}
+
+/**
+ * regulator_get_current_limit - get regulator output current
+ * @regulator: regulator source
+ *
+ * This returns the current supplied by the specified current sink in uA.
+ *
+ * NOTE: If the regulator is disabled it will return the current value. This
+ * function should not be used to determine regulator state.
+ */
+int regulator_get_current_limit(struct regulator *regulator)
+{
+	return _regulator_get_current_limit(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_get_current_limit);
+
+/**
+ * regulator_set_mode - set regulator operating mode
+ * @regulator: regulator source
+ * @mode: operating mode - one of the REGULATOR_MODE constants
+ *
+ * Set regulator operating mode to increase regulator efficiency or improve
+ * regulation performance.
+ *
+ * NOTE: Regulator system constraints must be set for this regulator before
+ * calling this function otherwise this call will fail.
+ */
+int regulator_set_mode(struct regulator *regulator, unsigned int mode)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret;
+	int regulator_curr_mode;
+
+	mutex_lock(&rdev->mutex);
+
+	/* sanity check */
+	if (!rdev->desc->ops->set_mode) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* return if the same mode is requested */
+	if (rdev->desc->ops->get_mode) {
+		regulator_curr_mode = rdev->desc->ops->get_mode(rdev);
+		if (regulator_curr_mode == mode) {
+			ret = 0;
+			goto out;
+		}
+	}
+
+	/* constraints check */
+	ret = regulator_mode_constrain(rdev, &mode);
+	if (ret < 0)
+		goto out;
+
+	ret = rdev->desc->ops->set_mode(rdev, mode);
+out:
+	mutex_unlock(&rdev->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_mode);
+
+static unsigned int _regulator_get_mode(struct regulator_dev *rdev)
+{
+	int ret;
+
+	mutex_lock(&rdev->mutex);
+
+	/* sanity check */
+	if (!rdev->desc->ops->get_mode) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = rdev->desc->ops->get_mode(rdev);
+out:
+	mutex_unlock(&rdev->mutex);
+	return ret;
+}
+
+/**
+ * regulator_get_mode - get regulator operating mode
+ * @regulator: regulator source
+ *
+ * Get the current regulator operating mode.
+ */
+unsigned int regulator_get_mode(struct regulator *regulator)
+{
+	return _regulator_get_mode(regulator->rdev);
+}
+EXPORT_SYMBOL_GPL(regulator_get_mode);
+
+/**
+ * regulator_set_optimum_mode - set regulator optimum operating mode
+ * @regulator: regulator source
+ * @uA_load: load current
+ *
+ * Notifies the regulator core of a new device load. This is then used by
+ * DRMS (if enabled by constraints) to set the most efficient regulator
+ * operating mode for the new regulator loading.
+ *
+ * Consumer devices notify their supply regulator of the maximum power
+ * they will require (can be taken from device datasheet in the power
+ * consumption tables) when they change operational status and hence power
+ * state. Examples of operational state changes that can affect power
+ * consumption are :-
+ *
+ *    o Device is opened / closed.
+ *    o Device I/O is about to begin or has just finished.
+ *    o Device is idling in between work.
+ *
+ * This information is also exported via sysfs to userspace.
+ *
+ * DRMS will sum the total requested load on the regulator and change
+ * to the most efficient operating mode if platform constraints allow.
+ *
+ * Returns the new regulator mode or error.
+ */
+int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	struct regulator *consumer;
+	int ret, output_uV, input_uV, total_uA_load = 0;
+	unsigned int mode;
+
+	mutex_lock(&rdev->mutex);
+
+	/*
+	 * first check to see if we can set modes at all, otherwise just
+	 * tell the consumer everything is OK.
+	 */
+	regulator->uA_load = uA_load;
+	ret = regulator_check_drms(rdev);
+	if (ret < 0) {
+		ret = 0;
+		goto out;
+	}
+
+	if (!rdev->desc->ops->get_optimum_mode)
+		goto out;
+
+	/*
+	 * we can actually do this so any errors are indicators of
+	 * potential real failure.
+	 */
+	ret = -EINVAL;
+
+	/* get output voltage */
+	output_uV = _regulator_get_voltage(rdev);
+	if (output_uV <= 0) {
+		rdev_err(rdev, "invalid output voltage found\n");
+		goto out;
+	}
+
+	/* get input voltage */
+	input_uV = 0;
+	if (rdev->supply)
+		input_uV = regulator_get_voltage(rdev->supply);
+	if (input_uV <= 0)
+		input_uV = rdev->constraints->input_uV;
+	if (input_uV <= 0) {
+		rdev_err(rdev, "invalid input voltage found\n");
+		goto out;
+	}
+
+	/* calc total requested load for this regulator */
+	list_for_each_entry(consumer, &rdev->consumer_list, list)
+		total_uA_load += consumer->uA_load;
+
+	mode = rdev->desc->ops->get_optimum_mode(rdev,
+						 input_uV, output_uV,
+						 total_uA_load);
+	ret = regulator_mode_constrain(rdev, &mode);
+	if (ret < 0) {
+		rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n",
+			 total_uA_load, input_uV, output_uV);
+		goto out;
+	}
+
+	ret = rdev->desc->ops->set_mode(rdev, mode);
+	if (ret < 0) {
+		rdev_err(rdev, "failed to set optimum mode %x\n", mode);
+		goto out;
+	}
+	ret = mode;
+out:
+	mutex_unlock(&rdev->mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
+
+/**
+ * regulator_register_notifier - register regulator event notifier
+ * @regulator: regulator source
+ * @nb: notifier block
+ *
+ * Register notifier block to receive regulator events.
+ */
+int regulator_register_notifier(struct regulator *regulator,
+			      struct notifier_block *nb)
+{
+	return blocking_notifier_chain_register(&regulator->rdev->notifier,
+						nb);
+}
+EXPORT_SYMBOL_GPL(regulator_register_notifier);
+
+/**
+ * regulator_unregister_notifier - unregister regulator event notifier
+ * @regulator: regulator source
+ * @nb: notifier block
+ *
+ * Unregister regulator event notifier block.
+ */
+int regulator_unregister_notifier(struct regulator *regulator,
+				struct notifier_block *nb)
+{
+	return blocking_notifier_chain_unregister(&regulator->rdev->notifier,
+						  nb);
+}
+EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
+
+/* notify regulator consumers and downstream regulator consumers.
+ * Note mutex must be held by caller.
+ */
+static void _notifier_call_chain(struct regulator_dev *rdev,
+				  unsigned long event, void *data)
+{
+	/* call rdev chain first */
+	blocking_notifier_call_chain(&rdev->notifier, event, NULL);
+}
+
+/**
+ * regulator_bulk_get - get multiple regulator consumers
+ *
+ * @dev:           Device to supply
+ * @num_consumers: Number of consumers to register
+ * @consumers:     Configuration of consumers; clients are stored here.
+ *
+ * @return 0 on success, an errno on failure.
+ *
+ * This helper function allows drivers to get several regulator
+ * consumers in one operation.  If any of the regulators cannot be
+ * acquired then any regulators that were allocated will be freed
+ * before returning to the caller.
+ */
+int regulator_bulk_get(struct device *dev, int num_consumers,
+		       struct regulator_bulk_data *consumers)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < num_consumers; i++)
+		consumers[i].consumer = NULL;
+
+	for (i = 0; i < num_consumers; i++) {
+		consumers[i].consumer = regulator_get(dev,
+						      consumers[i].supply);
+		if (IS_ERR(consumers[i].consumer)) {
+			ret = PTR_ERR(consumers[i].consumer);
+			dev_err(dev, "Failed to get supply '%s': %d\n",
+				consumers[i].supply, ret);
+			consumers[i].consumer = NULL;
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	while (--i >= 0)
+		regulator_put(consumers[i].consumer);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_get);
+
+/**
+ * devm_regulator_bulk_get - managed get multiple regulator consumers
+ *
+ * @dev:           Device to supply
+ * @num_consumers: Number of consumers to register
+ * @consumers:     Configuration of consumers; clients are stored here.
+ *
+ * @return 0 on success, an errno on failure.
+ *
+ * This helper function allows drivers to get several regulator
+ * consumers in one operation with management, the regulators will
+ * automatically be freed when the device is unbound.  If any of the
+ * regulators cannot be acquired then any regulators that were
+ * allocated will be freed before returning to the caller.
+ */
+int devm_regulator_bulk_get(struct device *dev, int num_consumers,
+			    struct regulator_bulk_data *consumers)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < num_consumers; i++)
+		consumers[i].consumer = NULL;
+
+	for (i = 0; i < num_consumers; i++) {
+		consumers[i].consumer = devm_regulator_get(dev,
+							   consumers[i].supply);
+		if (IS_ERR(consumers[i].consumer)) {
+			ret = PTR_ERR(consumers[i].consumer);
+			dev_err(dev, "Failed to get supply '%s': %d\n",
+				consumers[i].supply, ret);
+			consumers[i].consumer = NULL;
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	for (i = 0; i < num_consumers && consumers[i].consumer; i++)
+		devm_regulator_put(consumers[i].consumer);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_bulk_get);
+
+static void regulator_bulk_enable_async(void *data, async_cookie_t cookie)
+{
+	struct regulator_bulk_data *bulk = data;
+
+	bulk->ret = regulator_enable(bulk->consumer);
+}
+
+/**
+ * regulator_bulk_enable - enable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers:     Consumer data; clients are stored here.
+ * @return         0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to enable multiple regulator
+ * clients in a single API call.  If any consumers cannot be enabled
+ * then any others that were enabled will be disabled again prior to
+ * return.
+ */
+int regulator_bulk_enable(int num_consumers,
+			  struct regulator_bulk_data *consumers)
+{
+	LIST_HEAD(async_domain);
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < num_consumers; i++)
+		async_schedule_domain(regulator_bulk_enable_async,
+				      &consumers[i], &async_domain);
+
+	async_synchronize_full_domain(&async_domain);
+
+	/* If any consumer failed we need to unwind any that succeeded */
+	for (i = 0; i < num_consumers; i++) {
+		if (consumers[i].ret != 0) {
+			ret = consumers[i].ret;
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret);
+	while (--i >= 0)
+		regulator_disable(consumers[i].consumer);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_enable);
+
+/**
+ * regulator_bulk_disable - disable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers:     Consumer data; clients are stored here.
+ * @return         0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to disable multiple regulator
+ * clients in a single API call.  If any consumers cannot be disabled
+ * then any others that were disabled will be enabled again prior to
+ * return.
+ */
+int regulator_bulk_disable(int num_consumers,
+			   struct regulator_bulk_data *consumers)
+{
+	int i;
+	int ret;
+
+	for (i = num_consumers - 1; i >= 0; --i) {
+		ret = regulator_disable(consumers[i].consumer);
+		if (ret != 0)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret);
+	for (++i; i < num_consumers; ++i)
+		regulator_enable(consumers[i].consumer);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_disable);
+
+/**
+ * regulator_bulk_force_disable - force disable multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers:     Consumer data; clients are stored here.
+ * @return         0 on success, an errno on failure
+ *
+ * This convenience API allows consumers to forcibly disable multiple regulator
+ * clients in a single API call.
+ * NOTE: This should be used for situations when device damage will
+ * likely occur if the regulators are not disabled (e.g. over temp).
+ * Although regulator_force_disable function call for some consumers can
+ * return error numbers, the function is called for all consumers.
+ */
+int regulator_bulk_force_disable(int num_consumers,
+			   struct regulator_bulk_data *consumers)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < num_consumers; i++)
+		consumers[i].ret =
+			    regulator_force_disable(consumers[i].consumer);
+
+	for (i = 0; i < num_consumers; i++) {
+		if (consumers[i].ret != 0) {
+			ret = consumers[i].ret;
+			goto out;
+		}
+	}
+
+	return 0;
+out:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_force_disable);
+
+/**
+ * regulator_bulk_free - free multiple regulator consumers
+ *
+ * @num_consumers: Number of consumers
+ * @consumers:     Consumer data; clients are stored here.
+ *
+ * This convenience API allows consumers to free multiple regulator
+ * clients in a single API call.
+ */
+void regulator_bulk_free(int num_consumers,
+			 struct regulator_bulk_data *consumers)
+{
+	int i;
+
+	for (i = 0; i < num_consumers; i++) {
+		regulator_put(consumers[i].consumer);
+		consumers[i].consumer = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(regulator_bulk_free);
+
+/**
+ * regulator_notifier_call_chain - call regulator event notifier
+ * @rdev: regulator source
+ * @event: notifier block
+ * @data: callback-specific data.
+ *
+ * Called by regulator drivers to notify clients a regulator event has
+ * occurred. We also notify regulator clients downstream.
+ * Note lock must be held by caller.
+ */
+int regulator_notifier_call_chain(struct regulator_dev *rdev,
+				  unsigned long event, void *data)
+{
+	_notifier_call_chain(rdev, event, data);
+	return NOTIFY_DONE;
+
+}
+EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);
+
+/**
+ * regulator_mode_to_status - convert a regulator mode into a status
+ *
+ * @mode: Mode to convert
+ *
+ * Convert a regulator mode into a status.
+ */
+int regulator_mode_to_status(unsigned int mode)
+{
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		return REGULATOR_STATUS_FAST;
+	case REGULATOR_MODE_NORMAL:
+		return REGULATOR_STATUS_NORMAL;
+	case REGULATOR_MODE_IDLE:
+		return REGULATOR_STATUS_IDLE;
+	case REGULATOR_STATUS_STANDBY:
+		return REGULATOR_STATUS_STANDBY;
+	default:
+		return 0;
+	}
+}
+EXPORT_SYMBOL_GPL(regulator_mode_to_status);
+
+/*
+ * To avoid cluttering sysfs (and memory) with useless state, only
+ * create attributes that can be meaningfully displayed.
+ */
+static int add_regulator_attributes(struct regulator_dev *rdev)
+{
+	struct device		*dev = &rdev->dev;
+	struct regulator_ops	*ops = rdev->desc->ops;
+	int			status = 0;
+
+	/* some attributes need specific methods to be displayed */
+	if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
+	    (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0)) {
+		status = device_create_file(dev, &dev_attr_microvolts);
+		if (status < 0)
+			return status;
+	}
+	if (ops->get_current_limit) {
+		status = device_create_file(dev, &dev_attr_microamps);
+		if (status < 0)
+			return status;
+	}
+	if (ops->get_mode) {
+		status = device_create_file(dev, &dev_attr_opmode);
+		if (status < 0)
+			return status;
+	}
+	if (ops->is_enabled) {
+		status = device_create_file(dev, &dev_attr_state);
+		if (status < 0)
+			return status;
+	}
+	if (ops->get_status) {
+		status = device_create_file(dev, &dev_attr_status);
+		if (status < 0)
+			return status;
+	}
+
+	/* some attributes are type-specific */
+	if (rdev->desc->type == REGULATOR_CURRENT) {
+		status = device_create_file(dev, &dev_attr_requested_microamps);
+		if (status < 0)
+			return status;
+	}
+
+	/* all the other attributes exist to support constraints;
+	 * don't show them if there are no constraints, or if the
+	 * relevant supporting methods are missing.
+	 */
+	if (!rdev->constraints)
+		return status;
+
+	/* constraints need specific supporting methods */
+	if (ops->set_voltage || ops->set_voltage_sel) {
+		status = device_create_file(dev, &dev_attr_min_microvolts);
+		if (status < 0)
+			return status;
+		status = device_create_file(dev, &dev_attr_max_microvolts);
+		if (status < 0)
+			return status;
+	}
+	if (ops->set_current_limit) {
+		status = device_create_file(dev, &dev_attr_min_microamps);
+		if (status < 0)
+			return status;
+		status = device_create_file(dev, &dev_attr_max_microamps);
+		if (status < 0)
+			return status;
+	}
+
+	/* suspend mode constraints need multiple supporting methods */
+	if (!(ops->set_suspend_enable && ops->set_suspend_disable))
+		return status;
+
+	status = device_create_file(dev, &dev_attr_suspend_standby_state);
+	if (status < 0)
+		return status;
+	status = device_create_file(dev, &dev_attr_suspend_mem_state);
+	if (status < 0)
+		return status;
+	status = device_create_file(dev, &dev_attr_suspend_disk_state);
+	if (status < 0)
+		return status;
+
+	if (ops->set_suspend_voltage) {
+		status = device_create_file(dev,
+				&dev_attr_suspend_standby_microvolts);
+		if (status < 0)
+			return status;
+		status = device_create_file(dev,
+				&dev_attr_suspend_mem_microvolts);
+		if (status < 0)
+			return status;
+		status = device_create_file(dev,
+				&dev_attr_suspend_disk_microvolts);
+		if (status < 0)
+			return status;
+	}
+
+	if (ops->set_suspend_mode) {
+		status = device_create_file(dev,
+				&dev_attr_suspend_standby_mode);
+		if (status < 0)
+			return status;
+		status = device_create_file(dev,
+				&dev_attr_suspend_mem_mode);
+		if (status < 0)
+			return status;
+		status = device_create_file(dev,
+				&dev_attr_suspend_disk_mode);
+		if (status < 0)
+			return status;
+	}
+
+	return status;
+}
+
+static void rdev_init_debugfs(struct regulator_dev *rdev)
+{
+	rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root);
+	if (!rdev->debugfs) {
+		rdev_warn(rdev, "Failed to create debugfs directory\n");
+		return;
+	}
+
+	debugfs_create_u32("use_count", 0444, rdev->debugfs,
+			   &rdev->use_count);
+	debugfs_create_u32("open_count", 0444, rdev->debugfs,
+			   &rdev->open_count);
+}
+
+/**
+ * regulator_register - register regulator
+ * @regulator_desc: regulator to register
+ * @dev: struct device for the regulator
+ * @init_data: platform provided init data, passed through by driver
+ * @driver_data: private regulator data
+ * @of_node: OpenFirmware node to parse for device tree bindings (may be
+ *           NULL).
+ *
+ * Called by regulator drivers to register a regulator.
+ * Returns 0 on success.
+ */
+struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
+	struct device *dev, const struct regulator_init_data *init_data,
+	void *driver_data, struct device_node *of_node)
+{
+	const struct regulation_constraints *constraints = NULL;
+	static atomic_t regulator_no = ATOMIC_INIT(0);
+	struct regulator_dev *rdev;
+	int ret, i;
+	const char *supply = NULL;
+
+	if (regulator_desc == NULL)
+		return ERR_PTR(-EINVAL);
+
+	if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
+		return ERR_PTR(-EINVAL);
+
+	if (regulator_desc->type != REGULATOR_VOLTAGE &&
+	    regulator_desc->type != REGULATOR_CURRENT)
+		return ERR_PTR(-EINVAL);
+
+	/* Only one of each should be implemented */
+	WARN_ON(regulator_desc->ops->get_voltage &&
+		regulator_desc->ops->get_voltage_sel);
+	WARN_ON(regulator_desc->ops->set_voltage &&
+		regulator_desc->ops->set_voltage_sel);
+
+	/* If we're using selectors we must implement list_voltage. */
+	if (regulator_desc->ops->get_voltage_sel &&
+	    !regulator_desc->ops->list_voltage) {
+		return ERR_PTR(-EINVAL);
+	}
+	if (regulator_desc->ops->set_voltage_sel &&
+	    !regulator_desc->ops->list_voltage) {
+		return ERR_PTR(-EINVAL);
+	}
+
+	rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
+	if (rdev == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_lock(&regulator_list_mutex);
+
+	mutex_init(&rdev->mutex);
+	rdev->reg_data = driver_data;
+	rdev->owner = regulator_desc->owner;
+	rdev->desc = regulator_desc;
+	INIT_LIST_HEAD(&rdev->consumer_list);
+	INIT_LIST_HEAD(&rdev->list);
+	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
+	INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
+
+	/* preform any regulator specific init */
+	if (init_data && init_data->regulator_init) {
+		ret = init_data->regulator_init(rdev->reg_data);
+		if (ret < 0)
+			goto clean;
+	}
+
+	/* register with sysfs */
+	rdev->dev.class = &regulator_class;
+	rdev->dev.of_node = of_node;
+	rdev->dev.parent = dev;
+	dev_set_name(&rdev->dev, "regulator.%d",
+		     atomic_inc_return(&regulator_no) - 1);
+	ret = device_register(&rdev->dev);
+	if (ret != 0) {
+		put_device(&rdev->dev);
+		goto clean;
+	}
+
+	dev_set_drvdata(&rdev->dev, rdev);
+
+	/* set regulator constraints */
+	if (init_data)
+		constraints = &init_data->constraints;
+
+	ret = set_machine_constraints(rdev, constraints);
+	if (ret < 0)
+		goto scrub;
+
+	/* add attributes supported by this regulator */
+	ret = add_regulator_attributes(rdev);
+	if (ret < 0)
+		goto scrub;
+
+	if (init_data && init_data->supply_regulator)
+		supply = init_data->supply_regulator;
+	else if (regulator_desc->supply_name)
+		supply = regulator_desc->supply_name;
+
+	if (supply) {
+		struct regulator_dev *r;
+
+		r = regulator_dev_lookup(dev, supply);
+
+		if (!r) {
+			dev_err(dev, "Failed to find supply %s\n", supply);
+			ret = -EPROBE_DEFER;
+			goto scrub;
+		}
+
+		ret = set_supply(rdev, r);
+		if (ret < 0)
+			goto scrub;
+
+		/* Enable supply if rail is enabled */
+		if (rdev->desc->ops->is_enabled &&
+				rdev->desc->ops->is_enabled(rdev)) {
+			ret = regulator_enable(rdev->supply);
+			if (ret < 0)
+				goto scrub;
+		}
+	}
+
+	/* add consumers devices */
+	if (init_data) {
+		for (i = 0; i < init_data->num_consumer_supplies; i++) {
+			ret = set_consumer_device_supply(rdev,
+				init_data->consumer_supplies[i].dev_name,
+				init_data->consumer_supplies[i].supply);
+			if (ret < 0) {
+				dev_err(dev, "Failed to set supply %s\n",
+					init_data->consumer_supplies[i].supply);
+				goto unset_supplies;
+			}
+		}
+	}
+
+	list_add(&rdev->list, &regulator_list);
+
+	rdev_init_debugfs(rdev);
+out:
+	mutex_unlock(&regulator_list_mutex);
+	return rdev;
+
+unset_supplies:
+	unset_regulator_supplies(rdev);
+
+scrub:
+	if (rdev->supply)
+		regulator_put(rdev->supply);
+	kfree(rdev->constraints);
+	device_unregister(&rdev->dev);
+	/* device core frees rdev */
+	rdev = ERR_PTR(ret);
+	goto out;
+
+clean:
+	kfree(rdev);
+	rdev = ERR_PTR(ret);
+	goto out;
+}
+EXPORT_SYMBOL_GPL(regulator_register);
+
+/**
+ * regulator_unregister - unregister regulator
+ * @rdev: regulator to unregister
+ *
+ * Called by regulator drivers to unregister a regulator.
+ */
+void regulator_unregister(struct regulator_dev *rdev)
+{
+	if (rdev == NULL)
+		return;
+
+	if (rdev->supply)
+		regulator_put(rdev->supply);
+	mutex_lock(&regulator_list_mutex);
+	debugfs_remove_recursive(rdev->debugfs);
+	flush_work_sync(&rdev->disable_work.work);
+	WARN_ON(rdev->open_count);
+	unset_regulator_supplies(rdev);
+	list_del(&rdev->list);
+	kfree(rdev->constraints);
+	device_unregister(&rdev->dev);
+	mutex_unlock(&regulator_list_mutex);
+}
+EXPORT_SYMBOL_GPL(regulator_unregister);
+
+/**
+ * regulator_suspend_prepare - prepare regulators for system wide suspend
+ * @state: system suspend state
+ *
+ * Configure each regulator with it's suspend operating parameters for state.
+ * This will usually be called by machine suspend code prior to supending.
+ */
+int regulator_suspend_prepare(suspend_state_t state)
+{
+	struct regulator_dev *rdev;
+	int ret = 0;
+
+	/* ON is handled by regulator active state */
+	if (state == PM_SUSPEND_ON)
+		return -EINVAL;
+
+	mutex_lock(&regulator_list_mutex);
+	list_for_each_entry(rdev, &regulator_list, list) {
+
+		mutex_lock(&rdev->mutex);
+		ret = suspend_prepare(rdev, state);
+		mutex_unlock(&rdev->mutex);
+
+		if (ret < 0) {
+			rdev_err(rdev, "failed to prepare\n");
+			goto out;
+		}
+	}
+out:
+	mutex_unlock(&regulator_list_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
+
+/**
+ * regulator_suspend_finish - resume regulators from system wide suspend
+ *
+ * Turn on regulators that might be turned off by regulator_suspend_prepare
+ * and that should be turned on according to the regulators properties.
+ */
+int regulator_suspend_finish(void)
+{
+	struct regulator_dev *rdev;
+	int ret = 0, error;
+
+	mutex_lock(&regulator_list_mutex);
+	list_for_each_entry(rdev, &regulator_list, list) {
+		struct regulator_ops *ops = rdev->desc->ops;
+
+		mutex_lock(&rdev->mutex);
+		if ((rdev->use_count > 0  || rdev->constraints->always_on) &&
+				ops->enable) {
+			error = ops->enable(rdev);
+			if (error)
+				ret = error;
+		} else {
+			if (!has_full_constraints)
+				goto unlock;
+			if (!ops->disable)
+				goto unlock;
+			if (ops->is_enabled && !ops->is_enabled(rdev))
+				goto unlock;
+
+			error = ops->disable(rdev);
+			if (error)
+				ret = error;
+		}
+unlock:
+		mutex_unlock(&rdev->mutex);
+	}
+	mutex_unlock(&regulator_list_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_suspend_finish);
+
+/**
+ * regulator_has_full_constraints - the system has fully specified constraints
+ *
+ * Calling this function will cause the regulator API to disable all
+ * regulators which have a zero use count and don't have an always_on
+ * constraint in a late_initcall.
+ *
+ * The intention is that this will become the default behaviour in a
+ * future kernel release so users are encouraged to use this facility
+ * now.
+ */
+void regulator_has_full_constraints(void)
+{
+	has_full_constraints = 1;
+}
+EXPORT_SYMBOL_GPL(regulator_has_full_constraints);
+
+/**
+ * regulator_use_dummy_regulator - Provide a dummy regulator when none is found
+ *
+ * Calling this function will cause the regulator API to provide a
+ * dummy regulator to consumers if no physical regulator is found,
+ * allowing most consumers to proceed as though a regulator were
+ * configured.  This allows systems such as those with software
+ * controllable regulators for the CPU core only to be brought up more
+ * readily.
+ */
+void regulator_use_dummy_regulator(void)
+{
+	board_wants_dummy_regulator = true;
+}
+EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator);
+
+/**
+ * rdev_get_drvdata - get rdev regulator driver data
+ * @rdev: regulator
+ *
+ * Get rdev regulator driver private data. This call can be used in the
+ * regulator driver context.
+ */
+void *rdev_get_drvdata(struct regulator_dev *rdev)
+{
+	return rdev->reg_data;
+}
+EXPORT_SYMBOL_GPL(rdev_get_drvdata);
+
+/**
+ * regulator_get_drvdata - get regulator driver data
+ * @regulator: regulator
+ *
+ * Get regulator driver private data. This call can be used in the consumer
+ * driver context when non API regulator specific functions need to be called.
+ */
+void *regulator_get_drvdata(struct regulator *regulator)
+{
+	return regulator->rdev->reg_data;
+}
+EXPORT_SYMBOL_GPL(regulator_get_drvdata);
+
+/**
+ * regulator_set_drvdata - set regulator driver data
+ * @regulator: regulator
+ * @data: data
+ */
+void regulator_set_drvdata(struct regulator *regulator, void *data)
+{
+	regulator->rdev->reg_data = data;
+}
+EXPORT_SYMBOL_GPL(regulator_set_drvdata);
+
+/**
+ * regulator_get_id - get regulator ID
+ * @rdev: regulator
+ */
+int rdev_get_id(struct regulator_dev *rdev)
+{
+	return rdev->desc->id;
+}
+EXPORT_SYMBOL_GPL(rdev_get_id);
+
+struct device *rdev_get_dev(struct regulator_dev *rdev)
+{
+	return &rdev->dev;
+}
+EXPORT_SYMBOL_GPL(rdev_get_dev);
+
+void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data)
+{
+	return reg_init_data->driver_data;
+}
+EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t supply_map_read_file(struct file *file, char __user *user_buf,
+				    size_t count, loff_t *ppos)
+{
+	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	ssize_t len, ret = 0;
+	struct regulator_map *map;
+
+	if (!buf)
+		return -ENOMEM;
+
+	list_for_each_entry(map, &regulator_map_list, list) {
+		len = snprintf(buf + ret, PAGE_SIZE - ret,
+			       "%s -> %s.%s\n",
+			       rdev_get_name(map->regulator), map->dev_name,
+			       map->supply);
+		if (len >= 0)
+			ret += len;
+		if (ret > PAGE_SIZE) {
+			ret = PAGE_SIZE;
+			break;
+		}
+	}
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+	kfree(buf);
+
+	return ret;
+}
+#endif
+
+static const struct file_operations supply_map_fops = {
+#ifdef CONFIG_DEBUG_FS
+	.read = supply_map_read_file,
+	.llseek = default_llseek,
+#endif
+};
+
+static int __init regulator_init(void)
+{
+	int ret;
+
+	ret = class_register(&regulator_class);
+
+	debugfs_root = debugfs_create_dir("regulator", NULL);
+	if (!debugfs_root)
+		pr_warn("regulator: Failed to create debugfs directory\n");
+
+	debugfs_create_file("supply_map", 0444, debugfs_root, NULL,
+			    &supply_map_fops);
+
+	regulator_dummy_init();
+
+	return ret;
+}
+
+/* init early to allow our consumers to complete system booting */
+core_initcall(regulator_init);
+
+static int __init regulator_init_complete(void)
+{
+	struct regulator_dev *rdev;
+	struct regulator_ops *ops;
+	struct regulation_constraints *c;
+	int enabled, ret;
+
+	mutex_lock(&regulator_list_mutex);
+
+	/* If we have a full configuration then disable any regulators
+	 * which are not in use or always_on.  This will become the
+	 * default behaviour in the future.
+	 */
+	list_for_each_entry(rdev, &regulator_list, list) {
+		ops = rdev->desc->ops;
+		c = rdev->constraints;
+
+		if (!ops->disable || (c && c->always_on))
+			continue;
+
+		mutex_lock(&rdev->mutex);
+
+		if (rdev->use_count)
+			goto unlock;
+
+		/* If we can't read the status assume it's on. */
+		if (ops->is_enabled)
+			enabled = ops->is_enabled(rdev);
+		else
+			enabled = 1;
+
+		if (!enabled)
+			goto unlock;
+
+		if (has_full_constraints) {
+			/* We log since this may kill the system if it
+			 * goes wrong. */
+			rdev_info(rdev, "disabling\n");
+			ret = ops->disable(rdev);
+			if (ret != 0) {
+				rdev_err(rdev, "couldn't disable: %d\n", ret);
+			}
+		} else {
+			/* The intention is that in future we will
+			 * assume that full constraints are provided
+			 * so warn even if we aren't going to do
+			 * anything here.
+			 */
+			rdev_warn(rdev, "incomplete constraints, leaving on\n");
+		}
+
+unlock:
+		mutex_unlock(&rdev->mutex);
+	}
+
+	mutex_unlock(&regulator_list_mutex);
+
+	return 0;
+}
+late_initcall(regulator_init_complete);
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/da903x.c b/ap/os/linux/linux-3.4.x/drivers/regulator/da903x.c
new file mode 100644
index 0000000..1851f09
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/da903x.c
@@ -0,0 +1,584 @@
+/*
+ * Regulators driver for Dialog Semiconductor DA903x
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Copyright (C) 2008 Compulab Ltd.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/da903x.h>
+
+/* DA9030 Registers */
+#define DA9030_INVAL		(-1)
+#define DA9030_LDO1011		(0x10)
+#define DA9030_LDO15		(0x11)
+#define DA9030_LDO1416		(0x12)
+#define DA9030_LDO1819		(0x13)
+#define DA9030_LDO17		(0x14)
+#define DA9030_BUCK2DVM1	(0x15)
+#define DA9030_BUCK2DVM2	(0x16)
+#define DA9030_RCTL11		(0x17)
+#define DA9030_RCTL21		(0x18)
+#define DA9030_LDO1		(0x90)
+#define DA9030_LDO23		(0x91)
+#define DA9030_LDO45		(0x92)
+#define DA9030_LDO6		(0x93)
+#define DA9030_LDO78		(0x94)
+#define DA9030_LDO912		(0x95)
+#define DA9030_BUCK		(0x96)
+#define DA9030_RCTL12		(0x97)
+#define DA9030_RCTL22		(0x98)
+#define DA9030_LDO_UNLOCK	(0xa0)
+#define DA9030_LDO_UNLOCK_MASK	(0xe0)
+#define DA9034_OVER1		(0x10)
+
+/* DA9034 Registers */
+#define DA9034_INVAL		(-1)
+#define DA9034_OVER2		(0x11)
+#define DA9034_OVER3		(0x12)
+#define DA9034_LDO643		(0x13)
+#define DA9034_LDO987		(0x14)
+#define DA9034_LDO1110		(0x15)
+#define DA9034_LDO1312		(0x16)
+#define DA9034_LDO1514		(0x17)
+#define DA9034_VCC1		(0x20)
+#define DA9034_ADTV1		(0x23)
+#define DA9034_ADTV2		(0x24)
+#define DA9034_AVRC		(0x25)
+#define DA9034_CDTV1		(0x26)
+#define DA9034_CDTV2		(0x27)
+#define DA9034_CVRC		(0x28)
+#define DA9034_SDTV1		(0x29)
+#define DA9034_SDTV2		(0x2a)
+#define DA9034_SVRC		(0x2b)
+#define DA9034_MDTV1		(0x32)
+#define DA9034_MDTV2		(0x33)
+#define DA9034_MVRC		(0x34)
+
+/* DA9035 Registers. DA9034 Registers are comptabile to DA9035. */
+#define DA9035_OVER3		(0x12)
+#define DA9035_VCC2		(0x1f)
+#define DA9035_3DTV1		(0x2c)
+#define DA9035_3DTV2		(0x2d)
+#define DA9035_3VRC		(0x2e)
+#define DA9035_AUTOSKIP		(0x2f)
+
+struct da903x_regulator_info {
+	struct regulator_desc desc;
+
+	int	min_uV;
+	int	max_uV;
+	int	step_uV;
+	int	vol_reg;
+	int	vol_shift;
+	int	vol_nbits;
+	int	update_reg;
+	int	update_bit;
+	int	enable_reg;
+	int	enable_bit;
+};
+
+static int da9034_ldo12_data[] = { 1700, 1750, 1800, 1850, 1900, 1950,
+				   2000, 2050, 2700, 2750, 2800, 2850,
+				   2900, 2950, 3000, 3050 };
+
+static inline struct device *to_da903x_dev(struct regulator_dev *rdev)
+{
+	return rdev_get_dev(rdev)->parent->parent;
+}
+
+static inline int check_range(struct da903x_regulator_info *info,
+				int min_uV, int max_uV)
+{
+	if (min_uV < info->min_uV || min_uV > info->max_uV)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* DA9030/DA9034 common operations */
+static int da903x_set_ldo_voltage(struct regulator_dev *rdev,
+				  int min_uV, int max_uV, unsigned *selector)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = to_da903x_dev(rdev);
+	uint8_t val, mask;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
+	*selector = val;
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+	return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da903x_get_voltage(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = to_da903x_dev(rdev);
+	uint8_t val, mask;
+	int ret;
+
+	ret = da903x_read(da9034_dev, info->vol_reg, &val);
+	if (ret)
+		return ret;
+
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+	val = (val & mask) >> info->vol_shift;
+
+	return info->min_uV + info->step_uV * val;
+}
+
+static int da903x_enable(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = to_da903x_dev(rdev);
+
+	return da903x_set_bits(da9034_dev, info->enable_reg,
+					1 << info->enable_bit);
+}
+
+static int da903x_disable(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = to_da903x_dev(rdev);
+
+	return da903x_clr_bits(da9034_dev, info->enable_reg,
+					1 << info->enable_bit);
+}
+
+static int da903x_is_enabled(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = to_da903x_dev(rdev);
+	uint8_t reg_val;
+	int ret;
+
+	ret = da903x_read(da9034_dev, info->enable_reg, &reg_val);
+	if (ret)
+		return ret;
+
+	return !!(reg_val & (1 << info->enable_bit));
+}
+
+static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret;
+
+	ret = info->min_uV + info->step_uV * selector;
+	if (ret > info->max_uV)
+		return -EINVAL;
+	return ret;
+}
+
+/* DA9030 specific operations */
+static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
+				      int min_uV, int max_uV,
+				      unsigned *selector)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da903x_dev = to_da903x_dev(rdev);
+	uint8_t val, mask;
+	int ret;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
+	*selector = val;
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+	val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */
+	mask |= DA9030_LDO_UNLOCK_MASK;
+
+	/* write twice */
+	ret = da903x_update(da903x_dev, info->vol_reg, val, mask);
+	if (ret)
+		return ret;
+
+	return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_set_ldo14_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV,
+				    unsigned *selector)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da903x_dev = to_da903x_dev(rdev);
+	uint8_t val, mask;
+	int thresh;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	thresh = (info->max_uV + info->min_uV) / 2;
+	if (min_uV < thresh) {
+		val = DIV_ROUND_UP(thresh - min_uV, info->step_uV);
+		val |= 0x4;
+	} else {
+		val = DIV_ROUND_UP(min_uV - thresh, info->step_uV);
+	}
+
+	*selector = val;
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+	return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_get_ldo14_voltage(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da903x_dev = to_da903x_dev(rdev);
+	uint8_t val, mask;
+	int ret;
+
+	ret = da903x_read(da903x_dev, info->vol_reg, &val);
+	if (ret)
+		return ret;
+
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+	val = (val & mask) >> info->vol_shift;
+
+	if (val & 0x4)
+		return info->min_uV + info->step_uV * (3 - (val & ~0x4));
+	else
+		return (info->max_uV + info->min_uV) / 2 +
+			info->step_uV * (val & ~0x4);
+}
+
+/* DA9034 specific operations */
+static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
+				  int min_uV, int max_uV, unsigned *selector)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = to_da903x_dev(rdev);
+	uint8_t val, mask;
+	int ret;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
+	*selector = val;
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+	ret = da903x_update(da9034_dev, info->vol_reg, val, mask);
+	if (ret)
+		return ret;
+
+	ret = da903x_set_bits(da9034_dev, info->update_reg,
+					1 << info->update_bit);
+	return ret;
+}
+
+static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV, unsigned *selector)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = to_da903x_dev(rdev);
+	uint8_t val, mask;
+
+	if (check_range(info, min_uV, max_uV)) {
+		pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
+	val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val);
+	*selector = val;
+	val <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+
+	return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
+{
+	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+	struct device *da9034_dev = to_da903x_dev(rdev);
+	uint8_t val, mask;
+	int ret;
+
+	ret = da903x_read(da9034_dev, info->vol_reg, &val);
+	if (ret)
+		return ret;
+
+	mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
+	val = (val & mask) >> info->vol_shift;
+
+	if (val >= 8)
+		return 2700000 + info->step_uV * (val - 8);
+
+	return info->min_uV + info->step_uV * val;
+}
+
+static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
+				     unsigned selector)
+{
+	if (selector >= ARRAY_SIZE(da9034_ldo12_data))
+		return -EINVAL;
+	return da9034_ldo12_data[selector] * 1000;
+}
+
+static struct regulator_ops da903x_regulator_ldo_ops = {
+	.set_voltage	= da903x_set_ldo_voltage,
+	.get_voltage	= da903x_get_voltage,
+	.list_voltage	= da903x_list_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane DA9030 LDO14 */
+static struct regulator_ops da9030_regulator_ldo14_ops = {
+	.set_voltage	= da9030_set_ldo14_voltage,
+	.get_voltage	= da9030_get_ldo14_voltage,
+	.list_voltage	= da903x_list_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks  */
+static struct regulator_ops da9030_regulator_ldo1_15_ops = {
+	.set_voltage	= da9030_set_ldo1_15_voltage,
+	.get_voltage	= da903x_get_voltage,
+	.list_voltage	= da903x_list_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+static struct regulator_ops da9034_regulator_dvc_ops = {
+	.set_voltage	= da9034_set_dvc_voltage,
+	.get_voltage	= da903x_get_voltage,
+	.list_voltage	= da903x_list_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane LDO12 */
+static struct regulator_ops da9034_regulator_ldo12_ops = {
+	.set_voltage	= da9034_set_ldo12_voltage,
+	.get_voltage	= da9034_get_ldo12_voltage,
+	.list_voltage	= da9034_list_ldo12_voltage,
+	.enable		= da903x_enable,
+	.disable	= da903x_disable,
+	.is_enabled	= da903x_is_enabled,
+};
+
+#define DA903x_LDO(_pmic, _id, min, max, step, vreg, shift, nbits, ereg, ebit)	\
+{									\
+	.desc	= {							\
+		.name	= "LDO" #_id,					\
+		.ops	= &da903x_regulator_ldo_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= _pmic##_ID_LDO##_id,				\
+		.n_voltages = (step) ? ((max - min) / step + 1) : 1,	\
+		.owner	= THIS_MODULE,					\
+	},								\
+	.min_uV		= (min) * 1000,					\
+	.max_uV		= (max) * 1000,					\
+	.step_uV	= (step) * 1000,				\
+	.vol_reg	= _pmic##_##vreg,				\
+	.vol_shift	= (shift),					\
+	.vol_nbits	= (nbits),					\
+	.enable_reg	= _pmic##_##ereg,				\
+	.enable_bit	= (ebit),					\
+}
+
+#define DA903x_DVC(_pmic, _id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+{									\
+	.desc	= {							\
+		.name	= #_id,						\
+		.ops	= &da9034_regulator_dvc_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= _pmic##_ID_##_id,				\
+		.n_voltages = (step) ? ((max - min) / step + 1) : 1,	\
+		.owner	= THIS_MODULE,					\
+	},								\
+	.min_uV		= (min) * 1000,					\
+	.max_uV		= (max) * 1000,					\
+	.step_uV	= (step) * 1000,				\
+	.vol_reg	= _pmic##_##vreg,				\
+	.vol_shift	= (0),						\
+	.vol_nbits	= (nbits),					\
+	.update_reg	= _pmic##_##ureg,				\
+	.update_bit	= (ubit),					\
+	.enable_reg	= _pmic##_##ereg,				\
+	.enable_bit	= (ebit),					\
+}
+
+#define DA9034_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit)	\
+	DA903x_LDO(DA9034, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+#define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit)	\
+	DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+#define DA9030_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+	DA903x_DVC(DA9030, _id, min, max, step, vreg, nbits, ureg, ubit, \
+		   ereg, ebit)
+
+#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+	DA903x_DVC(DA9034, _id, min, max, step, vreg, nbits, ureg, ubit, \
+		   ereg, ebit)
+
+#define DA9035_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+	DA903x_DVC(DA9035, _id, min, max, step, vreg, nbits, ureg, ubit, \
+		   ereg, ebit)
+
+static struct da903x_regulator_info da903x_regulator_info[] = {
+	/* DA9030 */
+	DA9030_DVC(BUCK2, 850, 1625, 25, BUCK2DVM1, 5, BUCK2DVM1, 7, RCTL11, 0),
+
+	DA9030_LDO( 1, 1200, 3200, 100,    LDO1, 0, 5, RCTL12, 1),
+	DA9030_LDO( 2, 1800, 3200, 100,   LDO23, 0, 4, RCTL12, 2),
+	DA9030_LDO( 3, 1800, 3200, 100,   LDO23, 4, 4, RCTL12, 3),
+	DA9030_LDO( 4, 1800, 3200, 100,   LDO45, 0, 4, RCTL12, 4),
+	DA9030_LDO( 5, 1800, 3200, 100,   LDO45, 4, 4, RCTL12, 5),
+	DA9030_LDO( 6, 1800, 3200, 100,    LDO6, 0, 4, RCTL12, 6),
+	DA9030_LDO( 7, 1800, 3200, 100,   LDO78, 0, 4, RCTL12, 7),
+	DA9030_LDO( 8, 1800, 3200, 100,   LDO78, 4, 4, RCTL22, 0),
+	DA9030_LDO( 9, 1800, 3200, 100,  LDO912, 0, 4, RCTL22, 1),
+	DA9030_LDO(10, 1800, 3200, 100, LDO1011, 0, 4, RCTL22, 2),
+	DA9030_LDO(11, 1800, 3200, 100, LDO1011, 4, 4, RCTL22, 3),
+	DA9030_LDO(12, 1800, 3200, 100,  LDO912, 4, 4, RCTL22, 4),
+	DA9030_LDO(14, 2760, 2940,  30, LDO1416, 0, 3, RCTL11, 4),
+	DA9030_LDO(15, 1100, 2650,  50,	  LDO15, 0, 5, RCTL11, 5),
+	DA9030_LDO(16, 1100, 2650,  50, LDO1416, 3, 5, RCTL11, 6),
+	DA9030_LDO(17, 1800, 3200, 100,   LDO17, 0, 4, RCTL11, 7),
+	DA9030_LDO(18, 1800, 3200, 100, LDO1819, 0, 4, RCTL21, 2),
+	DA9030_LDO(19, 1800, 3200, 100, LDO1819, 4, 4, RCTL21, 1),
+	DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */
+
+	/* DA9034 */
+	DA9034_DVC(BUCK1, 725, 1500, 25, ADTV2, 5, VCC1, 0, OVER1, 0),
+	DA9034_DVC(BUCK2, 725, 1500, 25, CDTV2, 5, VCC1, 2, OVER1, 1),
+	DA9034_DVC(LDO2,  725, 1500, 25, SDTV2, 5, VCC1, 4, OVER1, 2),
+	DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4),
+
+	DA9034_LDO( 3, 1800, 3300, 100,  LDO643, 0, 4, OVER3, 5),
+	DA9034_LDO( 4, 1800, 2900,1100,  LDO643, 4, 1, OVER3, 6),
+	DA9034_LDO( 6, 2500, 2850,  50,  LDO643, 5, 3, OVER2, 0),
+	DA9034_LDO( 7, 2700, 3050,  50,  LDO987, 0, 3, OVER2, 1),
+	DA9034_LDO( 8, 2700, 2850,  50,  LDO987, 3, 2, OVER2, 2),
+	DA9034_LDO( 9, 2700, 3050,  50,  LDO987, 5, 3, OVER2, 3),
+	DA9034_LDO(10, 2700, 3050,  50, LDO1110, 0, 3, OVER2, 4),
+	DA9034_LDO(11, 1800, 3300, 100, LDO1110, 4, 4, OVER2, 5),
+	DA9034_LDO(12, 1700, 3050,  50, LDO1312, 0, 4, OVER3, 6),
+	DA9034_LDO(13, 1800, 3300, 100, LDO1312, 4, 4, OVER2, 7),
+	DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0),
+	DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1),
+	DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */
+
+	/* DA9035 */
+	DA9035_DVC(BUCK3, 1800, 2200, 100, 3DTV1, 3, VCC2, 0, OVER3, 3),
+};
+
+static inline struct da903x_regulator_info *find_regulator_info(int id)
+{
+	struct da903x_regulator_info *ri;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(da903x_regulator_info); i++) {
+		ri = &da903x_regulator_info[i];
+		if (ri->desc.id == id)
+			return ri;
+	}
+	return NULL;
+}
+
+static int __devinit da903x_regulator_probe(struct platform_device *pdev)
+{
+	struct da903x_regulator_info *ri = NULL;
+	struct regulator_dev *rdev;
+
+	ri = find_regulator_info(pdev->id);
+	if (ri == NULL) {
+		dev_err(&pdev->dev, "invalid regulator ID specified\n");
+		return -EINVAL;
+	}
+
+	/* Workaround for the weird LDO12 voltage setting */
+	if (ri->desc.id == DA9034_ID_LDO12) {
+		ri->desc.ops = &da9034_regulator_ldo12_ops;
+		ri->desc.n_voltages = ARRAY_SIZE(da9034_ldo12_data);
+	}
+
+	if (ri->desc.id == DA9030_ID_LDO14)
+		ri->desc.ops = &da9030_regulator_ldo14_ops;
+
+	if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15)
+		ri->desc.ops = &da9030_regulator_ldo1_15_ops;
+
+	rdev = regulator_register(&ri->desc, &pdev->dev,
+				  pdev->dev.platform_data, ri, NULL);
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "failed to register regulator %s\n",
+				ri->desc.name);
+		return PTR_ERR(rdev);
+	}
+
+	platform_set_drvdata(pdev, rdev);
+	return 0;
+}
+
+static int __devexit da903x_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	regulator_unregister(rdev);
+	return 0;
+}
+
+static struct platform_driver da903x_regulator_driver = {
+	.driver	= {
+		.name	= "da903x-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= da903x_regulator_probe,
+	.remove		= __devexit_p(da903x_regulator_remove),
+};
+
+static int __init da903x_regulator_init(void)
+{
+	return platform_driver_register(&da903x_regulator_driver);
+}
+subsys_initcall(da903x_regulator_init);
+
+static void __exit da903x_regulator_exit(void)
+{
+	platform_driver_unregister(&da903x_regulator_driver);
+}
+module_exit(da903x_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
+	      "Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Regulator Driver for Dialog Semiconductor DA903X PMIC");
+MODULE_ALIAS("platform:da903x-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/da9052-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/da9052-regulator.c
new file mode 100644
index 0000000..09915e8
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/da9052-regulator.c
@@ -0,0 +1,610 @@
+/*
+* da9052-regulator.c: Regulator driver for DA9052
+*
+* Copyright(c) 2011 Dialog Semiconductor Ltd.
+*
+* Author: David Dajun Chen <dchen@diasemi.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/pdata.h>
+
+/* Buck step size */
+#define DA9052_BUCK_PERI_3uV_STEP		100000
+#define DA9052_BUCK_PERI_REG_MAP_UPTO_3uV	24
+#define DA9052_CONST_3uV			3000000
+
+#define DA9052_MIN_UA		0
+#define DA9052_MAX_UA		3
+#define DA9052_CURRENT_RANGE	4
+
+/* Bit masks */
+#define DA9052_BUCK_ILIM_MASK_EVEN	0x0c
+#define DA9052_BUCK_ILIM_MASK_ODD	0xc0
+
+static const u32 da9052_current_limits[3][4] = {
+	{700000, 800000, 1000000, 1200000},	/* DA9052-BC BUCKs */
+	{1600000, 2000000, 2400000, 3000000},	/* DA9053-AA/Bx BUCK-CORE */
+	{800000, 1000000, 1200000, 1500000},	/* DA9053-AA/Bx BUCK-PRO,
+						 * BUCK-MEM and BUCK-PERI
+						*/
+};
+
+struct da9052_regulator_info {
+	struct regulator_desc reg_desc;
+	int step_uV;
+	int min_uV;
+	int max_uV;
+	unsigned char volt_shift;
+	unsigned char en_bit;
+	unsigned char activate_bit;
+};
+
+struct da9052_regulator {
+	struct da9052 *da9052;
+	struct da9052_regulator_info *info;
+	struct regulator_dev *rdev;
+};
+
+static int verify_range(struct da9052_regulator_info *info,
+			 int min_uV, int max_uV)
+{
+	if (min_uV > info->max_uV || max_uV < info->min_uV)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int da9052_regulator_enable(struct regulator_dev *rdev)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int offset = rdev_get_id(rdev);
+
+	return da9052_reg_update(regulator->da9052,
+				 DA9052_BUCKCORE_REG + offset,
+				 1 << info->en_bit, 1 << info->en_bit);
+}
+
+static int da9052_regulator_disable(struct regulator_dev *rdev)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int offset = rdev_get_id(rdev);
+
+	return da9052_reg_update(regulator->da9052,
+				 DA9052_BUCKCORE_REG + offset,
+				 1 << info->en_bit, 0);
+}
+
+static int da9052_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int offset = rdev_get_id(rdev);
+	int ret;
+
+	ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset);
+	if (ret < 0)
+		return ret;
+
+	return ret & (1 << info->en_bit);
+}
+
+static int da9052_dcdc_get_current_limit(struct regulator_dev *rdev)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	int offset = rdev_get_id(rdev);
+	int ret, row = 2;
+
+	ret = da9052_reg_read(regulator->da9052, DA9052_BUCKA_REG + offset/2);
+	if (ret < 0)
+		return ret;
+
+	/* Determine the even or odd position of the buck current limit
+	 * register field
+	*/
+	if (offset % 2 == 0)
+		ret = (ret & DA9052_BUCK_ILIM_MASK_EVEN) >> 2;
+	else
+		ret = (ret & DA9052_BUCK_ILIM_MASK_ODD) >> 6;
+
+	/* Select the appropriate current limit range */
+	if (regulator->da9052->chip_id == DA9052)
+		row = 0;
+	else if (offset == 0)
+		row = 1;
+
+	return da9052_current_limits[row][ret];
+}
+
+static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA,
+					  int max_uA)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	int offset = rdev_get_id(rdev);
+	int reg_val = 0;
+	int i, row = 2;
+
+	/* Select the appropriate current limit range */
+	if (regulator->da9052->chip_id == DA9052)
+		row = 0;
+	else if (offset == 0)
+		row = 1;
+
+	if (min_uA > da9052_current_limits[row][DA9052_MAX_UA] ||
+	    max_uA < da9052_current_limits[row][DA9052_MIN_UA])
+		return -EINVAL;
+
+	for (i = 0; i < DA9052_CURRENT_RANGE; i++) {
+		if (min_uA <= da9052_current_limits[row][i]) {
+			reg_val = i;
+			break;
+		}
+	}
+
+	/* Determine the even or odd position of the buck current limit
+	 * register field
+	*/
+	if (offset % 2 == 0)
+		return da9052_reg_update(regulator->da9052,
+					 DA9052_BUCKA_REG + offset/2,
+					 DA9052_BUCK_ILIM_MASK_EVEN,
+					 reg_val << 2);
+	else
+		return da9052_reg_update(regulator->da9052,
+					 DA9052_BUCKA_REG + offset/2,
+					 DA9052_BUCK_ILIM_MASK_ODD,
+					 reg_val << 6);
+}
+
+static int da9052_list_buckperi_voltage(struct regulator_dev *rdev,
+					 unsigned int selector)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int volt_uV;
+
+	if ((regulator->da9052->chip_id == DA9052) &&
+	    (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) {
+		volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV)
+			    + info->min_uV);
+		volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)
+			    * (DA9052_BUCK_PERI_3uV_STEP);
+	} else
+			volt_uV = (selector * info->step_uV) + info->min_uV;
+
+	if (volt_uV > info->max_uV)
+		return -EINVAL;
+
+	return volt_uV;
+}
+
+static int da9052_list_voltage(struct regulator_dev *rdev,
+				unsigned int selector)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int volt_uV;
+
+	volt_uV = info->min_uV + info->step_uV * selector;
+
+	if (volt_uV > info->max_uV)
+		return -EINVAL;
+
+	return volt_uV;
+}
+
+static int da9052_regulator_set_voltage_int(struct regulator_dev *rdev,
+					     int min_uV, int max_uV,
+					     unsigned int *selector)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int offset = rdev_get_id(rdev);
+	int ret;
+
+	ret = verify_range(info, min_uV, max_uV);
+	if (ret < 0)
+		return ret;
+
+	if (min_uV < info->min_uV)
+		min_uV = info->min_uV;
+
+	*selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
+
+	ret = da9052_list_voltage(rdev, *selector);
+	if (ret < 0)
+		return ret;
+
+	return da9052_reg_update(regulator->da9052,
+				 DA9052_BUCKCORE_REG + offset,
+				 (1 << info->volt_shift) - 1, *selector);
+}
+
+static int da9052_set_ldo_voltage(struct regulator_dev *rdev,
+				   int min_uV, int max_uV,
+				   unsigned int *selector)
+{
+	return da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector);
+}
+
+static int da9052_set_ldo5_6_voltage(struct regulator_dev *rdev,
+				      int min_uV, int max_uV,
+				      unsigned int *selector)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int ret;
+
+	ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector);
+	if (ret < 0)
+		return ret;
+
+	/* Some LDOs are DVC controlled which requires enabling of
+	 * the LDO activate bit to implment the changes on the
+	 * LDO output.
+	*/
+	return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
+				 info->activate_bit, info->activate_bit);
+}
+
+static int da9052_set_dcdc_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV,
+				    unsigned int *selector)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int ret;
+
+	ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector);
+	if (ret < 0)
+		return ret;
+
+	/* Some DCDCs are DVC controlled which requires enabling of
+	 * the DCDC activate bit to implment the changes on the
+	 * DCDC output.
+	*/
+	return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,
+				 info->activate_bit, info->activate_bit);
+}
+
+static int da9052_get_regulator_voltage_sel(struct regulator_dev *rdev)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int offset = rdev_get_id(rdev);
+	int ret;
+
+	ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset);
+	if (ret < 0)
+		return ret;
+
+	ret &= ((1 << info->volt_shift) - 1);
+
+	return ret;
+}
+
+static int da9052_set_buckperi_voltage(struct regulator_dev *rdev, int min_uV,
+					int max_uV, unsigned int *selector)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int offset = rdev_get_id(rdev);
+	int ret;
+
+	ret = verify_range(info, min_uV, max_uV);
+	if (ret < 0)
+		return ret;
+
+	if (min_uV < info->min_uV)
+		min_uV = info->min_uV;
+
+	if ((regulator->da9052->chip_id == DA9052) &&
+	    (min_uV >= DA9052_CONST_3uV))
+		*selector = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV +
+			    DIV_ROUND_UP(min_uV - DA9052_CONST_3uV,
+					 DA9052_BUCK_PERI_3uV_STEP);
+	else
+		*selector = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
+
+	ret = da9052_list_buckperi_voltage(rdev, *selector);
+	if (ret < 0)
+		return ret;
+
+	return da9052_reg_update(regulator->da9052,
+				 DA9052_BUCKCORE_REG + offset,
+				 (1 << info->volt_shift) - 1, *selector);
+}
+
+static int da9052_get_buckperi_voltage_sel(struct regulator_dev *rdev)
+{
+	struct da9052_regulator *regulator = rdev_get_drvdata(rdev);
+	struct da9052_regulator_info *info = regulator->info;
+	int offset = rdev_get_id(rdev);
+	int ret;
+
+	ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset);
+	if (ret < 0)
+		return ret;
+
+	ret &= ((1 << info->volt_shift) - 1);
+
+	return ret;
+}
+
+static struct regulator_ops da9052_buckperi_ops = {
+	.list_voltage = da9052_list_buckperi_voltage,
+	.get_voltage_sel = da9052_get_buckperi_voltage_sel,
+	.set_voltage = da9052_set_buckperi_voltage,
+
+	.get_current_limit = da9052_dcdc_get_current_limit,
+	.set_current_limit = da9052_dcdc_set_current_limit,
+
+	.is_enabled = da9052_regulator_is_enabled,
+	.enable = da9052_regulator_enable,
+	.disable = da9052_regulator_disable,
+};
+
+static struct regulator_ops da9052_dcdc_ops = {
+	.set_voltage = da9052_set_dcdc_voltage,
+	.get_current_limit = da9052_dcdc_get_current_limit,
+	.set_current_limit = da9052_dcdc_set_current_limit,
+
+	.list_voltage = da9052_list_voltage,
+	.get_voltage_sel = da9052_get_regulator_voltage_sel,
+	.is_enabled = da9052_regulator_is_enabled,
+	.enable = da9052_regulator_enable,
+	.disable = da9052_regulator_disable,
+};
+
+static struct regulator_ops da9052_ldo5_6_ops = {
+	.set_voltage = da9052_set_ldo5_6_voltage,
+
+	.list_voltage = da9052_list_voltage,
+	.get_voltage_sel = da9052_get_regulator_voltage_sel,
+	.is_enabled = da9052_regulator_is_enabled,
+	.enable = da9052_regulator_enable,
+	.disable = da9052_regulator_disable,
+};
+
+static struct regulator_ops da9052_ldo_ops = {
+	.set_voltage = da9052_set_ldo_voltage,
+
+	.list_voltage = da9052_list_voltage,
+	.get_voltage_sel = da9052_get_regulator_voltage_sel,
+	.is_enabled = da9052_regulator_is_enabled,
+	.enable = da9052_regulator_enable,
+	.disable = da9052_regulator_disable,
+};
+
+#define DA9052_LDO5_6(_id, step, min, max, sbits, ebits, abits) \
+{\
+	.reg_desc = {\
+		.name = "LDO" #_id,\
+		.ops = &da9052_ldo5_6_ops,\
+		.type = REGULATOR_VOLTAGE,\
+		.id = _id,\
+		.n_voltages = (max - min) / step + 1, \
+		.owner = THIS_MODULE,\
+	},\
+	.min_uV = (min) * 1000,\
+	.max_uV = (max) * 1000,\
+	.step_uV = (step) * 1000,\
+	.volt_shift = (sbits),\
+	.en_bit = (ebits),\
+	.activate_bit = (abits),\
+}
+
+#define DA9052_LDO(_id, step, min, max, sbits, ebits, abits) \
+{\
+	.reg_desc = {\
+		.name = "LDO" #_id,\
+		.ops = &da9052_ldo_ops,\
+		.type = REGULATOR_VOLTAGE,\
+		.id = _id,\
+		.n_voltages = (max - min) / step + 1, \
+		.owner = THIS_MODULE,\
+	},\
+	.min_uV = (min) * 1000,\
+	.max_uV = (max) * 1000,\
+	.step_uV = (step) * 1000,\
+	.volt_shift = (sbits),\
+	.en_bit = (ebits),\
+	.activate_bit = (abits),\
+}
+
+#define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \
+{\
+	.reg_desc = {\
+		.name = "BUCK" #_id,\
+		.ops = &da9052_dcdc_ops,\
+		.type = REGULATOR_VOLTAGE,\
+		.id = _id,\
+		.n_voltages = (max - min) / step + 1, \
+		.owner = THIS_MODULE,\
+	},\
+	.min_uV = (min) * 1000,\
+	.max_uV = (max) * 1000,\
+	.step_uV = (step) * 1000,\
+	.volt_shift = (sbits),\
+	.en_bit = (ebits),\
+	.activate_bit = (abits),\
+}
+
+#define DA9052_BUCKPERI(_id, step, min, max, sbits, ebits, abits) \
+{\
+	.reg_desc = {\
+		.name = "BUCK" #_id,\
+		.ops = &da9052_buckperi_ops,\
+		.type = REGULATOR_VOLTAGE,\
+		.id = _id,\
+		.n_voltages = (max - min) / step + 1, \
+		.owner = THIS_MODULE,\
+	},\
+	.min_uV = (min) * 1000,\
+	.max_uV = (max) * 1000,\
+	.step_uV = (step) * 1000,\
+	.volt_shift = (sbits),\
+	.en_bit = (ebits),\
+	.activate_bit = (abits),\
+}
+
+static struct da9052_regulator_info da9052_regulator_info[] = {
+	/* Buck1 - 4 */
+	DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
+	DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
+	DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO),
+	DA9052_BUCKPERI(3, 50, 1800, 3600, 5, 6, 0),
+	/* LD01 - LDO10 */
+	DA9052_LDO(4, 50, 600, 1800, 5, 6, 0),
+	DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
+	DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
+	DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0),
+	DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0),
+	DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0),
+	DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0),
+	DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0),
+	DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0),
+	DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0),
+};
+
+static struct da9052_regulator_info da9053_regulator_info[] = {
+	/* Buck1 - 4 */
+	DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
+	DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
+	DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO),
+	DA9052_BUCKPERI(3, 25, 925, 2500, 6, 6, 0),
+	/* LD01 - LDO10 */
+	DA9052_LDO(4, 50, 600, 1800, 5, 6, 0),
+	DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
+	DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
+	DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0),
+	DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0),
+	DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0),
+	DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0),
+	DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0),
+	DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0),
+	DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0),
+};
+
+static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id,
+								 int id)
+{
+	struct da9052_regulator_info *info;
+	int i;
+
+	switch (chip_id) {
+	case DA9052:
+		for (i = 0; i < ARRAY_SIZE(da9052_regulator_info); i++) {
+			info = &da9052_regulator_info[i];
+			if (info->reg_desc.id == id)
+				return info;
+		}
+		break;
+	case DA9053_AA:
+	case DA9053_BA:
+	case DA9053_BB:
+		for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) {
+			info = &da9053_regulator_info[i];
+			if (info->reg_desc.id == id)
+				return info;
+		}
+		break;
+	}
+
+	return NULL;
+}
+
+static int __devinit da9052_regulator_probe(struct platform_device *pdev)
+{
+	struct da9052_regulator *regulator;
+	struct da9052 *da9052;
+	struct da9052_pdata *pdata;
+	int ret;
+
+	regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator),
+				 GFP_KERNEL);
+	if (!regulator)
+		return -ENOMEM;
+
+	da9052 = dev_get_drvdata(pdev->dev.parent);
+	pdata = da9052->dev->platform_data;
+	regulator->da9052 = da9052;
+
+	regulator->info = find_regulator_info(regulator->da9052->chip_id,
+					      pdev->id);
+	if (regulator->info == NULL) {
+		dev_err(&pdev->dev, "invalid regulator ID specified\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	regulator->rdev = regulator_register(&regulator->info->reg_desc,
+					     &pdev->dev,
+					     pdata->regulators[pdev->id],
+					     regulator, NULL);
+	if (IS_ERR(regulator->rdev)) {
+		dev_err(&pdev->dev, "failed to register regulator %s\n",
+			regulator->info->reg_desc.name);
+		ret = PTR_ERR(regulator->rdev);
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, regulator);
+
+	return 0;
+err:
+	devm_kfree(&pdev->dev, regulator);
+	return ret;
+}
+
+static int __devexit da9052_regulator_remove(struct platform_device *pdev)
+{
+	struct da9052_regulator *regulator = platform_get_drvdata(pdev);
+
+	regulator_unregister(regulator->rdev);
+	devm_kfree(&pdev->dev, regulator);
+
+	return 0;
+}
+
+static struct platform_driver da9052_regulator_driver = {
+	.probe = da9052_regulator_probe,
+	.remove = __devexit_p(da9052_regulator_remove),
+	.driver = {
+		.name = "da9052-regulator",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init da9052_regulator_init(void)
+{
+	return platform_driver_register(&da9052_regulator_driver);
+}
+subsys_initcall(da9052_regulator_init);
+
+static void __exit da9052_regulator_exit(void)
+{
+	platform_driver_unregister(&da9052_regulator_driver);
+}
+module_exit(da9052_regulator_exit);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/db8500-prcmu.c b/ap/os/linux/linux-3.4.x/drivers/regulator/db8500-prcmu.c
new file mode 100644
index 0000000..4bd25e7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/db8500-prcmu.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *          Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Power domain regulators on DB8500
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/db8500-prcmu.h>
+#include <linux/module.h>
+#include "dbx500-prcmu.h"
+
+static int db8500_regulator_enable(struct regulator_dev *rdev)
+{
+	struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (info == NULL)
+		return -EINVAL;
+
+	dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n",
+		info->desc.name);
+
+	if (!info->is_enabled) {
+		info->is_enabled = true;
+		if (!info->exclude_from_power_state)
+			power_state_active_enable();
+	}
+
+	return 0;
+}
+
+static int db8500_regulator_disable(struct regulator_dev *rdev)
+{
+	struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret = 0;
+
+	if (info == NULL)
+		return -EINVAL;
+
+	dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n",
+		info->desc.name);
+
+	if (info->is_enabled) {
+		info->is_enabled = false;
+		if (!info->exclude_from_power_state)
+			ret = power_state_active_disable();
+	}
+
+	return ret;
+}
+
+static int db8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (info == NULL)
+		return -EINVAL;
+
+	dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):"
+		" %i\n", info->desc.name, info->is_enabled);
+
+	return info->is_enabled;
+}
+
+/* db8500 regulator operations */
+static struct regulator_ops db8500_regulator_ops = {
+	.enable			= db8500_regulator_enable,
+	.disable		= db8500_regulator_disable,
+	.is_enabled		= db8500_regulator_is_enabled,
+};
+
+/*
+ * EPOD control
+ */
+static bool epod_on[NUM_EPOD_ID];
+static bool epod_ramret[NUM_EPOD_ID];
+
+static int enable_epod(u16 epod_id, bool ramret)
+{
+	int ret;
+
+	if (ramret) {
+		if (!epod_on[epod_id]) {
+			ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+			if (ret < 0)
+				return ret;
+		}
+		epod_ramret[epod_id] = true;
+	} else {
+		ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
+		if (ret < 0)
+			return ret;
+		epod_on[epod_id] = true;
+	}
+
+	return 0;
+}
+
+static int disable_epod(u16 epod_id, bool ramret)
+{
+	int ret;
+
+	if (ramret) {
+		if (!epod_on[epod_id]) {
+			ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+			if (ret < 0)
+				return ret;
+		}
+		epod_ramret[epod_id] = false;
+	} else {
+		if (epod_ramret[epod_id]) {
+			ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+			if (ret < 0)
+				return ret;
+		} else {
+			ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+			if (ret < 0)
+				return ret;
+		}
+		epod_on[epod_id] = false;
+	}
+
+	return 0;
+}
+
+/*
+ * Regulator switch
+ */
+static int db8500_regulator_switch_enable(struct regulator_dev *rdev)
+{
+	struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret;
+
+	if (info == NULL)
+		return -EINVAL;
+
+	dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n",
+		info->desc.name);
+
+	ret = enable_epod(info->epod_id, info->is_ramret);
+	if (ret < 0) {
+		dev_err(rdev_get_dev(rdev),
+			"regulator-switch-%s-enable: prcmu call failed\n",
+			info->desc.name);
+		goto out;
+	}
+
+	info->is_enabled = true;
+out:
+	return ret;
+}
+
+static int db8500_regulator_switch_disable(struct regulator_dev *rdev)
+{
+	struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
+	int ret;
+
+	if (info == NULL)
+		return -EINVAL;
+
+	dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n",
+		info->desc.name);
+
+	ret = disable_epod(info->epod_id, info->is_ramret);
+	if (ret < 0) {
+		dev_err(rdev_get_dev(rdev),
+			"regulator_switch-%s-disable: prcmu call failed\n",
+			info->desc.name);
+		goto out;
+	}
+
+	info->is_enabled = 0;
+out:
+	return ret;
+}
+
+static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev)
+{
+	struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (info == NULL)
+		return -EINVAL;
+
+	dev_vdbg(rdev_get_dev(rdev),
+		"regulator-switch-%s-is_enabled (is_enabled): %i\n",
+		info->desc.name, info->is_enabled);
+
+	return info->is_enabled;
+}
+
+static struct regulator_ops db8500_regulator_switch_ops = {
+	.enable			= db8500_regulator_switch_enable,
+	.disable		= db8500_regulator_switch_disable,
+	.is_enabled		= db8500_regulator_switch_is_enabled,
+};
+
+/*
+ * Regulator information
+ */
+static struct dbx500_regulator_info
+dbx500_regulator_info[DB8500_NUM_REGULATORS] = {
+	[DB8500_REGULATOR_VAPE] = {
+		.desc = {
+			.name	= "db8500-vape",
+			.id	= DB8500_REGULATOR_VAPE,
+			.ops	= &db8500_regulator_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+	},
+	[DB8500_REGULATOR_VARM] = {
+		.desc = {
+			.name	= "db8500-varm",
+			.id	= DB8500_REGULATOR_VARM,
+			.ops	= &db8500_regulator_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+	},
+	[DB8500_REGULATOR_VMODEM] = {
+		.desc = {
+			.name	= "db8500-vmodem",
+			.id	= DB8500_REGULATOR_VMODEM,
+			.ops	= &db8500_regulator_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+	},
+	[DB8500_REGULATOR_VPLL] = {
+		.desc = {
+			.name	= "db8500-vpll",
+			.id	= DB8500_REGULATOR_VPLL,
+			.ops	= &db8500_regulator_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+	},
+	[DB8500_REGULATOR_VSMPS1] = {
+		.desc = {
+			.name	= "db8500-vsmps1",
+			.id	= DB8500_REGULATOR_VSMPS1,
+			.ops	= &db8500_regulator_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+	},
+	[DB8500_REGULATOR_VSMPS2] = {
+		.desc = {
+			.name	= "db8500-vsmps2",
+			.id	= DB8500_REGULATOR_VSMPS2,
+			.ops	= &db8500_regulator_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.exclude_from_power_state = true,
+	},
+	[DB8500_REGULATOR_VSMPS3] = {
+		.desc = {
+			.name	= "db8500-vsmps3",
+			.id	= DB8500_REGULATOR_VSMPS3,
+			.ops	= &db8500_regulator_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+	},
+	[DB8500_REGULATOR_VRF1] = {
+		.desc = {
+			.name	= "db8500-vrf1",
+			.id	= DB8500_REGULATOR_VRF1,
+			.ops	= &db8500_regulator_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+	},
+	[DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
+		.desc = {
+			.name	= "db8500-sva-mmdsp",
+			.id	= DB8500_REGULATOR_SWITCH_SVAMMDSP,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_SVAMMDSP,
+	},
+	[DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
+		.desc = {
+			.name	= "db8500-sva-mmdsp-ret",
+			.id	= DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_SVAMMDSP,
+		.is_ramret = true,
+	},
+	[DB8500_REGULATOR_SWITCH_SVAPIPE] = {
+		.desc = {
+			.name	= "db8500-sva-pipe",
+			.id	= DB8500_REGULATOR_SWITCH_SVAPIPE,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_SVAPIPE,
+	},
+	[DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
+		.desc = {
+			.name	= "db8500-sia-mmdsp",
+			.id	= DB8500_REGULATOR_SWITCH_SIAMMDSP,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_SIAMMDSP,
+	},
+	[DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
+		.desc = {
+			.name	= "db8500-sia-mmdsp-ret",
+			.id	= DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_SIAMMDSP,
+		.is_ramret = true,
+	},
+	[DB8500_REGULATOR_SWITCH_SIAPIPE] = {
+		.desc = {
+			.name	= "db8500-sia-pipe",
+			.id	= DB8500_REGULATOR_SWITCH_SIAPIPE,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_SIAPIPE,
+	},
+	[DB8500_REGULATOR_SWITCH_SGA] = {
+		.desc = {
+			.name	= "db8500-sga",
+			.id	= DB8500_REGULATOR_SWITCH_SGA,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_SGA,
+	},
+	[DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
+		.desc = {
+			.name	= "db8500-b2r2-mcde",
+			.id	= DB8500_REGULATOR_SWITCH_B2R2_MCDE,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_B2R2_MCDE,
+	},
+	[DB8500_REGULATOR_SWITCH_ESRAM12] = {
+		.desc = {
+			.name	= "db8500-esram12",
+			.id	= DB8500_REGULATOR_SWITCH_ESRAM12,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id	= EPOD_ID_ESRAM12,
+		.is_enabled	= true,
+	},
+	[DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
+		.desc = {
+			.name	= "db8500-esram12-ret",
+			.id	= DB8500_REGULATOR_SWITCH_ESRAM12RET,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_ESRAM12,
+		.is_ramret = true,
+	},
+	[DB8500_REGULATOR_SWITCH_ESRAM34] = {
+		.desc = {
+			.name	= "db8500-esram34",
+			.id	= DB8500_REGULATOR_SWITCH_ESRAM34,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id	= EPOD_ID_ESRAM34,
+		.is_enabled	= true,
+	},
+	[DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
+		.desc = {
+			.name	= "db8500-esram34-ret",
+			.id	= DB8500_REGULATOR_SWITCH_ESRAM34RET,
+			.ops	= &db8500_regulator_switch_ops,
+			.type	= REGULATOR_VOLTAGE,
+			.owner	= THIS_MODULE,
+		},
+		.epod_id = EPOD_ID_ESRAM34,
+		.is_ramret = true,
+	},
+};
+
+static int __devinit db8500_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_init_data *db8500_init_data =
+					dev_get_platdata(&pdev->dev);
+	int i, err;
+
+	/* register all regulators */
+	for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
+		struct dbx500_regulator_info *info;
+		struct regulator_init_data *init_data = &db8500_init_data[i];
+
+		/* assign per-regulator data */
+		info = &dbx500_regulator_info[i];
+		info->dev = &pdev->dev;
+
+		/* register with the regulator framework */
+		info->rdev = regulator_register(&info->desc, &pdev->dev,
+				init_data, info, NULL);
+		if (IS_ERR(info->rdev)) {
+			err = PTR_ERR(info->rdev);
+			dev_err(&pdev->dev, "failed to register %s: err %i\n",
+				info->desc.name, err);
+
+			/* if failing, unregister all earlier regulators */
+			while (--i >= 0) {
+				info = &dbx500_regulator_info[i];
+				regulator_unregister(info->rdev);
+			}
+			return err;
+		}
+
+		dev_dbg(rdev_get_dev(info->rdev),
+			"regulator-%s-probed\n", info->desc.name);
+	}
+	err = ux500_regulator_debug_init(pdev,
+					 dbx500_regulator_info,
+					 ARRAY_SIZE(dbx500_regulator_info));
+
+	return err;
+}
+
+static int __exit db8500_regulator_remove(struct platform_device *pdev)
+{
+	int i;
+
+	ux500_regulator_debug_exit();
+
+	for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
+		struct dbx500_regulator_info *info;
+		info = &dbx500_regulator_info[i];
+
+		dev_vdbg(rdev_get_dev(info->rdev),
+			"regulator-%s-remove\n", info->desc.name);
+
+		regulator_unregister(info->rdev);
+	}
+
+	return 0;
+}
+
+static struct platform_driver db8500_regulator_driver = {
+	.driver = {
+		.name = "db8500-prcmu-regulators",
+		.owner = THIS_MODULE,
+	},
+	.probe = db8500_regulator_probe,
+	.remove = __exit_p(db8500_regulator_remove),
+};
+
+static int __init db8500_regulator_init(void)
+{
+	return platform_driver_register(&db8500_regulator_driver);
+}
+
+static void __exit db8500_regulator_exit(void)
+{
+	platform_driver_unregister(&db8500_regulator_driver);
+}
+
+arch_initcall(db8500_regulator_init);
+module_exit(db8500_regulator_exit);
+
+MODULE_AUTHOR("STMicroelectronics/ST-Ericsson");
+MODULE_DESCRIPTION("DB8500 regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/dbx500-prcmu.c b/ap/os/linux/linux-3.4.x/drivers/regulator/dbx500-prcmu.c
new file mode 100644
index 0000000..f2e5ecd
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/dbx500-prcmu.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *          Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * UX500 common part of Power domain regulators
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/regulator/driver.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+
+#include "dbx500-prcmu.h"
+
+/*
+ * power state reference count
+ */
+static int power_state_active_cnt; /* will initialize to zero */
+static DEFINE_SPINLOCK(power_state_active_lock);
+
+int power_state_active_get(void)
+{
+	unsigned long flags;
+	int cnt;
+
+	spin_lock_irqsave(&power_state_active_lock, flags);
+	cnt = power_state_active_cnt;
+	spin_unlock_irqrestore(&power_state_active_lock, flags);
+
+	return cnt;
+}
+
+void power_state_active_enable(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&power_state_active_lock, flags);
+	power_state_active_cnt++;
+	spin_unlock_irqrestore(&power_state_active_lock, flags);
+}
+
+int power_state_active_disable(void)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&power_state_active_lock, flags);
+	if (power_state_active_cnt <= 0) {
+		pr_err("power state: unbalanced enable/disable calls\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	power_state_active_cnt--;
+out:
+	spin_unlock_irqrestore(&power_state_active_lock, flags);
+	return ret;
+}
+
+#ifdef CONFIG_REGULATOR_DEBUG
+
+static struct ux500_regulator_debug {
+	struct dentry *dir;
+	struct dentry *status_file;
+	struct dentry *power_state_cnt_file;
+	struct dbx500_regulator_info *regulator_array;
+	int num_regulators;
+	u8 *state_before_suspend;
+	u8 *state_after_suspend;
+} rdebug;
+
+void ux500_regulator_suspend_debug(void)
+{
+	int i;
+	for (i = 0; i < rdebug.num_regulators; i++)
+		rdebug.state_before_suspend[i] =
+			rdebug.regulator_array[i].is_enabled;
+}
+
+void ux500_regulator_resume_debug(void)
+{
+	int i;
+	for (i = 0; i < rdebug.num_regulators; i++)
+		rdebug.state_after_suspend[i] =
+			rdebug.regulator_array[i].is_enabled;
+}
+
+static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
+{
+	struct device *dev = s->private;
+	int err;
+
+	/* print power state count */
+	err = seq_printf(s, "ux500-regulator power state count: %i\n",
+		power_state_active_get());
+	if (err < 0)
+		dev_err(dev, "seq_printf overflow\n");
+
+	return 0;
+}
+
+static int ux500_regulator_power_state_cnt_open(struct inode *inode,
+	struct file *file)
+{
+	return single_open(file, ux500_regulator_power_state_cnt_print,
+		inode->i_private);
+}
+
+static const struct file_operations ux500_regulator_power_state_cnt_fops = {
+	.open = ux500_regulator_power_state_cnt_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ux500_regulator_status_print(struct seq_file *s, void *p)
+{
+	struct device *dev = s->private;
+	int err;
+	int i;
+
+	/* print dump header */
+	err = seq_printf(s, "ux500-regulator status:\n");
+	if (err < 0)
+		dev_err(dev, "seq_printf overflow\n");
+
+	err = seq_printf(s, "%31s : %8s : %8s\n", "current",
+		"before", "after");
+	if (err < 0)
+		dev_err(dev, "seq_printf overflow\n");
+
+	for (i = 0; i < rdebug.num_regulators; i++) {
+		struct dbx500_regulator_info *info;
+		/* Access per-regulator data */
+		info = &rdebug.regulator_array[i];
+
+		/* print status */
+		err = seq_printf(s, "%20s : %8s : %8s : %8s\n", info->desc.name,
+			info->is_enabled ? "enabled" : "disabled",
+			rdebug.state_before_suspend[i] ? "enabled" : "disabled",
+			rdebug.state_after_suspend[i] ? "enabled" : "disabled");
+		if (err < 0)
+			dev_err(dev, "seq_printf overflow\n");
+	}
+
+	return 0;
+}
+
+static int ux500_regulator_status_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ux500_regulator_status_print,
+		inode->i_private);
+}
+
+static const struct file_operations ux500_regulator_status_fops = {
+	.open = ux500_regulator_status_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+int __attribute__((weak)) dbx500_regulator_testcase(
+	struct dbx500_regulator_info *regulator_info,
+	int num_regulators)
+{
+	return 0;
+}
+
+int __devinit
+ux500_regulator_debug_init(struct platform_device *pdev,
+	struct dbx500_regulator_info *regulator_info,
+	int num_regulators)
+{
+	/* create directory */
+	rdebug.dir = debugfs_create_dir("ux500-regulator", NULL);
+	if (!rdebug.dir)
+		goto exit_no_debugfs;
+
+	/* create "status" file */
+	rdebug.status_file = debugfs_create_file("status",
+		S_IRUGO, rdebug.dir, &pdev->dev,
+		&ux500_regulator_status_fops);
+	if (!rdebug.status_file)
+		goto exit_destroy_dir;
+
+	/* create "power-state-count" file */
+	rdebug.power_state_cnt_file = debugfs_create_file("power-state-count",
+		S_IRUGO, rdebug.dir, &pdev->dev,
+		&ux500_regulator_power_state_cnt_fops);
+	if (!rdebug.power_state_cnt_file)
+		goto exit_destroy_status;
+
+	rdebug.regulator_array = regulator_info;
+	rdebug.num_regulators = num_regulators;
+
+	rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
+	if (!rdebug.state_before_suspend) {
+		dev_err(&pdev->dev,
+			"could not allocate memory for saving state\n");
+		goto exit_destroy_power_state;
+	}
+
+	rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
+	if (!rdebug.state_after_suspend) {
+		dev_err(&pdev->dev,
+			"could not allocate memory for saving state\n");
+		goto exit_free;
+	}
+
+	dbx500_regulator_testcase(regulator_info, num_regulators);
+	return 0;
+
+exit_free:
+	kfree(rdebug.state_before_suspend);
+exit_destroy_power_state:
+	debugfs_remove(rdebug.power_state_cnt_file);
+exit_destroy_status:
+	debugfs_remove(rdebug.status_file);
+exit_destroy_dir:
+	debugfs_remove(rdebug.dir);
+exit_no_debugfs:
+	dev_err(&pdev->dev, "failed to create debugfs entries.\n");
+	return -ENOMEM;
+}
+
+int __devexit ux500_regulator_debug_exit(void)
+{
+	debugfs_remove_recursive(rdebug.dir);
+	kfree(rdebug.state_after_suspend);
+	kfree(rdebug.state_before_suspend);
+
+	return 0;
+}
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/dbx500-prcmu.h b/ap/os/linux/linux-3.4.x/drivers/regulator/dbx500-prcmu.h
new file mode 100644
index 0000000..e763883
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/dbx500-prcmu.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Bengt Jonsson <bengt.jonsson@stericsson.com> for ST-Ericsson,
+ *	   Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ *
+ * License Terms: GNU General Public License v2
+ *
+ */
+
+#ifndef DBX500_REGULATOR_H
+#define DBX500_REGULATOR_H
+
+#include <linux/platform_device.h>
+
+/**
+ * struct dbx500_regulator_info - dbx500 regulator information
+ * @dev: device pointer
+ * @desc: regulator description
+ * @rdev: regulator device pointer
+ * @is_enabled: status of the regulator
+ * @epod_id: id for EPOD (power domain)
+ * @is_ramret: RAM retention switch for EPOD (power domain)
+ * @operating_point: operating point (only for vape, to be removed)
+ *
+ */
+struct dbx500_regulator_info {
+	struct device *dev;
+	struct regulator_desc desc;
+	struct regulator_dev *rdev;
+	bool is_enabled;
+	u16 epod_id;
+	bool is_ramret;
+	bool exclude_from_power_state;
+	unsigned int operating_point;
+};
+
+void power_state_active_enable(void);
+int power_state_active_disable(void);
+
+
+#ifdef CONFIG_REGULATOR_DEBUG
+int ux500_regulator_debug_init(struct platform_device *pdev,
+			       struct dbx500_regulator_info *regulator_info,
+			       int num_regulators);
+
+int ux500_regulator_debug_exit(void);
+#else
+
+static inline int ux500_regulator_debug_init(struct platform_device *pdev,
+			     struct dbx500_regulator_info *regulator_info,
+			     int num_regulators)
+{
+	return 0;
+}
+
+static inline int ux500_regulator_debug_exit(void)
+{
+	return 0;
+}
+
+#endif
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/dummy.c b/ap/os/linux/linux-3.4.x/drivers/regulator/dummy.c
new file mode 100644
index 0000000..0ee00de
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/dummy.c
@@ -0,0 +1,87 @@
+/*
+ * dummy.c
+ *
+ * Copyright 2010 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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 is useful for systems with mixed controllable and
+ * non-controllable regulators, as well as for allowing testing on
+ * systems with no controllable regulators.
+ */
+
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include "dummy.h"
+
+struct regulator_dev *dummy_regulator_rdev;
+
+static struct regulator_init_data dummy_initdata;
+
+static struct regulator_ops dummy_ops;
+
+static struct regulator_desc dummy_desc = {
+	.name = "dummy",
+	.id = -1,
+	.type = REGULATOR_VOLTAGE,
+	.owner = THIS_MODULE,
+	.ops = &dummy_ops,
+};
+
+static int __devinit dummy_regulator_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
+						  &dummy_initdata, NULL, NULL);
+	if (IS_ERR(dummy_regulator_rdev)) {
+		ret = PTR_ERR(dummy_regulator_rdev);
+		pr_err("Failed to register regulator: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct platform_driver dummy_regulator_driver = {
+	.probe		= dummy_regulator_probe,
+	.driver		= {
+		.name		= "reg-dummy",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static struct platform_device *dummy_pdev;
+
+void __init regulator_dummy_init(void)
+{
+	int ret;
+
+	dummy_pdev = platform_device_alloc("reg-dummy", -1);
+	if (!dummy_pdev) {
+		pr_err("Failed to allocate dummy regulator device\n");
+		return;
+	}
+
+	ret = platform_device_add(dummy_pdev);
+	if (ret != 0) {
+		pr_err("Failed to register dummy regulator device: %d\n", ret);
+		platform_device_put(dummy_pdev);
+		return;
+	}
+
+	ret = platform_driver_register(&dummy_regulator_driver);
+	if (ret != 0) {
+		pr_err("Failed to register dummy regulator driver: %d\n", ret);
+		platform_device_unregister(dummy_pdev);
+	}
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/dummy.h b/ap/os/linux/linux-3.4.x/drivers/regulator/dummy.h
new file mode 100644
index 0000000..97a11b7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/dummy.h
@@ -0,0 +1,27 @@
+/*
+ * dummy.h
+ *
+ * Copyright 2010 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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 is useful for systems with mixed controllable and
+ * non-controllable regulators, as well as for allowing testing on
+ * systems with no controllable regulators.
+ */
+
+#ifndef _DUMMY_H
+#define _DUMMY_H
+
+struct regulator_dev;
+
+extern struct regulator_dev *dummy_regulator_rdev;
+
+void __init regulator_dummy_init(void);
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/fixed-helper.c b/ap/os/linux/linux-3.4.x/drivers/regulator/fixed-helper.c
new file mode 100644
index 0000000..cacd33c
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/fixed-helper.c
@@ -0,0 +1,52 @@
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+
+struct fixed_regulator_data {
+	struct fixed_voltage_config cfg;
+	struct regulator_init_data init_data;
+	struct platform_device pdev;
+};
+
+static void regulator_fixed_release(struct device *dev)
+{
+	struct fixed_regulator_data *data = container_of(dev,
+			struct fixed_regulator_data, pdev.dev);
+	kfree(data);
+}
+
+/**
+ * regulator_register_fixed - register a no-op fixed regulator
+ * @id: platform device id
+ * @supplies: consumers for this regulator
+ * @num_supplies: number of consumers
+ */
+struct platform_device *regulator_register_fixed(int id,
+		struct regulator_consumer_supply *supplies, int num_supplies)
+{
+	struct fixed_regulator_data *data;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	data->cfg.supply_name = "fixed-dummy";
+	data->cfg.microvolts = 0;
+	data->cfg.gpio = -EINVAL;
+	data->cfg.enabled_at_boot = 1;
+	data->cfg.init_data = &data->init_data;
+
+	data->init_data.constraints.always_on = 1;
+	data->init_data.consumer_supplies = supplies;
+	data->init_data.num_consumer_supplies = num_supplies;
+
+	data->pdev.name = "reg-fixed-voltage";
+	data->pdev.id = id;
+	data->pdev.dev.platform_data = &data->cfg;
+	data->pdev.dev.release = regulator_fixed_release;
+
+	platform_device_register(&data->pdev);
+
+	return &data->pdev;
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/fixed.c b/ap/os/linux/linux-3.4.x/drivers/regulator/fixed.c
new file mode 100644
index 0000000..40f3803
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/fixed.c
@@ -0,0 +1,325 @@
+/*
+ * fixed.c
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * Copyright (c) 2009 Nokia Corporation
+ * Roger Quadros <ext-roger.quadros@nokia.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 is useful for systems with mixed controllable and
+ * non-controllable regulators, as well as for allowing testing on
+ * systems with no controllable regulators.
+ */
+
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/fixed.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+
+struct fixed_voltage_data {
+	struct regulator_desc desc;
+	struct regulator_dev *dev;
+	int microvolts;
+	int gpio;
+	unsigned startup_delay;
+	bool enable_high;
+	bool is_enabled;
+};
+
+
+/**
+ * of_get_fixed_voltage_config - extract fixed_voltage_config structure info
+ * @dev: device requesting for fixed_voltage_config
+ *
+ * Populates fixed_voltage_config structure by extracting data from device
+ * tree node, returns a pointer to the populated structure of NULL if memory
+ * alloc fails.
+ */
+static struct fixed_voltage_config *
+of_get_fixed_voltage_config(struct device *dev)
+{
+	struct fixed_voltage_config *config;
+	struct device_node *np = dev->of_node;
+	const __be32 *delay;
+	struct regulator_init_data *init_data;
+
+	config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
+								 GFP_KERNEL);
+	if (!config)
+		return NULL;
+
+	config->init_data = of_get_regulator_init_data(dev, dev->of_node);
+	if (!config->init_data)
+		return NULL;
+
+	init_data = config->init_data;
+	init_data->constraints.apply_uV = 0;
+
+	config->supply_name = init_data->constraints.name;
+	if (init_data->constraints.min_uV == init_data->constraints.max_uV) {
+		config->microvolts = init_data->constraints.min_uV;
+	} else {
+		dev_err(dev,
+			 "Fixed regulator specified with variable voltages\n");
+		return NULL;
+	}
+
+	if (init_data->constraints.boot_on)
+		config->enabled_at_boot = true;
+
+	config->gpio = of_get_named_gpio(np, "gpio", 0);
+	delay = of_get_property(np, "startup-delay-us", NULL);
+	if (delay)
+		config->startup_delay = be32_to_cpu(*delay);
+
+	if (of_find_property(np, "enable-active-high", NULL))
+		config->enable_high = true;
+
+	return config;
+}
+
+static int fixed_voltage_is_enabled(struct regulator_dev *dev)
+{
+	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
+
+	return data->is_enabled;
+}
+
+static int fixed_voltage_enable(struct regulator_dev *dev)
+{
+	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
+
+	if (gpio_is_valid(data->gpio)) {
+		gpio_set_value_cansleep(data->gpio, data->enable_high);
+		data->is_enabled = true;
+	}
+
+	return 0;
+}
+
+static int fixed_voltage_disable(struct regulator_dev *dev)
+{
+	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
+
+	if (gpio_is_valid(data->gpio)) {
+		gpio_set_value_cansleep(data->gpio, !data->enable_high);
+		data->is_enabled = false;
+	}
+
+	return 0;
+}
+
+static int fixed_voltage_enable_time(struct regulator_dev *dev)
+{
+	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
+
+	return data->startup_delay;
+}
+
+static int fixed_voltage_get_voltage(struct regulator_dev *dev)
+{
+	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
+
+	if (data->microvolts)
+		return data->microvolts;
+	else
+		return -EINVAL;
+}
+
+static int fixed_voltage_list_voltage(struct regulator_dev *dev,
+				      unsigned selector)
+{
+	struct fixed_voltage_data *data = rdev_get_drvdata(dev);
+
+	if (selector != 0)
+		return -EINVAL;
+
+	return data->microvolts;
+}
+
+static struct regulator_ops fixed_voltage_ops = {
+	.is_enabled = fixed_voltage_is_enabled,
+	.enable = fixed_voltage_enable,
+	.disable = fixed_voltage_disable,
+	.enable_time = fixed_voltage_enable_time,
+	.get_voltage = fixed_voltage_get_voltage,
+	.list_voltage = fixed_voltage_list_voltage,
+};
+
+static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
+{
+	struct fixed_voltage_config *config;
+	struct fixed_voltage_data *drvdata;
+	int ret;
+
+	if (pdev->dev.of_node)
+		config = of_get_fixed_voltage_config(&pdev->dev);
+	else
+		config = pdev->dev.platform_data;
+
+	if (!config)
+		return -ENOMEM;
+
+	drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL);
+	if (drvdata == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate device data\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
+	if (drvdata->desc.name == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate supply name\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	drvdata->desc.type = REGULATOR_VOLTAGE;
+	drvdata->desc.owner = THIS_MODULE;
+	drvdata->desc.ops = &fixed_voltage_ops;
+
+	if (config->microvolts)
+		drvdata->desc.n_voltages = 1;
+
+	drvdata->microvolts = config->microvolts;
+	drvdata->gpio = config->gpio;
+	drvdata->startup_delay = config->startup_delay;
+
+	if (gpio_is_valid(config->gpio)) {
+		drvdata->enable_high = config->enable_high;
+
+		/* FIXME: Remove below print warning
+		 *
+		 * config->gpio must be set to -EINVAL by platform code if
+		 * GPIO control is not required. However, early adopters
+		 * not requiring GPIO control may forget to initialize
+		 * config->gpio to -EINVAL. This will cause GPIO 0 to be used
+		 * for GPIO control.
+		 *
+		 * This warning will be removed once there are a couple of users
+		 * for this driver.
+		 */
+		if (!config->gpio)
+			dev_warn(&pdev->dev,
+				"using GPIO 0 for regulator enable control\n");
+
+		ret = gpio_request(config->gpio, config->supply_name);
+		if (ret) {
+			dev_err(&pdev->dev,
+			   "Could not obtain regulator enable GPIO %d: %d\n",
+							config->gpio, ret);
+			goto err_name;
+		}
+
+		/* set output direction without changing state
+		 * to prevent glitch
+		 */
+		drvdata->is_enabled = config->enabled_at_boot;
+		ret = drvdata->is_enabled ?
+				config->enable_high : !config->enable_high;
+
+		ret = gpio_direction_output(config->gpio, ret);
+		if (ret) {
+			dev_err(&pdev->dev,
+			   "Could not configure regulator enable GPIO %d direction: %d\n",
+							config->gpio, ret);
+			goto err_gpio;
+		}
+
+	} else {
+		/* Regulator without GPIO control is considered
+		 * always enabled
+		 */
+		drvdata->is_enabled = true;
+	}
+
+	drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
+					  config->init_data, drvdata,
+					  pdev->dev.of_node);
+	if (IS_ERR(drvdata->dev)) {
+		ret = PTR_ERR(drvdata->dev);
+		dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
+		goto err_gpio;
+	}
+
+	platform_set_drvdata(pdev, drvdata);
+
+	dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name,
+		drvdata->microvolts);
+
+	return 0;
+
+err_gpio:
+	if (gpio_is_valid(config->gpio))
+		gpio_free(config->gpio);
+err_name:
+	kfree(drvdata->desc.name);
+err:
+	kfree(drvdata);
+	return ret;
+}
+
+static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev)
+{
+	struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
+
+	regulator_unregister(drvdata->dev);
+	if (gpio_is_valid(drvdata->gpio))
+		gpio_free(drvdata->gpio);
+	kfree(drvdata->desc.name);
+	kfree(drvdata);
+
+	return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id fixed_of_match[] __devinitconst = {
+	{ .compatible = "regulator-fixed", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, fixed_of_match);
+#else
+#define fixed_of_match NULL
+#endif
+
+static struct platform_driver regulator_fixed_voltage_driver = {
+	.probe		= reg_fixed_voltage_probe,
+	.remove		= __devexit_p(reg_fixed_voltage_remove),
+	.driver		= {
+		.name		= "reg-fixed-voltage",
+		.owner		= THIS_MODULE,
+		.of_match_table = fixed_of_match,
+	},
+};
+
+static int __init regulator_fixed_voltage_init(void)
+{
+	return platform_driver_register(&regulator_fixed_voltage_driver);
+}
+subsys_initcall(regulator_fixed_voltage_init);
+
+static void __exit regulator_fixed_voltage_exit(void)
+{
+	platform_driver_unregister(&regulator_fixed_voltage_driver);
+}
+module_exit(regulator_fixed_voltage_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Fixed voltage regulator");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:reg-fixed-voltage");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/gpio-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/gpio-regulator.c
new file mode 100644
index 0000000..42e1cb1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/gpio-regulator.c
@@ -0,0 +1,358 @@
+/*
+ * gpio-regulator.c
+ *
+ * Copyright 2011 Heiko Stuebner <heiko@sntech.de>
+ *
+ * based on fixed.c
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * Copyright (c) 2009 Nokia Corporation
+ * Roger Quadros <ext-roger.quadros@nokia.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 is useful for systems with mixed controllable and
+ * non-controllable regulators, as well as for allowing testing on
+ * systems with no controllable regulators.
+ */
+
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/gpio-regulator.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+struct gpio_regulator_data {
+	struct regulator_desc desc;
+	struct regulator_dev *dev;
+
+	int enable_gpio;
+	bool enable_high;
+	bool is_enabled;
+	unsigned startup_delay;
+
+	struct gpio *gpios;
+	int nr_gpios;
+
+	struct gpio_regulator_state *states;
+	int nr_states;
+
+	int state;
+};
+
+static int gpio_regulator_is_enabled(struct regulator_dev *dev)
+{
+	struct gpio_regulator_data *data = rdev_get_drvdata(dev);
+
+	return data->is_enabled;
+}
+
+static int gpio_regulator_enable(struct regulator_dev *dev)
+{
+	struct gpio_regulator_data *data = rdev_get_drvdata(dev);
+
+	if (gpio_is_valid(data->enable_gpio)) {
+		gpio_set_value_cansleep(data->enable_gpio, data->enable_high);
+		data->is_enabled = true;
+	}
+
+	return 0;
+}
+
+static int gpio_regulator_disable(struct regulator_dev *dev)
+{
+	struct gpio_regulator_data *data = rdev_get_drvdata(dev);
+
+	if (gpio_is_valid(data->enable_gpio)) {
+		gpio_set_value_cansleep(data->enable_gpio, !data->enable_high);
+		data->is_enabled = false;
+	}
+
+	return 0;
+}
+
+static int gpio_regulator_enable_time(struct regulator_dev *dev)
+{
+	struct gpio_regulator_data *data = rdev_get_drvdata(dev);
+
+	return data->startup_delay;
+}
+
+static int gpio_regulator_get_value(struct regulator_dev *dev)
+{
+	struct gpio_regulator_data *data = rdev_get_drvdata(dev);
+	int ptr;
+
+	for (ptr = 0; ptr < data->nr_states; ptr++)
+		if (data->states[ptr].gpios == data->state)
+			return data->states[ptr].value;
+
+	return -EINVAL;
+}
+
+static int gpio_regulator_set_value(struct regulator_dev *dev,
+					int min, int max)
+{
+	struct gpio_regulator_data *data = rdev_get_drvdata(dev);
+	int ptr, target, state;
+
+	target = -1;
+	for (ptr = 0; ptr < data->nr_states; ptr++)
+		if (data->states[ptr].value >= min &&
+		    data->states[ptr].value <= max)
+			target = data->states[ptr].gpios;
+
+	if (target < 0)
+		return -EINVAL;
+
+	for (ptr = 0; ptr < data->nr_gpios; ptr++) {
+		state = (target & (1 << ptr)) >> ptr;
+		gpio_set_value(data->gpios[ptr].gpio, state);
+	}
+	data->state = target;
+
+	return 0;
+}
+
+static int gpio_regulator_set_voltage(struct regulator_dev *dev,
+					int min_uV, int max_uV,
+					unsigned *selector)
+{
+	return gpio_regulator_set_value(dev, min_uV, max_uV);
+}
+
+static int gpio_regulator_list_voltage(struct regulator_dev *dev,
+				      unsigned selector)
+{
+	struct gpio_regulator_data *data = rdev_get_drvdata(dev);
+
+	if (selector >= data->nr_states)
+		return -EINVAL;
+
+	return data->states[selector].value;
+}
+
+static int gpio_regulator_set_current_limit(struct regulator_dev *dev,
+					int min_uA, int max_uA)
+{
+	return gpio_regulator_set_value(dev, min_uA, max_uA);
+}
+
+static struct regulator_ops gpio_regulator_voltage_ops = {
+	.is_enabled = gpio_regulator_is_enabled,
+	.enable = gpio_regulator_enable,
+	.disable = gpio_regulator_disable,
+	.enable_time = gpio_regulator_enable_time,
+	.get_voltage = gpio_regulator_get_value,
+	.set_voltage = gpio_regulator_set_voltage,
+	.list_voltage = gpio_regulator_list_voltage,
+};
+
+static struct regulator_ops gpio_regulator_current_ops = {
+	.is_enabled = gpio_regulator_is_enabled,
+	.enable = gpio_regulator_enable,
+	.disable = gpio_regulator_disable,
+	.enable_time = gpio_regulator_enable_time,
+	.get_current_limit = gpio_regulator_get_value,
+	.set_current_limit = gpio_regulator_set_current_limit,
+};
+
+static int __devinit gpio_regulator_probe(struct platform_device *pdev)
+{
+	struct gpio_regulator_config *config = pdev->dev.platform_data;
+	struct gpio_regulator_data *drvdata;
+	int ptr, ret, state;
+
+	drvdata = kzalloc(sizeof(struct gpio_regulator_data), GFP_KERNEL);
+	if (drvdata == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate device data\n");
+		return -ENOMEM;
+	}
+
+	drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
+	if (drvdata->desc.name == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate supply name\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	drvdata->gpios = kmemdup(config->gpios,
+				 config->nr_gpios * sizeof(struct gpio),
+				 GFP_KERNEL);
+	if (drvdata->gpios == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate gpio data\n");
+		ret = -ENOMEM;
+		goto err_name;
+	}
+
+	drvdata->states = kmemdup(config->states,
+				  config->nr_states *
+					 sizeof(struct gpio_regulator_state),
+				  GFP_KERNEL);
+	if (drvdata->states == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate state data\n");
+		ret = -ENOMEM;
+		goto err_memgpio;
+	}
+	drvdata->nr_states = config->nr_states;
+
+	drvdata->desc.owner = THIS_MODULE;
+
+	/* handle regulator type*/
+	switch (config->type) {
+	case REGULATOR_VOLTAGE:
+		drvdata->desc.type = REGULATOR_VOLTAGE;
+		drvdata->desc.ops = &gpio_regulator_voltage_ops;
+		drvdata->desc.n_voltages = config->nr_states;
+		break;
+	case REGULATOR_CURRENT:
+		drvdata->desc.type = REGULATOR_CURRENT;
+		drvdata->desc.ops = &gpio_regulator_current_ops;
+		break;
+	default:
+		dev_err(&pdev->dev, "No regulator type set\n");
+		ret = -EINVAL;
+		goto err_memgpio;
+		break;
+	}
+
+	drvdata->enable_gpio = config->enable_gpio;
+	drvdata->startup_delay = config->startup_delay;
+
+	if (gpio_is_valid(config->enable_gpio)) {
+		drvdata->enable_high = config->enable_high;
+
+		ret = gpio_request(config->enable_gpio, config->supply_name);
+		if (ret) {
+			dev_err(&pdev->dev,
+			   "Could not obtain regulator enable GPIO %d: %d\n",
+						config->enable_gpio, ret);
+			goto err_memstate;
+		}
+
+		/* set output direction without changing state
+		 * to prevent glitch
+		 */
+		if (config->enabled_at_boot) {
+			drvdata->is_enabled = true;
+			ret = gpio_direction_output(config->enable_gpio,
+						    config->enable_high);
+		} else {
+			drvdata->is_enabled = false;
+			ret = gpio_direction_output(config->enable_gpio,
+						    !config->enable_high);
+		}
+
+		if (ret) {
+			dev_err(&pdev->dev,
+			   "Could not configure regulator enable GPIO %d direction: %d\n",
+						config->enable_gpio, ret);
+			goto err_enablegpio;
+		}
+	} else {
+		/* Regulator without GPIO control is considered
+		 * always enabled
+		 */
+		drvdata->is_enabled = true;
+	}
+
+	drvdata->nr_gpios = config->nr_gpios;
+	ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
+	if (ret) {
+		dev_err(&pdev->dev,
+		   "Could not obtain regulator setting GPIOs: %d\n", ret);
+		goto err_enablegpio;
+	}
+
+	/* build initial state from gpio init data. */
+	state = 0;
+	for (ptr = 0; ptr < drvdata->nr_gpios; ptr++) {
+		if (config->gpios[ptr].flags & GPIOF_OUT_INIT_HIGH)
+			state |= (1 << ptr);
+	}
+	drvdata->state = state;
+
+	drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
+					  config->init_data, drvdata, NULL);
+	if (IS_ERR(drvdata->dev)) {
+		ret = PTR_ERR(drvdata->dev);
+		dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
+		goto err_stategpio;
+	}
+
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;
+
+err_stategpio:
+	gpio_free_array(drvdata->gpios, drvdata->nr_gpios);
+err_enablegpio:
+	if (gpio_is_valid(config->enable_gpio))
+		gpio_free(config->enable_gpio);
+err_memstate:
+	kfree(drvdata->states);
+err_memgpio:
+	kfree(drvdata->gpios);
+err_name:
+	kfree(drvdata->desc.name);
+err:
+	kfree(drvdata);
+	return ret;
+}
+
+static int __devexit gpio_regulator_remove(struct platform_device *pdev)
+{
+	struct gpio_regulator_data *drvdata = platform_get_drvdata(pdev);
+
+	regulator_unregister(drvdata->dev);
+
+	gpio_free_array(drvdata->gpios, drvdata->nr_gpios);
+
+	kfree(drvdata->states);
+	kfree(drvdata->gpios);
+
+	if (gpio_is_valid(drvdata->enable_gpio))
+		gpio_free(drvdata->enable_gpio);
+
+	kfree(drvdata->desc.name);
+	kfree(drvdata);
+
+	return 0;
+}
+
+static struct platform_driver gpio_regulator_driver = {
+	.probe		= gpio_regulator_probe,
+	.remove		= __devexit_p(gpio_regulator_remove),
+	.driver		= {
+		.name		= "gpio-regulator",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init gpio_regulator_init(void)
+{
+	return platform_driver_register(&gpio_regulator_driver);
+}
+subsys_initcall(gpio_regulator_init);
+
+static void __exit gpio_regulator_exit(void)
+{
+	platform_driver_unregister(&gpio_regulator_driver);
+}
+module_exit(gpio_regulator_exit);
+
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_DESCRIPTION("gpio voltage regulator");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/isl6271a-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/isl6271a-regulator.c
new file mode 100644
index 0000000..775f5fd
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/isl6271a-regulator.c
@@ -0,0 +1,230 @@
+/*
+ * isl6271a-regulator.c
+ *
+ * Support for Intersil ISL6271A voltage regulator
+ *
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#define	ISL6271A_VOLTAGE_MIN	850000
+#define	ISL6271A_VOLTAGE_MAX	1600000
+#define	ISL6271A_VOLTAGE_STEP	50000
+
+/* PMIC details */
+struct isl_pmic {
+	struct i2c_client	*client;
+	struct regulator_dev	*rdev[3];
+	struct mutex		mtx;
+};
+
+static int isl6271a_get_voltage(struct regulator_dev *dev)
+{
+	struct isl_pmic *pmic = rdev_get_drvdata(dev);
+	int idx, data;
+
+	mutex_lock(&pmic->mtx);
+
+	idx = i2c_smbus_read_byte(pmic->client);
+	if (idx < 0) {
+		dev_err(&pmic->client->dev, "Error getting voltage\n");
+		data = idx;
+		goto out;
+	}
+
+	/* Convert the data from chip to microvolts */
+	data = ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * (idx & 0xf));
+
+out:
+	mutex_unlock(&pmic->mtx);
+	return data;
+}
+
+static int isl6271a_set_voltage(struct regulator_dev *dev,
+				int minuV, int maxuV,
+				unsigned *selector)
+{
+	struct isl_pmic *pmic = rdev_get_drvdata(dev);
+	int err, data;
+
+	if (minuV < ISL6271A_VOLTAGE_MIN || minuV > ISL6271A_VOLTAGE_MAX)
+		return -EINVAL;
+	if (maxuV < ISL6271A_VOLTAGE_MIN || maxuV > ISL6271A_VOLTAGE_MAX)
+		return -EINVAL;
+
+	data = DIV_ROUND_UP(minuV - ISL6271A_VOLTAGE_MIN,
+			    ISL6271A_VOLTAGE_STEP);
+	*selector = data;
+
+	mutex_lock(&pmic->mtx);
+
+	err = i2c_smbus_write_byte(pmic->client, data);
+	if (err < 0)
+		dev_err(&pmic->client->dev, "Error setting voltage\n");
+
+	mutex_unlock(&pmic->mtx);
+	return err;
+}
+
+static int isl6271a_list_voltage(struct regulator_dev *dev, unsigned selector)
+{
+	return ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * selector);
+}
+
+static struct regulator_ops isl_core_ops = {
+	.get_voltage	= isl6271a_get_voltage,
+	.set_voltage	= isl6271a_set_voltage,
+	.list_voltage	= isl6271a_list_voltage,
+};
+
+static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
+{
+	int id = rdev_get_id(dev);
+	return (id == 1) ? 1100000 : 1300000;
+}
+
+static int isl6271a_list_fixed_voltage(struct regulator_dev *dev, unsigned selector)
+{
+	int id = rdev_get_id(dev);
+	return (id == 1) ? 1100000 : 1300000;
+}
+
+static struct regulator_ops isl_fixed_ops = {
+	.get_voltage	= isl6271a_get_fixed_voltage,
+	.list_voltage	= isl6271a_list_fixed_voltage,
+};
+
+static struct regulator_desc isl_rd[] = {
+	{
+		.name		= "Core Buck",
+		.id		= 0,
+		.n_voltages	= 16,
+		.ops		= &isl_core_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO1",
+		.id		= 1,
+		.n_voltages	= 1,
+		.ops		= &isl_fixed_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO2",
+		.id		= 2,
+		.n_voltages	= 1,
+		.ops		= &isl_fixed_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __devinit isl6271a_probe(struct i2c_client *i2c,
+				     const struct i2c_device_id *id)
+{
+	struct regulator_init_data *init_data	= i2c->dev.platform_data;
+	struct isl_pmic *pmic;
+	int err, i;
+
+	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	if (!init_data) {
+		dev_err(&i2c->dev, "no platform data supplied\n");
+		return -EIO;
+	}
+
+	pmic = kzalloc(sizeof(struct isl_pmic), GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	pmic->client = i2c;
+
+	mutex_init(&pmic->mtx);
+
+	for (i = 0; i < 3; i++) {
+		pmic->rdev[i] = regulator_register(&isl_rd[i], &i2c->dev,
+						init_data, pmic, NULL);
+		if (IS_ERR(pmic->rdev[i])) {
+			dev_err(&i2c->dev, "failed to register %s\n", id->name);
+			err = PTR_ERR(pmic->rdev[i]);
+			goto error;
+		}
+	}
+
+	i2c_set_clientdata(i2c, pmic);
+
+	return 0;
+
+error:
+	while (--i >= 0)
+		regulator_unregister(pmic->rdev[i]);
+
+	kfree(pmic);
+	return err;
+}
+
+static int __devexit isl6271a_remove(struct i2c_client *i2c)
+{
+	struct isl_pmic *pmic = i2c_get_clientdata(i2c);
+	int i;
+
+	for (i = 0; i < 3; i++)
+		regulator_unregister(pmic->rdev[i]);
+
+	kfree(pmic);
+
+	return 0;
+}
+
+static const struct i2c_device_id isl6271a_id[] = {
+	{.name = "isl6271a", 0 },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, isl6271a_id);
+
+static struct i2c_driver isl6271a_i2c_driver = {
+	.driver = {
+		.name = "isl6271a",
+		.owner = THIS_MODULE,
+	},
+	.probe = isl6271a_probe,
+	.remove = __devexit_p(isl6271a_remove),
+	.id_table = isl6271a_id,
+};
+
+static int __init isl6271a_init(void)
+{
+	return i2c_add_driver(&isl6271a_i2c_driver);
+}
+
+static void __exit isl6271a_cleanup(void)
+{
+	i2c_del_driver(&isl6271a_i2c_driver);
+}
+
+subsys_initcall(isl6271a_init);
+module_exit(isl6271a_cleanup);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("Intersil ISL6271A voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/lp3971.c b/ap/os/linux/linux-3.4.x/drivers/regulator/lp3971.c
new file mode 100644
index 0000000..0cfabd3
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/lp3971.c
@@ -0,0 +1,568 @@
+/*
+ * Regulator driver for National Semiconductors LP3971 PMIC chip
+ *
+ *  Copyright (C) 2009 Samsung Electronics
+ *  Author: Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * Based on wm8350.c
+ *
+ * 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/bug.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/lp3971.h>
+#include <linux/slab.h>
+
+struct lp3971 {
+	struct device *dev;
+	struct mutex io_lock;
+	struct i2c_client *i2c;
+	int num_regulators;
+	struct regulator_dev **rdev;
+};
+
+static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg);
+static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val);
+
+#define LP3971_SYS_CONTROL1_REG 0x07
+
+/* System control register 1 initial value,
+   bits 4 and 5 are EPROM programmable */
+#define SYS_CONTROL1_INIT_VAL 0x40
+#define SYS_CONTROL1_INIT_MASK 0xCF
+
+#define LP3971_BUCK_VOL_ENABLE_REG 0x10
+#define LP3971_BUCK_VOL_CHANGE_REG 0x20
+
+/*	Voltage control registers shift:
+	LP3971_BUCK1 -> 0
+	LP3971_BUCK2 -> 4
+	LP3971_BUCK3 -> 6
+*/
+#define BUCK_VOL_CHANGE_SHIFT(x) (((!!x) << 2) | (x & ~0x01))
+#define BUCK_VOL_CHANGE_FLAG_GO 0x01
+#define BUCK_VOL_CHANGE_FLAG_TARGET 0x02
+#define BUCK_VOL_CHANGE_FLAG_MASK 0x03
+
+#define LP3971_BUCK1_BASE 0x23
+#define LP3971_BUCK2_BASE 0x29
+#define LP3971_BUCK3_BASE 0x32
+
+static const int buck_base_addr[] = {
+	LP3971_BUCK1_BASE,
+	LP3971_BUCK2_BASE,
+	LP3971_BUCK3_BASE,
+};
+
+#define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
+#define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
+
+static const int buck_voltage_map[] = {
+	   0,  800,  850,  900,  950, 1000, 1050, 1100,
+	1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
+	1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
+	3000, 3300,
+};
+
+#define BUCK_TARGET_VOL_MASK 0x3f
+#define BUCK_TARGET_VOL_MIN_IDX 0x01
+#define BUCK_TARGET_VOL_MAX_IDX 0x19
+
+#define LP3971_BUCK_RAMP_REG(x)	(buck_base_addr[x]+2)
+
+#define LP3971_LDO_ENABLE_REG 0x12
+#define LP3971_LDO_VOL_CONTR_BASE 0x39
+
+/*	Voltage control registers:
+	LP3971_LDO1 -> LP3971_LDO_VOL_CONTR_BASE + 0
+	LP3971_LDO2 -> LP3971_LDO_VOL_CONTR_BASE + 0
+	LP3971_LDO3 -> LP3971_LDO_VOL_CONTR_BASE + 1
+	LP3971_LDO4 -> LP3971_LDO_VOL_CONTR_BASE + 1
+	LP3971_LDO5 -> LP3971_LDO_VOL_CONTR_BASE + 2
+*/
+#define LP3971_LDO_VOL_CONTR_REG(x)	(LP3971_LDO_VOL_CONTR_BASE + (x >> 1))
+
+/*	Voltage control registers shift:
+	LP3971_LDO1 -> 0, LP3971_LDO2 -> 4
+	LP3971_LDO3 -> 0, LP3971_LDO4 -> 4
+	LP3971_LDO5 -> 0
+*/
+#define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
+#define LDO_VOL_CONTR_MASK 0x0f
+
+static const int ldo45_voltage_map[] = {
+	1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
+	1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
+};
+
+static const int ldo123_voltage_map[] = {
+	1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
+	2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
+};
+
+static const int *ldo_voltage_map[] = {
+	ldo123_voltage_map, /* LDO1 */
+	ldo123_voltage_map, /* LDO2 */
+	ldo123_voltage_map, /* LDO3 */
+	ldo45_voltage_map, /* LDO4 */
+	ldo45_voltage_map, /* LDO5 */
+};
+
+#define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)])
+
+#define LDO_VOL_MIN_IDX 0x00
+#define LDO_VOL_MAX_IDX 0x0f
+
+static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
+{
+	int ldo = rdev_get_id(dev) - LP3971_LDO1;
+	return 1000 * LDO_VOL_VALUE_MAP(ldo)[index];
+}
+
+static int lp3971_ldo_is_enabled(struct regulator_dev *dev)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3971_LDO1;
+	u16 mask = 1 << (1 + ldo);
+	u16 val;
+
+	val = lp3971_reg_read(lp3971, LP3971_LDO_ENABLE_REG);
+	return (val & mask) != 0;
+}
+
+static int lp3971_ldo_enable(struct regulator_dev *dev)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3971_LDO1;
+	u16 mask = 1 << (1 + ldo);
+
+	return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, mask);
+}
+
+static int lp3971_ldo_disable(struct regulator_dev *dev)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3971_LDO1;
+	u16 mask = 1 << (1 + ldo);
+
+	return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0);
+}
+
+static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3971_LDO1;
+	u16 val, reg;
+
+	reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
+	val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
+
+	return 1000 * LDO_VOL_VALUE_MAP(ldo)[val];
+}
+
+static int lp3971_ldo_set_voltage(struct regulator_dev *dev,
+				  int min_uV, int max_uV,
+				  unsigned int *selector)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3971_LDO1;
+	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+	const int *vol_map = LDO_VOL_VALUE_MAP(ldo);
+	u16 val;
+
+	if (min_vol < vol_map[LDO_VOL_MIN_IDX] ||
+	    min_vol > vol_map[LDO_VOL_MAX_IDX])
+		return -EINVAL;
+
+	for (val = LDO_VOL_MIN_IDX; val <= LDO_VOL_MAX_IDX; val++)
+		if (vol_map[val] >= min_vol)
+			break;
+
+	if (val > LDO_VOL_MAX_IDX || vol_map[val] > max_vol)
+		return -EINVAL;
+
+	*selector = val;
+
+	return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo),
+			LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo),
+			val << LDO_VOL_CONTR_SHIFT(ldo));
+}
+
+static struct regulator_ops lp3971_ldo_ops = {
+	.list_voltage = lp3971_ldo_list_voltage,
+	.is_enabled = lp3971_ldo_is_enabled,
+	.enable = lp3971_ldo_enable,
+	.disable = lp3971_ldo_disable,
+	.get_voltage = lp3971_ldo_get_voltage,
+	.set_voltage = lp3971_ldo_set_voltage,
+};
+
+static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
+{
+	return 1000 * buck_voltage_map[index];
+}
+
+static int lp3971_dcdc_is_enabled(struct regulator_dev *dev)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3971_DCDC1;
+	u16 mask = 1 << (buck * 2);
+	u16 val;
+
+	val = lp3971_reg_read(lp3971, LP3971_BUCK_VOL_ENABLE_REG);
+	return (val & mask) != 0;
+}
+
+static int lp3971_dcdc_enable(struct regulator_dev *dev)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3971_DCDC1;
+	u16 mask = 1 << (buck * 2);
+
+	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, mask);
+}
+
+static int lp3971_dcdc_disable(struct regulator_dev *dev)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3971_DCDC1;
+	u16 mask = 1 << (buck * 2);
+
+	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0);
+}
+
+static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3971_DCDC1;
+	u16 reg;
+	int val;
+
+	reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck));
+	reg &= BUCK_TARGET_VOL_MASK;
+
+	if (reg <= BUCK_TARGET_VOL_MAX_IDX)
+		val = 1000 * buck_voltage_map[reg];
+	else {
+		val = 0;
+		dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
+	}
+
+	return val;
+}
+
+static int lp3971_dcdc_set_voltage(struct regulator_dev *dev,
+				   int min_uV, int max_uV,
+				   unsigned int *selector)
+{
+	struct lp3971 *lp3971 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3971_DCDC1;
+	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+	const int *vol_map = buck_voltage_map;
+	u16 val;
+	int ret;
+
+	if (min_vol < vol_map[BUCK_TARGET_VOL_MIN_IDX] ||
+	    min_vol > vol_map[BUCK_TARGET_VOL_MAX_IDX])
+		return -EINVAL;
+
+	for (val = BUCK_TARGET_VOL_MIN_IDX; val <= BUCK_TARGET_VOL_MAX_IDX;
+	     val++)
+		if (vol_map[val] >= min_vol)
+			break;
+
+	if (val > BUCK_TARGET_VOL_MAX_IDX || vol_map[val] > max_vol)
+		return -EINVAL;
+
+	*selector = val;
+
+	ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck),
+	       BUCK_TARGET_VOL_MASK, val);
+	if (ret)
+		return ret;
+
+	ret = lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
+	       BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
+	       BUCK_VOL_CHANGE_FLAG_GO << BUCK_VOL_CHANGE_SHIFT(buck));
+	if (ret)
+		return ret;
+
+	return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_CHANGE_REG,
+	       BUCK_VOL_CHANGE_FLAG_MASK << BUCK_VOL_CHANGE_SHIFT(buck),
+	       0 << BUCK_VOL_CHANGE_SHIFT(buck));
+}
+
+static struct regulator_ops lp3971_dcdc_ops = {
+	.list_voltage = lp3971_dcdc_list_voltage,
+	.is_enabled = lp3971_dcdc_is_enabled,
+	.enable = lp3971_dcdc_enable,
+	.disable = lp3971_dcdc_disable,
+	.get_voltage = lp3971_dcdc_get_voltage,
+	.set_voltage = lp3971_dcdc_set_voltage,
+};
+
+static struct regulator_desc regulators[] = {
+	{
+		.name = "LDO1",
+		.id = LP3971_LDO1,
+		.ops = &lp3971_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO2",
+		.id = LP3971_LDO2,
+		.ops = &lp3971_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO3",
+		.id = LP3971_LDO3,
+		.ops = &lp3971_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO4",
+		.id = LP3971_LDO4,
+		.ops = &lp3971_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO5",
+		.id = LP3971_LDO5,
+		.ops = &lp3971_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo45_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC1",
+		.id = LP3971_DCDC1,
+		.ops = &lp3971_dcdc_ops,
+		.n_voltages = ARRAY_SIZE(buck_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC2",
+		.id = LP3971_DCDC2,
+		.ops = &lp3971_dcdc_ops,
+		.n_voltages = ARRAY_SIZE(buck_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC3",
+		.id = LP3971_DCDC3,
+		.ops = &lp3971_dcdc_ops,
+		.n_voltages = ARRAY_SIZE(buck_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,
+	u16 *dest)
+{
+	int ret;
+
+	if (count != 1)
+		return -EIO;
+	ret = i2c_smbus_read_byte_data(i2c, reg);
+	if (ret < 0)
+		return -EIO;
+
+	*dest = ret;
+	return 0;
+}
+
+static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count,
+	const u16 *src)
+{
+	if (count != 1)
+		return -EIO;
+	return i2c_smbus_write_byte_data(i2c, reg, *src);
+}
+
+static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg)
+{
+	u16 val = 0;
+
+	mutex_lock(&lp3971->io_lock);
+
+	lp3971_i2c_read(lp3971->i2c, reg, 1, &val);
+
+	dev_dbg(lp3971->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg,
+		(unsigned)val&0xff);
+
+	mutex_unlock(&lp3971->io_lock);
+
+	return val & 0xff;
+}
+
+static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val)
+{
+	u16 tmp;
+	int ret;
+
+	mutex_lock(&lp3971->io_lock);
+
+	ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp);
+	tmp = (tmp & ~mask) | val;
+	if (ret == 0) {
+		ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp);
+		dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
+			(unsigned)val&0xff);
+	}
+	mutex_unlock(&lp3971->io_lock);
+
+	return ret;
+}
+
+static int __devinit setup_regulators(struct lp3971 *lp3971,
+				      struct lp3971_platform_data *pdata)
+{
+	int i, err;
+
+	lp3971->num_regulators = pdata->num_regulators;
+	lp3971->rdev = kcalloc(pdata->num_regulators,
+				sizeof(struct regulator_dev *), GFP_KERNEL);
+	if (!lp3971->rdev) {
+		err = -ENOMEM;
+		goto err_nomem;
+	}
+
+	/* Instantiate the regulators */
+	for (i = 0; i < pdata->num_regulators; i++) {
+		struct lp3971_regulator_subdev *reg = &pdata->regulators[i];
+		lp3971->rdev[i] = regulator_register(&regulators[reg->id],
+				lp3971->dev, reg->initdata, lp3971, NULL);
+
+		if (IS_ERR(lp3971->rdev[i])) {
+			err = PTR_ERR(lp3971->rdev[i]);
+			dev_err(lp3971->dev, "regulator init failed: %d\n",
+				err);
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	while (--i >= 0)
+		regulator_unregister(lp3971->rdev[i]);
+	kfree(lp3971->rdev);
+	lp3971->rdev = NULL;
+err_nomem:
+	return err;
+}
+
+static int __devinit lp3971_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct lp3971 *lp3971;
+	struct lp3971_platform_data *pdata = i2c->dev.platform_data;
+	int ret;
+	u16 val;
+
+	if (!pdata) {
+		dev_dbg(&i2c->dev, "No platform init data supplied\n");
+		return -ENODEV;
+	}
+
+	lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL);
+	if (lp3971 == NULL)
+		return -ENOMEM;
+
+	lp3971->i2c = i2c;
+	lp3971->dev = &i2c->dev;
+
+	mutex_init(&lp3971->io_lock);
+
+	/* Detect LP3971 */
+	ret = lp3971_i2c_read(i2c, LP3971_SYS_CONTROL1_REG, 1, &val);
+	if (ret == 0 && (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL)
+		ret = -ENODEV;
+	if (ret < 0) {
+		dev_err(&i2c->dev, "failed to detect device\n");
+		goto err_detect;
+	}
+
+	ret = setup_regulators(lp3971, pdata);
+	if (ret < 0)
+		goto err_detect;
+
+	i2c_set_clientdata(i2c, lp3971);
+	return 0;
+
+err_detect:
+	kfree(lp3971);
+	return ret;
+}
+
+static int __devexit lp3971_i2c_remove(struct i2c_client *i2c)
+{
+	struct lp3971 *lp3971 = i2c_get_clientdata(i2c);
+	int i;
+
+	for (i = 0; i < lp3971->num_regulators; i++)
+		regulator_unregister(lp3971->rdev[i]);
+
+	kfree(lp3971->rdev);
+	kfree(lp3971);
+
+	return 0;
+}
+
+static const struct i2c_device_id lp3971_i2c_id[] = {
+       { "lp3971", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id);
+
+static struct i2c_driver lp3971_i2c_driver = {
+	.driver = {
+		.name = "LP3971",
+		.owner = THIS_MODULE,
+	},
+	.probe    = lp3971_i2c_probe,
+	.remove   = __devexit_p(lp3971_i2c_remove),
+	.id_table = lp3971_i2c_id,
+};
+
+static int __init lp3971_module_init(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&lp3971_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register I2C driver: %d\n", ret);
+
+	return ret;
+}
+module_init(lp3971_module_init);
+
+static void __exit lp3971_module_exit(void)
+{
+	i2c_del_driver(&lp3971_i2c_driver);
+}
+module_exit(lp3971_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marek Szyprowski <m.szyprowski@samsung.com>");
+MODULE_DESCRIPTION("LP3971 PMIC driver");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/lp3972.c b/ap/os/linux/linux-3.4.x/drivers/regulator/lp3972.c
new file mode 100644
index 0000000..49a15ee
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/lp3972.c
@@ -0,0 +1,667 @@
+/*
+ * Regulator driver for National Semiconductors LP3972 PMIC chip
+ *
+ * Based on lp3971.c
+ *
+ * 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/bug.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/lp3972.h>
+#include <linux/slab.h>
+
+struct lp3972 {
+	struct device *dev;
+	struct mutex io_lock;
+	struct i2c_client *i2c;
+	int num_regulators;
+	struct regulator_dev **rdev;
+};
+
+/* LP3972 Control Registers */
+#define LP3972_SCR_REG		0x07
+#define LP3972_OVER1_REG	0x10
+#define LP3972_OVSR1_REG	0x11
+#define LP3972_OVER2_REG	0x12
+#define LP3972_OVSR2_REG	0x13
+#define LP3972_VCC1_REG		0x20
+#define LP3972_ADTV1_REG	0x23
+#define LP3972_ADTV2_REG	0x24
+#define LP3972_AVRC_REG		0x25
+#define LP3972_CDTC1_REG	0x26
+#define LP3972_CDTC2_REG	0x27
+#define LP3972_SDTV1_REG	0x29
+#define LP3972_SDTV2_REG	0x2A
+#define LP3972_MDTV1_REG	0x32
+#define LP3972_MDTV2_REG	0x33
+#define LP3972_L2VCR_REG	0x39
+#define LP3972_L34VCR_REG	0x3A
+#define LP3972_SCR1_REG		0x80
+#define LP3972_SCR2_REG		0x81
+#define LP3972_OEN3_REG		0x82
+#define LP3972_OSR3_REG		0x83
+#define LP3972_LOER4_REG	0x84
+#define LP3972_B2TV_REG		0x85
+#define LP3972_B3TV_REG		0x86
+#define LP3972_B32RC_REG	0x87
+#define LP3972_ISRA_REG		0x88
+#define LP3972_BCCR_REG		0x89
+#define LP3972_II1RR_REG	0x8E
+#define LP3972_II2RR_REG	0x8F
+
+#define LP3972_SYS_CONTROL1_REG		LP3972_SCR1_REG
+/* System control register 1 initial value,
+ * bits 5, 6 and 7 are EPROM programmable */
+#define SYS_CONTROL1_INIT_VAL		0x02
+#define SYS_CONTROL1_INIT_MASK		0x1F
+
+#define LP3972_VOL_CHANGE_REG		LP3972_VCC1_REG
+#define LP3972_VOL_CHANGE_FLAG_GO	0x01
+#define LP3972_VOL_CHANGE_FLAG_MASK	0x03
+
+/* LDO output enable mask */
+#define LP3972_OEN3_L1EN	BIT(0)
+#define LP3972_OVER2_LDO2_EN	BIT(2)
+#define LP3972_OVER2_LDO3_EN	BIT(3)
+#define LP3972_OVER2_LDO4_EN	BIT(4)
+#define LP3972_OVER1_S_EN	BIT(2)
+
+static const int ldo1_voltage_map[] = {
+	1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
+	1900, 1925, 1950, 1975, 2000,
+};
+
+static const int ldo23_voltage_map[] = {
+	1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
+	2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
+};
+
+static const int ldo4_voltage_map[] = {
+	1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
+	1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
+};
+
+static const int ldo5_voltage_map[] = {
+	   0,    0,    0,    0,    0,  850,  875,  900,
+	 925,  950,  975, 1000, 1025, 1050, 1075, 1100,
+	1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
+	1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+};
+
+static const int buck1_voltage_map[] = {
+	 725,  750,  775,  800,  825,  850,  875,  900,
+	 925,  950,  975, 1000, 1025, 1050, 1075, 1100,
+	1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
+	1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+};
+
+static const int buck23_voltage_map[] = {
+	   0,  800,  850,  900,  950, 1000, 1050, 1100,
+	1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
+	1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
+	3000, 3300,
+};
+
+static const int *ldo_voltage_map[] = {
+	ldo1_voltage_map,
+	ldo23_voltage_map,
+	ldo23_voltage_map,
+	ldo4_voltage_map,
+	ldo5_voltage_map,
+};
+
+static const int *buck_voltage_map[] = {
+	buck1_voltage_map,
+	buck23_voltage_map,
+	buck23_voltage_map,
+};
+
+static const int ldo_output_enable_mask[] = {
+	LP3972_OEN3_L1EN,
+	LP3972_OVER2_LDO2_EN,
+	LP3972_OVER2_LDO3_EN,
+	LP3972_OVER2_LDO4_EN,
+	LP3972_OVER1_S_EN,
+};
+
+static const int ldo_output_enable_addr[] = {
+	LP3972_OEN3_REG,
+	LP3972_OVER2_REG,
+	LP3972_OVER2_REG,
+	LP3972_OVER2_REG,
+	LP3972_OVER1_REG,
+};
+
+static const int ldo_vol_ctl_addr[] = {
+	LP3972_MDTV1_REG,
+	LP3972_L2VCR_REG,
+	LP3972_L34VCR_REG,
+	LP3972_L34VCR_REG,
+	LP3972_SDTV1_REG,
+};
+
+static const int buck_vol_enable_addr[] = {
+	LP3972_OVER1_REG,
+	LP3972_OEN3_REG,
+	LP3972_OEN3_REG,
+};
+
+static const int buck_base_addr[] = {
+	LP3972_ADTV1_REG,
+	LP3972_B2TV_REG,
+	LP3972_B3TV_REG,
+};
+
+#define LP3972_LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[x])
+#define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x])
+#define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x])
+
+/*	LDO voltage control registers shift:
+	LP3972_LDO1 -> 0, LP3972_LDO2 -> 4
+	LP3972_LDO3 -> 0, LP3972_LDO4 -> 4
+	LP3972_LDO5 -> 0
+*/
+#define LP3972_LDO_VOL_CONTR_SHIFT(x) (((x) & 1) << 2)
+#define LP3972_LDO_VOL_CONTR_REG(x) (ldo_vol_ctl_addr[x])
+#define LP3972_LDO_VOL_CHANGE_SHIFT(x) ((x) ? 4 : 6)
+
+#define LP3972_LDO_VOL_MASK(x) (((x) % 4) ? 0x0f : 0x1f)
+#define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00)
+#define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c)
+
+#define LP3972_BUCK_VOL_VALUE_MAP(x) (buck_voltage_map[x])
+#define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
+#define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
+#define LP3972_BUCK_VOL_MASK 0x1f
+#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00)
+#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f)
+
+static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count,
+	u16 *dest)
+{
+	int ret;
+
+	if (count != 1)
+		return -EIO;
+	ret = i2c_smbus_read_byte_data(i2c, reg);
+	if (ret < 0)
+		return ret;
+
+	*dest = ret;
+	return 0;
+}
+
+static int lp3972_i2c_write(struct i2c_client *i2c, char reg, int count,
+	const u16 *src)
+{
+	if (count != 1)
+		return -EIO;
+	return i2c_smbus_write_byte_data(i2c, reg, *src);
+}
+
+static u8 lp3972_reg_read(struct lp3972 *lp3972, u8 reg)
+{
+	u16 val = 0;
+
+	mutex_lock(&lp3972->io_lock);
+
+	lp3972_i2c_read(lp3972->i2c, reg, 1, &val);
+
+	dev_dbg(lp3972->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg,
+		(unsigned)val & 0xff);
+
+	mutex_unlock(&lp3972->io_lock);
+
+	return val & 0xff;
+}
+
+static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val)
+{
+	u16 tmp;
+	int ret;
+
+	mutex_lock(&lp3972->io_lock);
+
+	ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp);
+	tmp = (tmp & ~mask) | val;
+	if (ret == 0) {
+		ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp);
+		dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
+			(unsigned)val & 0xff);
+	}
+	mutex_unlock(&lp3972->io_lock);
+
+	return ret;
+}
+
+static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
+{
+	int ldo = rdev_get_id(dev) - LP3972_LDO1;
+	return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index];
+}
+
+static int lp3972_ldo_is_enabled(struct regulator_dev *dev)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3972_LDO1;
+	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
+	u16 val;
+
+	val = lp3972_reg_read(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo));
+	return !!(val & mask);
+}
+
+static int lp3972_ldo_enable(struct regulator_dev *dev)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3972_LDO1;
+	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
+
+	return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo),
+				mask, mask);
+}
+
+static int lp3972_ldo_disable(struct regulator_dev *dev)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3972_LDO1;
+	u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo);
+
+	return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo),
+				mask, 0);
+}
+
+static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3972_LDO1;
+	u16 mask = LP3972_LDO_VOL_MASK(ldo);
+	u16 val, reg;
+
+	reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
+	val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
+
+	return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val];
+}
+
+static int lp3972_ldo_set_voltage(struct regulator_dev *dev,
+				  int min_uV, int max_uV,
+				  unsigned int *selector)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev) - LP3972_LDO1;
+	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+	const int *vol_map = LP3972_LDO_VOL_VALUE_MAP(ldo);
+	u16 val;
+	int shift, ret;
+
+	if (min_vol < vol_map[LP3972_LDO_VOL_MIN_IDX(ldo)] ||
+	    min_vol > vol_map[LP3972_LDO_VOL_MAX_IDX(ldo)])
+		return -EINVAL;
+
+	for (val = LP3972_LDO_VOL_MIN_IDX(ldo);
+		val <= LP3972_LDO_VOL_MAX_IDX(ldo); val++)
+		if (vol_map[val] >= min_vol)
+			break;
+
+	if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol)
+		return -EINVAL;
+
+	*selector = val;
+
+	shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo);
+	ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo),
+		LP3972_LDO_VOL_MASK(ldo) << shift, val << shift);
+
+	if (ret)
+		return ret;
+
+	/*
+	 * LDO1 and LDO5 support voltage control by either target voltage1
+	 * or target voltage2 register.
+	 * We use target voltage1 register for LDO1 and LDO5 in this driver.
+	 * We need to update voltage change control register(0x20) to enable
+	 * LDO1 and LDO5 to change to their programmed target values.
+	 */
+	switch (ldo) {
+	case LP3972_LDO1:
+	case LP3972_LDO5:
+		shift = LP3972_LDO_VOL_CHANGE_SHIFT(ldo);
+		ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
+			LP3972_VOL_CHANGE_FLAG_MASK << shift,
+			LP3972_VOL_CHANGE_FLAG_GO << shift);
+		if (ret)
+			return ret;
+
+		ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
+			LP3972_VOL_CHANGE_FLAG_MASK << shift, 0);
+		break;
+	}
+
+	return ret;
+}
+
+static struct regulator_ops lp3972_ldo_ops = {
+	.list_voltage = lp3972_ldo_list_voltage,
+	.is_enabled = lp3972_ldo_is_enabled,
+	.enable = lp3972_ldo_enable,
+	.disable = lp3972_ldo_disable,
+	.get_voltage = lp3972_ldo_get_voltage,
+	.set_voltage = lp3972_ldo_set_voltage,
+};
+
+static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
+{
+	int buck = rdev_get_id(dev) - LP3972_DCDC1;
+	return 1000 * buck_voltage_map[buck][index];
+}
+
+static int lp3972_dcdc_is_enabled(struct regulator_dev *dev)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3972_DCDC1;
+	u16 mask = 1 << (buck * 2);
+	u16 val;
+
+	val = lp3972_reg_read(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck));
+	return !!(val & mask);
+}
+
+static int lp3972_dcdc_enable(struct regulator_dev *dev)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3972_DCDC1;
+	u16 mask = 1 << (buck * 2);
+	u16 val;
+
+	val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck),
+				mask, mask);
+	return val;
+}
+
+static int lp3972_dcdc_disable(struct regulator_dev *dev)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3972_DCDC1;
+	u16 mask = 1 << (buck * 2);
+	u16 val;
+
+	val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck),
+				mask, 0);
+	return val;
+}
+
+static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3972_DCDC1;
+	u16 reg;
+	int val;
+
+	reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
+	reg &= LP3972_BUCK_VOL_MASK;
+	if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck))
+		val = 1000 * buck_voltage_map[buck][reg];
+	else {
+		val = 0;
+		dev_warn(&dev->dev, "chip reported incorrect voltage value."
+				    " reg = %d\n", reg);
+	}
+
+	return val;
+}
+
+static int lp3972_dcdc_set_voltage(struct regulator_dev *dev,
+				   int min_uV, int max_uV,
+				   unsigned int *selector)
+{
+	struct lp3972 *lp3972 = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - LP3972_DCDC1;
+	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+	const int *vol_map = buck_voltage_map[buck];
+	u16 val;
+	int ret;
+
+	if (min_vol < vol_map[LP3972_BUCK_VOL_MIN_IDX(buck)] ||
+	    min_vol > vol_map[LP3972_BUCK_VOL_MAX_IDX(buck)])
+		return -EINVAL;
+
+	for (val = LP3972_BUCK_VOL_MIN_IDX(buck);
+		val <= LP3972_BUCK_VOL_MAX_IDX(buck); val++)
+		if (vol_map[val] >= min_vol)
+			break;
+
+	if (val > LP3972_BUCK_VOL_MAX_IDX(buck) ||
+	    vol_map[val] > max_vol)
+		return -EINVAL;
+
+	*selector = val;
+
+	ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck),
+				LP3972_BUCK_VOL_MASK, val);
+	if (ret)
+		return ret;
+
+	if (buck != 0)
+		return ret;
+
+	ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
+		LP3972_VOL_CHANGE_FLAG_MASK, LP3972_VOL_CHANGE_FLAG_GO);
+	if (ret)
+		return ret;
+
+	return lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG,
+				LP3972_VOL_CHANGE_FLAG_MASK, 0);
+}
+
+static struct regulator_ops lp3972_dcdc_ops = {
+	.list_voltage = lp3972_dcdc_list_voltage,
+	.is_enabled = lp3972_dcdc_is_enabled,
+	.enable = lp3972_dcdc_enable,
+	.disable = lp3972_dcdc_disable,
+	.get_voltage = lp3972_dcdc_get_voltage,
+	.set_voltage = lp3972_dcdc_set_voltage,
+};
+
+static struct regulator_desc regulators[] = {
+	{
+		.name = "LDO1",
+		.id = LP3972_LDO1,
+		.ops = &lp3972_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo1_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO2",
+		.id = LP3972_LDO2,
+		.ops = &lp3972_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO3",
+		.id = LP3972_LDO3,
+		.ops = &lp3972_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo23_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO4",
+		.id = LP3972_LDO4,
+		.ops = &lp3972_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo4_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO5",
+		.id = LP3972_LDO5,
+		.ops = &lp3972_ldo_ops,
+		.n_voltages = ARRAY_SIZE(ldo5_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC1",
+		.id = LP3972_DCDC1,
+		.ops = &lp3972_dcdc_ops,
+		.n_voltages = ARRAY_SIZE(buck1_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC2",
+		.id = LP3972_DCDC2,
+		.ops = &lp3972_dcdc_ops,
+		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC3",
+		.id = LP3972_DCDC3,
+		.ops = &lp3972_dcdc_ops,
+		.n_voltages = ARRAY_SIZE(buck23_voltage_map),
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __devinit setup_regulators(struct lp3972 *lp3972,
+	struct lp3972_platform_data *pdata)
+{
+	int i, err;
+
+	lp3972->num_regulators = pdata->num_regulators;
+	lp3972->rdev = kcalloc(pdata->num_regulators,
+				sizeof(struct regulator_dev *), GFP_KERNEL);
+	if (!lp3972->rdev) {
+		err = -ENOMEM;
+		goto err_nomem;
+	}
+
+	/* Instantiate the regulators */
+	for (i = 0; i < pdata->num_regulators; i++) {
+		struct lp3972_regulator_subdev *reg = &pdata->regulators[i];
+		lp3972->rdev[i] = regulator_register(&regulators[reg->id],
+				lp3972->dev, reg->initdata, lp3972, NULL);
+
+		if (IS_ERR(lp3972->rdev[i])) {
+			err = PTR_ERR(lp3972->rdev[i]);
+			dev_err(lp3972->dev, "regulator init failed: %d\n",
+				err);
+			goto error;
+		}
+	}
+
+	return 0;
+error:
+	while (--i >= 0)
+		regulator_unregister(lp3972->rdev[i]);
+	kfree(lp3972->rdev);
+	lp3972->rdev = NULL;
+err_nomem:
+	return err;
+}
+
+static int __devinit lp3972_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct lp3972 *lp3972;
+	struct lp3972_platform_data *pdata = i2c->dev.platform_data;
+	int ret;
+	u16 val;
+
+	if (!pdata) {
+		dev_dbg(&i2c->dev, "No platform init data supplied\n");
+		return -ENODEV;
+	}
+
+	lp3972 = kzalloc(sizeof(struct lp3972), GFP_KERNEL);
+	if (!lp3972)
+		return -ENOMEM;
+
+	lp3972->i2c = i2c;
+	lp3972->dev = &i2c->dev;
+
+	mutex_init(&lp3972->io_lock);
+
+	/* Detect LP3972 */
+	ret = lp3972_i2c_read(i2c, LP3972_SYS_CONTROL1_REG, 1, &val);
+	if (ret == 0 &&
+		(val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) {
+		ret = -ENODEV;
+		dev_err(&i2c->dev, "chip reported: val = 0x%x\n", val);
+	}
+	if (ret < 0) {
+		dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret);
+		goto err_detect;
+	}
+
+	ret = setup_regulators(lp3972, pdata);
+	if (ret < 0)
+		goto err_detect;
+
+	i2c_set_clientdata(i2c, lp3972);
+	return 0;
+
+err_detect:
+	kfree(lp3972);
+	return ret;
+}
+
+static int __devexit lp3972_i2c_remove(struct i2c_client *i2c)
+{
+	struct lp3972 *lp3972 = i2c_get_clientdata(i2c);
+	int i;
+
+	for (i = 0; i < lp3972->num_regulators; i++)
+		regulator_unregister(lp3972->rdev[i]);
+	kfree(lp3972->rdev);
+	kfree(lp3972);
+
+	return 0;
+}
+
+static const struct i2c_device_id lp3972_i2c_id[] = {
+	{ "lp3972", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id);
+
+static struct i2c_driver lp3972_i2c_driver = {
+	.driver = {
+		.name = "lp3972",
+		.owner = THIS_MODULE,
+	},
+	.probe    = lp3972_i2c_probe,
+	.remove   = __devexit_p(lp3972_i2c_remove),
+	.id_table = lp3972_i2c_id,
+};
+
+static int __init lp3972_module_init(void)
+{
+	return i2c_add_driver(&lp3972_i2c_driver);
+}
+subsys_initcall(lp3972_module_init);
+
+static void __exit lp3972_module_exit(void)
+{
+	i2c_del_driver(&lp3972_i2c_driver);
+}
+module_exit(lp3972_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Axel Lin <axel.lin@gmail.com>");
+MODULE_DESCRIPTION("LP3972 PMIC driver");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/max1586.c b/ap/os/linux/linux-3.4.x/drivers/regulator/max1586.c
new file mode 100644
index 0000000..282d2ee
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/max1586.c
@@ -0,0 +1,283 @@
+/*
+ * max1586.c  --  Voltage and current regulation for the Maxim 1586
+ *
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/slab.h>
+#include <linux/regulator/max1586.h>
+
+#define MAX1586_V3_MAX_VSEL 31
+#define MAX1586_V6_MAX_VSEL 3
+
+#define MAX1586_V3_MIN_UV   700000
+#define MAX1586_V3_MAX_UV  1475000
+
+#define MAX1586_V6_MIN_UV        0
+#define MAX1586_V6_MAX_UV  3000000
+
+#define I2C_V3_SELECT (0 << 5)
+#define I2C_V6_SELECT (1 << 5)
+
+struct max1586_data {
+	struct i2c_client *client;
+
+	/* min/max V3 voltage */
+	unsigned int min_uV;
+	unsigned int max_uV;
+
+	struct regulator_dev *rdev[0];
+};
+
+/*
+ * V3 voltage
+ * On I2C bus, sending a "x" byte to the max1586 means :
+ *   set V3 to 0.700V + (x & 0x1f) * 0.025V
+ * This voltage can be increased by external resistors
+ * R24 and R25=100kOhm as described in the data sheet.
+ * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm
+ */
+static int max1586_v3_calc_voltage(struct max1586_data *max1586,
+	unsigned selector)
+{
+	unsigned range_uV = max1586->max_uV - max1586->min_uV;
+
+	return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL);
+}
+
+static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV,
+			  unsigned *selector)
+{
+	struct max1586_data *max1586 = rdev_get_drvdata(rdev);
+	struct i2c_client *client = max1586->client;
+	unsigned range_uV = max1586->max_uV - max1586->min_uV;
+	u8 v3_prog;
+
+	if (min_uV > max1586->max_uV || max_uV < max1586->min_uV)
+		return -EINVAL;
+	if (min_uV < max1586->min_uV)
+		min_uV = max1586->min_uV;
+
+	*selector = DIV_ROUND_UP((min_uV - max1586->min_uV) *
+				 MAX1586_V3_MAX_VSEL, range_uV);
+	if (max1586_v3_calc_voltage(max1586, *selector) > max_uV)
+		return -EINVAL;
+
+	dev_dbg(&client->dev, "changing voltage v3 to %dmv\n",
+		max1586_v3_calc_voltage(max1586, *selector) / 1000);
+
+	v3_prog = I2C_V3_SELECT | (u8) *selector;
+	return i2c_smbus_write_byte(client, v3_prog);
+}
+
+static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector)
+{
+	struct max1586_data *max1586 = rdev_get_drvdata(rdev);
+
+	if (selector > MAX1586_V3_MAX_VSEL)
+		return -EINVAL;
+	return max1586_v3_calc_voltage(max1586, selector);
+}
+
+/*
+ * V6 voltage
+ * On I2C bus, sending a "x" byte to the max1586 means :
+ *   set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3)
+ * As regulator framework doesn't accept voltages to be 0V, we use 1uV.
+ */
+static int max1586_v6_calc_voltage(unsigned selector)
+{
+	static int voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
+
+	return voltages_uv[selector];
+}
+
+static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV,
+			  unsigned int *selector)
+{
+	struct i2c_client *client = rdev_get_drvdata(rdev);
+	u8 v6_prog;
+
+	if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV)
+		return -EINVAL;
+	if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV)
+		return -EINVAL;
+
+	if (min_uV < 1800000)
+		*selector = 0;
+	else if (min_uV < 2500000)
+		*selector = 1;
+	else if (min_uV < 3000000)
+		*selector = 2;
+	else if (min_uV >= 3000000)
+		*selector = 3;
+
+	if (max1586_v6_calc_voltage(*selector) > max_uV)
+		return -EINVAL;
+
+	dev_dbg(&client->dev, "changing voltage v6 to %dmv\n",
+		max1586_v6_calc_voltage(*selector) / 1000);
+
+	v6_prog = I2C_V6_SELECT | (u8) *selector;
+	return i2c_smbus_write_byte(client, v6_prog);
+}
+
+static int max1586_v6_list(struct regulator_dev *rdev, unsigned selector)
+{
+	if (selector > MAX1586_V6_MAX_VSEL)
+		return -EINVAL;
+	return max1586_v6_calc_voltage(selector);
+}
+
+/*
+ * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back
+ * the set up value.
+ */
+static struct regulator_ops max1586_v3_ops = {
+	.set_voltage = max1586_v3_set,
+	.list_voltage = max1586_v3_list,
+};
+
+static struct regulator_ops max1586_v6_ops = {
+	.set_voltage = max1586_v6_set,
+	.list_voltage = max1586_v6_list,
+};
+
+static struct regulator_desc max1586_reg[] = {
+	{
+		.name = "Output_V3",
+		.id = MAX1586_V3,
+		.ops = &max1586_v3_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = MAX1586_V3_MAX_VSEL + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "Output_V6",
+		.id = MAX1586_V6,
+		.ops = &max1586_v6_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = MAX1586_V6_MAX_VSEL + 1,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __devinit max1586_pmic_probe(struct i2c_client *client,
+					const struct i2c_device_id *i2c_id)
+{
+	struct regulator_dev **rdev;
+	struct max1586_platform_data *pdata = client->dev.platform_data;
+	struct max1586_data *max1586;
+	int i, id, ret = -ENOMEM;
+
+	max1586 = kzalloc(sizeof(struct max1586_data) +
+			sizeof(struct regulator_dev *) * (MAX1586_V6 + 1),
+			GFP_KERNEL);
+	if (!max1586)
+		goto out;
+
+	max1586->client = client;
+
+	if (!pdata->v3_gain) {
+		ret = -EINVAL;
+		goto out_unmap;
+	}
+	max1586->min_uV = MAX1586_V3_MIN_UV / 1000 * pdata->v3_gain / 1000;
+	max1586->max_uV = MAX1586_V3_MAX_UV / 1000 * pdata->v3_gain / 1000;
+
+	rdev = max1586->rdev;
+	for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) {
+		id = pdata->subdevs[i].id;
+		if (!pdata->subdevs[i].platform_data)
+			continue;
+		if (id < MAX1586_V3 || id > MAX1586_V6) {
+			dev_err(&client->dev, "invalid regulator id %d\n", id);
+			goto err;
+		}
+		rdev[i] = regulator_register(&max1586_reg[id], &client->dev,
+					     pdata->subdevs[i].platform_data,
+					     max1586, NULL);
+		if (IS_ERR(rdev[i])) {
+			ret = PTR_ERR(rdev[i]);
+			dev_err(&client->dev, "failed to register %s\n",
+				max1586_reg[id].name);
+			goto err;
+		}
+	}
+
+	i2c_set_clientdata(client, max1586);
+	dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n");
+	return 0;
+
+err:
+	while (--i >= 0)
+		regulator_unregister(rdev[i]);
+out_unmap:
+	kfree(max1586);
+out:
+	return ret;
+}
+
+static int __devexit max1586_pmic_remove(struct i2c_client *client)
+{
+	struct max1586_data *max1586 = i2c_get_clientdata(client);
+	int i;
+
+	for (i = 0; i <= MAX1586_V6; i++)
+		if (max1586->rdev[i])
+			regulator_unregister(max1586->rdev[i]);
+	kfree(max1586);
+
+	return 0;
+}
+
+static const struct i2c_device_id max1586_id[] = {
+	{ "max1586", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max1586_id);
+
+static struct i2c_driver max1586_pmic_driver = {
+	.probe = max1586_pmic_probe,
+	.remove = __devexit_p(max1586_pmic_remove),
+	.driver		= {
+		.name	= "max1586",
+		.owner	= THIS_MODULE,
+	},
+	.id_table	= max1586_id,
+};
+
+static int __init max1586_pmic_init(void)
+{
+	return i2c_add_driver(&max1586_pmic_driver);
+}
+subsys_initcall(max1586_pmic_init);
+
+static void __exit max1586_pmic_exit(void)
+{
+	i2c_del_driver(&max1586_pmic_driver);
+}
+module_exit(max1586_pmic_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MAXIM 1586 voltage regulator driver");
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/max8649.c b/ap/os/linux/linux-3.4.x/drivers/regulator/max8649.c
new file mode 100644
index 0000000..824c650
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/max8649.c
@@ -0,0 +1,363 @@
+/*
+ * Regulators driver for Maxim max8649
+ *
+ * Copyright (C) 2009-2010 Marvell International Ltd.
+ *      Haojian Zhuang <haojian.zhuang@marvell.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/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/slab.h>
+#include <linux/regulator/max8649.h>
+#include <linux/regmap.h>
+
+#define MAX8649_DCDC_VMIN	750000		/* uV */
+#define MAX8649_DCDC_VMAX	1380000		/* uV */
+#define MAX8649_DCDC_STEP	10000		/* uV */
+#define MAX8649_VOL_MASK	0x3f
+
+/* Registers */
+#define MAX8649_MODE0		0x00
+#define MAX8649_MODE1		0x01
+#define MAX8649_MODE2		0x02
+#define MAX8649_MODE3		0x03
+#define MAX8649_CONTROL		0x04
+#define MAX8649_SYNC		0x05
+#define MAX8649_RAMP		0x06
+#define MAX8649_CHIP_ID1	0x08
+#define MAX8649_CHIP_ID2	0x09
+
+/* Bits */
+#define MAX8649_EN_PD		(1 << 7)
+#define MAX8649_VID0_PD		(1 << 6)
+#define MAX8649_VID1_PD		(1 << 5)
+#define MAX8649_VID_MASK	(3 << 5)
+
+#define MAX8649_FORCE_PWM	(1 << 7)
+#define MAX8649_SYNC_EXTCLK	(1 << 6)
+
+#define MAX8649_EXT_MASK	(3 << 6)
+
+#define MAX8649_RAMP_MASK	(7 << 5)
+#define MAX8649_RAMP_DOWN	(1 << 1)
+
+struct max8649_regulator_info {
+	struct regulator_dev	*regulator;
+	struct device		*dev;
+	struct regmap		*regmap;
+
+	int		vol_reg;
+	unsigned	mode:2;	/* bit[1:0] = VID1, VID0 */
+	unsigned	extclk_freq:2;
+	unsigned	extclk:1;
+	unsigned	ramp_timing:3;
+	unsigned	ramp_down:1;
+};
+
+/* I2C operations */
+
+static inline int check_range(int min_uV, int max_uV)
+{
+	if ((min_uV < MAX8649_DCDC_VMIN) || (max_uV > MAX8649_DCDC_VMAX)
+		|| (min_uV > max_uV))
+		return -EINVAL;
+	return 0;
+}
+
+static int max8649_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+	return (MAX8649_DCDC_VMIN + index * MAX8649_DCDC_STEP);
+}
+
+static int max8649_get_voltage(struct regulator_dev *rdev)
+{
+	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned int val;
+	unsigned char data;
+	int ret;
+
+	ret = regmap_read(info->regmap, info->vol_reg, &val);
+	if (ret != 0)
+		return ret;
+	data = (unsigned char)val & MAX8649_VOL_MASK;
+	return max8649_list_voltage(rdev, data);
+}
+
+static int max8649_set_voltage(struct regulator_dev *rdev,
+			       int min_uV, int max_uV, unsigned *selector)
+{
+	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned char data, mask;
+
+	if (check_range(min_uV, max_uV)) {
+		dev_err(info->dev, "invalid voltage range (%d, %d) uV\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+	data = DIV_ROUND_UP(min_uV - MAX8649_DCDC_VMIN, MAX8649_DCDC_STEP);
+	mask = MAX8649_VOL_MASK;
+	*selector = data & mask;
+
+	return regmap_update_bits(info->regmap, info->vol_reg, mask, data);
+}
+
+/* EN_PD means pulldown on EN input */
+static int max8649_enable(struct regulator_dev *rdev)
+{
+	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+	return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, 0);
+}
+
+/*
+ * Applied internal pulldown resistor on EN input pin.
+ * If pulldown EN pin outside, it would be better.
+ */
+static int max8649_disable(struct regulator_dev *rdev)
+{
+	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+	return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD,
+				MAX8649_EN_PD);
+}
+
+static int max8649_is_enabled(struct regulator_dev *rdev)
+{
+	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(info->regmap, MAX8649_CONTROL, &val);
+	if (ret != 0)
+		return ret;
+	return !((unsigned char)val & MAX8649_EN_PD);
+}
+
+static int max8649_enable_time(struct regulator_dev *rdev)
+{
+	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+	int voltage, rate, ret;
+	unsigned int val;
+
+	/* get voltage */
+	ret = regmap_read(info->regmap, info->vol_reg, &val);
+	if (ret != 0)
+		return ret;
+	val &= MAX8649_VOL_MASK;
+	voltage = max8649_list_voltage(rdev, (unsigned char)val); /* uV */
+
+	/* get rate */
+	ret = regmap_read(info->regmap, MAX8649_RAMP, &val);
+	if (ret != 0)
+		return ret;
+	ret = (val & MAX8649_RAMP_MASK) >> 5;
+	rate = (32 * 1000) >> ret;	/* uV/uS */
+
+	return DIV_ROUND_UP(voltage, rate);
+}
+
+static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		regmap_update_bits(info->regmap, info->vol_reg, MAX8649_FORCE_PWM,
+				   MAX8649_FORCE_PWM);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		regmap_update_bits(info->regmap, info->vol_reg,
+				   MAX8649_FORCE_PWM, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static unsigned int max8649_get_mode(struct regulator_dev *rdev)
+{
+	struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(info->regmap, info->vol_reg, &val);
+	if (ret != 0)
+		return ret;
+	if (val & MAX8649_FORCE_PWM)
+		return REGULATOR_MODE_FAST;
+	return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops max8649_dcdc_ops = {
+	.set_voltage	= max8649_set_voltage,
+	.get_voltage	= max8649_get_voltage,
+	.list_voltage	= max8649_list_voltage,
+	.enable		= max8649_enable,
+	.disable	= max8649_disable,
+	.is_enabled	= max8649_is_enabled,
+	.enable_time	= max8649_enable_time,
+	.set_mode	= max8649_set_mode,
+	.get_mode	= max8649_get_mode,
+
+};
+
+static struct regulator_desc dcdc_desc = {
+	.name		= "max8649",
+	.ops		= &max8649_dcdc_ops,
+	.type		= REGULATOR_VOLTAGE,
+	.n_voltages	= 1 << 6,
+	.owner		= THIS_MODULE,
+};
+
+static struct regmap_config max8649_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int __devinit max8649_regulator_probe(struct i2c_client *client,
+					     const struct i2c_device_id *id)
+{
+	struct max8649_platform_data *pdata = client->dev.platform_data;
+	struct max8649_regulator_info *info = NULL;
+	unsigned int val;
+	unsigned char data;
+	int ret;
+
+	info = kzalloc(sizeof(struct max8649_regulator_info), GFP_KERNEL);
+	if (!info) {
+		dev_err(&client->dev, "No enough memory\n");
+		return -ENOMEM;
+	}
+
+	info->regmap = regmap_init_i2c(client, &max8649_regmap_config);
+	if (IS_ERR(info->regmap)) {
+		ret = PTR_ERR(info->regmap);
+		dev_err(&client->dev, "Failed to allocate register map: %d\n", ret);
+		goto fail;
+	}
+
+	info->dev = &client->dev;
+	i2c_set_clientdata(client, info);
+
+	info->mode = pdata->mode;
+	switch (info->mode) {
+	case 0:
+		info->vol_reg = MAX8649_MODE0;
+		break;
+	case 1:
+		info->vol_reg = MAX8649_MODE1;
+		break;
+	case 2:
+		info->vol_reg = MAX8649_MODE2;
+		break;
+	case 3:
+		info->vol_reg = MAX8649_MODE3;
+		break;
+	default:
+		break;
+	}
+
+	ret = regmap_read(info->regmap, MAX8649_CHIP_ID1, &val);
+	if (ret != 0) {
+		dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n",
+			ret);
+		goto out;
+	}
+	dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val);
+
+	/* enable VID0 & VID1 */
+	regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_VID_MASK, 0);
+
+	/* enable/disable external clock synchronization */
+	info->extclk = pdata->extclk;
+	data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0;
+	regmap_update_bits(info->regmap, info->vol_reg, MAX8649_SYNC_EXTCLK, data);
+	if (info->extclk) {
+		/* set external clock frequency */
+		info->extclk_freq = pdata->extclk_freq;
+		regmap_update_bits(info->regmap, MAX8649_SYNC, MAX8649_EXT_MASK,
+				   info->extclk_freq << 6);
+	}
+
+	if (pdata->ramp_timing) {
+		info->ramp_timing = pdata->ramp_timing;
+		regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_MASK,
+				   info->ramp_timing << 5);
+	}
+
+	info->ramp_down = pdata->ramp_down;
+	if (info->ramp_down) {
+		regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_DOWN,
+				   MAX8649_RAMP_DOWN);
+	}
+
+	info->regulator = regulator_register(&dcdc_desc, &client->dev,
+					     pdata->regulator, info, NULL);
+	if (IS_ERR(info->regulator)) {
+		dev_err(info->dev, "failed to register regulator %s\n",
+			dcdc_desc.name);
+		ret = PTR_ERR(info->regulator);
+		goto out;
+	}
+
+	dev_info(info->dev, "Max8649 regulator device is detected.\n");
+	return 0;
+out:
+	regmap_exit(info->regmap);
+fail:
+	kfree(info);
+	return ret;
+}
+
+static int __devexit max8649_regulator_remove(struct i2c_client *client)
+{
+	struct max8649_regulator_info *info = i2c_get_clientdata(client);
+
+	if (info) {
+		if (info->regulator)
+			regulator_unregister(info->regulator);
+		regmap_exit(info->regmap);
+		kfree(info);
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id max8649_id[] = {
+	{ "max8649", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max8649_id);
+
+static struct i2c_driver max8649_driver = {
+	.probe		= max8649_regulator_probe,
+	.remove		= __devexit_p(max8649_regulator_remove),
+	.driver		= {
+		.name	= "max8649",
+	},
+	.id_table	= max8649_id,
+};
+
+static int __init max8649_init(void)
+{
+	return i2c_add_driver(&max8649_driver);
+}
+subsys_initcall(max8649_init);
+
+static void __exit max8649_exit(void)
+{
+	i2c_del_driver(&max8649_driver);
+}
+module_exit(max8649_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/max8660.c b/ap/os/linux/linux-3.4.x/drivers/regulator/max8660.c
new file mode 100644
index 0000000..4c5b053
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/max8660.c
@@ -0,0 +1,521 @@
+/*
+ * max8660.c  --  Voltage regulation for the Maxim 8660/8661
+ *
+ * based on max1586.c and wm8400-regulator.c
+ *
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix e.K.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Some info:
+ *
+ * Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8660-MAX8661.pdf
+ *
+ * This chip is a bit nasty because it is a write-only device. Thus, the driver
+ * uses shadow registers to keep track of its values. The main problem appears
+ * to be the initialization: When Linux boots up, we cannot know if the chip is
+ * in the default state or not, so we would have to pass such information in
+ * platform_data. As this adds a bit of complexity to the driver, this is left
+ * out for now until it is really needed.
+ *
+ * [A|S|M]DTV1 registers are currently not used, but [A|S|M]DTV2.
+ *
+ * If the driver is feature complete, it might be worth to check if one set of
+ * functions for V3-V7 is sufficient. For maximum flexibility during
+ * development, they are separated for now.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/slab.h>
+#include <linux/regulator/max8660.h>
+
+#define MAX8660_DCDC_MIN_UV	 725000
+#define MAX8660_DCDC_MAX_UV	1800000
+#define MAX8660_DCDC_STEP	  25000
+#define MAX8660_DCDC_MAX_SEL	0x2b
+
+#define MAX8660_LDO5_MIN_UV	1700000
+#define MAX8660_LDO5_MAX_UV	2000000
+#define MAX8660_LDO5_STEP	  25000
+#define MAX8660_LDO5_MAX_SEL	0x0c
+
+#define MAX8660_LDO67_MIN_UV	1800000
+#define MAX8660_LDO67_MAX_UV	3300000
+#define MAX8660_LDO67_STEP	 100000
+#define MAX8660_LDO67_MAX_SEL	0x0f
+
+enum {
+	MAX8660_OVER1,
+	MAX8660_OVER2,
+	MAX8660_VCC1,
+	MAX8660_ADTV1,
+	MAX8660_ADTV2,
+	MAX8660_SDTV1,
+	MAX8660_SDTV2,
+	MAX8660_MDTV1,
+	MAX8660_MDTV2,
+	MAX8660_L12VCR,
+	MAX8660_FPWM,
+	MAX8660_N_REGS,	/* not a real register */
+};
+
+struct max8660 {
+	struct i2c_client *client;
+	u8 shadow_regs[MAX8660_N_REGS];		/* as chip is write only */
+	struct regulator_dev *rdev[];
+};
+
+static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val)
+{
+	static const u8 max8660_addresses[MAX8660_N_REGS] =
+	  { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 };
+
+	int ret;
+	u8 reg_val = (max8660->shadow_regs[reg] & mask) | val;
+	dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n",
+			max8660_addresses[reg], reg_val);
+
+	ret = i2c_smbus_write_byte_data(max8660->client,
+			max8660_addresses[reg], reg_val);
+	if (ret == 0)
+		max8660->shadow_regs[reg] = reg_val;
+
+	return ret;
+}
+
+
+/*
+ * DCDC functions
+ */
+
+static int max8660_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 val = max8660->shadow_regs[MAX8660_OVER1];
+	u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+	return !!(val & mask);
+}
+
+static int max8660_dcdc_enable(struct regulator_dev *rdev)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4;
+	return max8660_write(max8660, MAX8660_OVER1, 0xff, bit);
+}
+
+static int max8660_dcdc_disable(struct regulator_dev *rdev)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4;
+	return max8660_write(max8660, MAX8660_OVER1, mask, 0);
+}
+
+static int max8660_dcdc_list(struct regulator_dev *rdev, unsigned selector)
+{
+	if (selector > MAX8660_DCDC_MAX_SEL)
+		return -EINVAL;
+	return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
+}
+
+static int max8660_dcdc_get(struct regulator_dev *rdev)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
+	u8 selector = max8660->shadow_regs[reg];
+	return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP;
+}
+
+static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV,
+			    unsigned int *s)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 reg, selector, bits;
+	int ret;
+
+	if (min_uV < MAX8660_DCDC_MIN_UV || min_uV > MAX8660_DCDC_MAX_UV)
+		return -EINVAL;
+	if (max_uV < MAX8660_DCDC_MIN_UV || max_uV > MAX8660_DCDC_MAX_UV)
+		return -EINVAL;
+
+	selector = DIV_ROUND_UP(min_uV - MAX8660_DCDC_MIN_UV,
+				MAX8660_DCDC_STEP);
+
+	ret = max8660_dcdc_list(rdev, selector);
+	if (ret < 0 || ret > max_uV)
+		return -EINVAL;
+
+	*s = selector;
+
+	reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;
+	ret = max8660_write(max8660, reg, 0, selector);
+	if (ret)
+		return ret;
+
+	/* Select target voltage register and activate regulation */
+	bits = (rdev_get_id(rdev) == MAX8660_V3) ? 0x03 : 0x30;
+	return max8660_write(max8660, MAX8660_VCC1, 0xff, bits);
+}
+
+static struct regulator_ops max8660_dcdc_ops = {
+	.is_enabled = max8660_dcdc_is_enabled,
+	.list_voltage = max8660_dcdc_list,
+	.set_voltage = max8660_dcdc_set,
+	.get_voltage = max8660_dcdc_get,
+};
+
+
+/*
+ * LDO5 functions
+ */
+
+static int max8660_ldo5_list(struct regulator_dev *rdev, unsigned selector)
+{
+	if (selector > MAX8660_LDO5_MAX_SEL)
+		return -EINVAL;
+	return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
+}
+
+static int max8660_ldo5_get(struct regulator_dev *rdev)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 selector = max8660->shadow_regs[MAX8660_MDTV2];
+
+	return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP;
+}
+
+static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV,
+			    unsigned int *s)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 selector;
+	int ret;
+
+	if (min_uV < MAX8660_LDO5_MIN_UV || min_uV > MAX8660_LDO5_MAX_UV)
+		return -EINVAL;
+	if (max_uV < MAX8660_LDO5_MIN_UV || max_uV > MAX8660_LDO5_MAX_UV)
+		return -EINVAL;
+
+	selector = DIV_ROUND_UP(min_uV - MAX8660_LDO5_MIN_UV,
+				MAX8660_LDO5_STEP);
+
+	ret = max8660_ldo5_list(rdev, selector);
+	if (ret < 0 || ret > max_uV)
+		return -EINVAL;
+
+	*s = selector;
+
+	ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector);
+	if (ret)
+		return ret;
+
+	/* Select target voltage register and activate regulation */
+	return max8660_write(max8660, MAX8660_VCC1, 0xff, 0xc0);
+}
+
+static struct regulator_ops max8660_ldo5_ops = {
+	.list_voltage = max8660_ldo5_list,
+	.set_voltage = max8660_ldo5_set,
+	.get_voltage = max8660_ldo5_get,
+};
+
+
+/*
+ * LDO67 functions
+ */
+
+static int max8660_ldo67_is_enabled(struct regulator_dev *rdev)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 val = max8660->shadow_regs[MAX8660_OVER2];
+	u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+	return !!(val & mask);
+}
+
+static int max8660_ldo67_enable(struct regulator_dev *rdev)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4;
+	return max8660_write(max8660, MAX8660_OVER2, 0xff, bit);
+}
+
+static int max8660_ldo67_disable(struct regulator_dev *rdev)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4;
+	return max8660_write(max8660, MAX8660_OVER2, mask, 0);
+}
+
+static int max8660_ldo67_list(struct regulator_dev *rdev, unsigned selector)
+{
+	if (selector > MAX8660_LDO67_MAX_SEL)
+		return -EINVAL;
+	return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
+}
+
+static int max8660_ldo67_get(struct regulator_dev *rdev)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4;
+	u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf;
+
+	return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP;
+}
+
+static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV,
+			     int max_uV, unsigned int *s)
+{
+	struct max8660 *max8660 = rdev_get_drvdata(rdev);
+	u8 selector;
+	int ret;
+
+	if (min_uV < MAX8660_LDO67_MIN_UV || min_uV > MAX8660_LDO67_MAX_UV)
+		return -EINVAL;
+	if (max_uV < MAX8660_LDO67_MIN_UV || max_uV > MAX8660_LDO67_MAX_UV)
+		return -EINVAL;
+
+	selector = DIV_ROUND_UP(min_uV - MAX8660_LDO67_MIN_UV,
+				MAX8660_LDO67_STEP);
+
+	ret = max8660_ldo67_list(rdev, selector);
+	if (ret < 0 || ret > max_uV)
+		return -EINVAL;
+
+	*s = selector;
+
+	if (rdev_get_id(rdev) == MAX8660_V6)
+		return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector);
+	else
+		return max8660_write(max8660, MAX8660_L12VCR, 0x0f, selector << 4);
+}
+
+static struct regulator_ops max8660_ldo67_ops = {
+	.is_enabled = max8660_ldo67_is_enabled,
+	.enable = max8660_ldo67_enable,
+	.disable = max8660_ldo67_disable,
+	.list_voltage = max8660_ldo67_list,
+	.get_voltage = max8660_ldo67_get,
+	.set_voltage = max8660_ldo67_set,
+};
+
+static struct regulator_desc max8660_reg[] = {
+	{
+		.name = "V3(DCDC)",
+		.id = MAX8660_V3,
+		.ops = &max8660_dcdc_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = MAX8660_DCDC_MAX_SEL + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "V4(DCDC)",
+		.id = MAX8660_V4,
+		.ops = &max8660_dcdc_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = MAX8660_DCDC_MAX_SEL + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "V5(LDO)",
+		.id = MAX8660_V5,
+		.ops = &max8660_ldo5_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = MAX8660_LDO5_MAX_SEL + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "V6(LDO)",
+		.id = MAX8660_V6,
+		.ops = &max8660_ldo67_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = MAX8660_LDO67_MAX_SEL + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "V7(LDO)",
+		.id = MAX8660_V7,
+		.ops = &max8660_ldo67_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = MAX8660_LDO67_MAX_SEL + 1,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __devinit max8660_probe(struct i2c_client *client,
+				   const struct i2c_device_id *i2c_id)
+{
+	struct regulator_dev **rdev;
+	struct max8660_platform_data *pdata = client->dev.platform_data;
+	struct max8660 *max8660;
+	int boot_on, i, id, ret = -EINVAL;
+
+	if (pdata->num_subdevs > MAX8660_V_END) {
+		dev_err(&client->dev, "Too many regulators found!\n");
+		goto out;
+	}
+
+	max8660 = kzalloc(sizeof(struct max8660) +
+			sizeof(struct regulator_dev *) * MAX8660_V_END,
+			GFP_KERNEL);
+	if (!max8660) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	max8660->client = client;
+	rdev = max8660->rdev;
+
+	if (pdata->en34_is_high) {
+		/* Simulate always on */
+		max8660->shadow_regs[MAX8660_OVER1] = 5;
+	} else {
+		/* Otherwise devices can be toggled via software */
+		max8660_dcdc_ops.enable = max8660_dcdc_enable;
+		max8660_dcdc_ops.disable = max8660_dcdc_disable;
+	}
+
+	/*
+	 * First, set up shadow registers to prevent glitches. As some
+	 * registers are shared between regulators, everything must be properly
+	 * set up for all regulators in advance.
+	 */
+	max8660->shadow_regs[MAX8660_ADTV1] =
+		max8660->shadow_regs[MAX8660_ADTV2] =
+		max8660->shadow_regs[MAX8660_SDTV1] =
+		max8660->shadow_regs[MAX8660_SDTV2] = 0x1b;
+	max8660->shadow_regs[MAX8660_MDTV1] =
+		max8660->shadow_regs[MAX8660_MDTV2] = 0x04;
+
+	for (i = 0; i < pdata->num_subdevs; i++) {
+
+		if (!pdata->subdevs[i].platform_data)
+			goto err_free;
+
+		boot_on = pdata->subdevs[i].platform_data->constraints.boot_on;
+
+		switch (pdata->subdevs[i].id) {
+		case MAX8660_V3:
+			if (boot_on)
+				max8660->shadow_regs[MAX8660_OVER1] |= 1;
+			break;
+
+		case MAX8660_V4:
+			if (boot_on)
+				max8660->shadow_regs[MAX8660_OVER1] |= 4;
+			break;
+
+		case MAX8660_V5:
+			break;
+
+		case MAX8660_V6:
+			if (boot_on)
+				max8660->shadow_regs[MAX8660_OVER2] |= 2;
+			break;
+
+		case MAX8660_V7:
+			if (!strcmp(i2c_id->name, "max8661")) {
+				dev_err(&client->dev, "Regulator not on this chip!\n");
+				goto err_free;
+			}
+
+			if (boot_on)
+				max8660->shadow_regs[MAX8660_OVER2] |= 4;
+			break;
+
+		default:
+			dev_err(&client->dev, "invalid regulator %s\n",
+				 pdata->subdevs[i].name);
+			goto err_free;
+		}
+	}
+
+	/* Finally register devices */
+	for (i = 0; i < pdata->num_subdevs; i++) {
+
+		id = pdata->subdevs[i].id;
+
+		rdev[i] = regulator_register(&max8660_reg[id], &client->dev,
+					     pdata->subdevs[i].platform_data,
+					     max8660, NULL);
+		if (IS_ERR(rdev[i])) {
+			ret = PTR_ERR(rdev[i]);
+			dev_err(&client->dev, "failed to register %s\n",
+				max8660_reg[id].name);
+			goto err_unregister;
+		}
+	}
+
+	i2c_set_clientdata(client, max8660);
+	dev_info(&client->dev, "Maxim 8660/8661 regulator driver loaded\n");
+	return 0;
+
+err_unregister:
+	while (--i >= 0)
+		regulator_unregister(rdev[i]);
+err_free:
+	kfree(max8660);
+out:
+	return ret;
+}
+
+static int __devexit max8660_remove(struct i2c_client *client)
+{
+	struct max8660 *max8660 = i2c_get_clientdata(client);
+	int i;
+
+	for (i = 0; i < MAX8660_V_END; i++)
+		if (max8660->rdev[i])
+			regulator_unregister(max8660->rdev[i]);
+	kfree(max8660);
+
+	return 0;
+}
+
+static const struct i2c_device_id max8660_id[] = {
+	{ "max8660", 0 },
+	{ "max8661", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max8660_id);
+
+static struct i2c_driver max8660_driver = {
+	.probe = max8660_probe,
+	.remove = __devexit_p(max8660_remove),
+	.driver		= {
+		.name	= "max8660",
+		.owner	= THIS_MODULE,
+	},
+	.id_table	= max8660_id,
+};
+
+static int __init max8660_init(void)
+{
+	return i2c_add_driver(&max8660_driver);
+}
+subsys_initcall(max8660_init);
+
+static void __exit max8660_exit(void)
+{
+	i2c_del_driver(&max8660_driver);
+}
+module_exit(max8660_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("MAXIM 8660/8661 voltage regulator driver");
+MODULE_AUTHOR("Wolfram Sang");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/max8925-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/max8925-regulator.c
new file mode 100644
index 0000000..2f242f4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/max8925-regulator.c
@@ -0,0 +1,322 @@
+/*
+ * Regulators driver for Maxim max8925
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ *      Haojian Zhuang <haojian.zhuang@marvell.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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/max8925.h>
+
+#define SD1_DVM_VMIN		850000
+#define SD1_DVM_VMAX		1000000
+#define SD1_DVM_STEP		50000
+#define SD1_DVM_SHIFT		5		/* SDCTL1 bit5 */
+#define SD1_DVM_EN		6		/* SDV1 bit 6 */
+
+/* bit definitions in LDO control registers */
+#define LDO_SEQ_I2C		0x7		/* Power U/D by i2c */
+#define LDO_SEQ_MASK		0x7		/* Power U/D sequence mask */
+#define LDO_SEQ_SHIFT		2		/* Power U/D sequence offset */
+#define LDO_I2C_EN		0x1		/* Enable by i2c */
+#define LDO_I2C_EN_MASK		0x1		/* Enable mask by i2c */
+#define LDO_I2C_EN_SHIFT	0		/* Enable offset by i2c */
+
+struct max8925_regulator_info {
+	struct regulator_desc	desc;
+	struct regulator_dev	*regulator;
+	struct i2c_client	*i2c;
+	struct max8925_chip	*chip;
+
+	int	min_uV;
+	int	max_uV;
+	int	step_uV;
+	int	vol_reg;
+	int	vol_shift;
+	int	vol_nbits;
+	int	enable_reg;
+};
+
+static inline int check_range(struct max8925_regulator_info *info,
+			      int min_uV, int max_uV)
+{
+	if (min_uV < info->min_uV || min_uV > info->max_uV)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+	return info->min_uV + index * info->step_uV;
+}
+
+static int max8925_set_voltage(struct regulator_dev *rdev,
+			       int min_uV, int max_uV, unsigned int *selector)
+{
+	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned char data, mask;
+
+	if (check_range(info, min_uV, max_uV)) {
+		dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+	data = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);
+	*selector = data;
+	data <<= info->vol_shift;
+	mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+	return max8925_set_bits(info->i2c, info->vol_reg, mask, data);
+}
+
+static int max8925_get_voltage(struct regulator_dev *rdev)
+{
+	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned char data, mask;
+	int ret;
+
+	ret = max8925_reg_read(info->i2c, info->vol_reg);
+	if (ret < 0)
+		return ret;
+	mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+	data = (ret & mask) >> info->vol_shift;
+
+	return max8925_list_voltage(rdev, data);
+}
+
+static int max8925_enable(struct regulator_dev *rdev)
+{
+	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+
+	return max8925_set_bits(info->i2c, info->enable_reg,
+				LDO_SEQ_MASK << LDO_SEQ_SHIFT |
+				LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT,
+				LDO_SEQ_I2C << LDO_SEQ_SHIFT |
+				LDO_I2C_EN << LDO_I2C_EN_SHIFT);
+}
+
+static int max8925_disable(struct regulator_dev *rdev)
+{
+	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+
+	return max8925_set_bits(info->i2c, info->enable_reg,
+				LDO_SEQ_MASK << LDO_SEQ_SHIFT |
+				LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT,
+				LDO_SEQ_I2C << LDO_SEQ_SHIFT);
+}
+
+static int max8925_is_enabled(struct regulator_dev *rdev)
+{
+	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+	int ldo_seq, ret;
+
+	ret = max8925_reg_read(info->i2c, info->enable_reg);
+	if (ret < 0)
+		return ret;
+	ldo_seq = (ret >> LDO_SEQ_SHIFT) & LDO_SEQ_MASK;
+	if (ldo_seq != LDO_SEQ_I2C)
+		return 1;
+	else
+		return ret & (LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT);
+}
+
+static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV)
+{
+	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+	unsigned char data, mask;
+
+	if (uV < SD1_DVM_VMIN || uV > SD1_DVM_VMAX)
+		return -EINVAL;
+
+	data = DIV_ROUND_UP(uV - SD1_DVM_VMIN, SD1_DVM_STEP);
+	data <<= SD1_DVM_SHIFT;
+	mask = 3 << SD1_DVM_SHIFT;
+
+	return max8925_set_bits(info->i2c, info->enable_reg, mask, data);
+}
+
+static int max8925_set_dvm_enable(struct regulator_dev *rdev)
+{
+	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+
+	return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN,
+				1 << SD1_DVM_EN);
+}
+
+static int max8925_set_dvm_disable(struct regulator_dev *rdev)
+{
+	struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
+
+	return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, 0);
+}
+
+static struct regulator_ops max8925_regulator_sdv_ops = {
+	.set_voltage		= max8925_set_voltage,
+	.get_voltage		= max8925_get_voltage,
+	.enable			= max8925_enable,
+	.disable		= max8925_disable,
+	.is_enabled		= max8925_is_enabled,
+	.set_suspend_voltage	= max8925_set_dvm_voltage,
+	.set_suspend_enable	= max8925_set_dvm_enable,
+	.set_suspend_disable	= max8925_set_dvm_disable,
+};
+
+static struct regulator_ops max8925_regulator_ldo_ops = {
+	.set_voltage		= max8925_set_voltage,
+	.get_voltage		= max8925_get_voltage,
+	.enable			= max8925_enable,
+	.disable		= max8925_disable,
+	.is_enabled		= max8925_is_enabled,
+};
+
+#define MAX8925_SDV(_id, min, max, step)			\
+{								\
+	.desc	= {						\
+		.name	= "SDV" #_id,				\
+		.ops	= &max8925_regulator_sdv_ops,		\
+		.type	= REGULATOR_VOLTAGE,			\
+		.id	= MAX8925_ID_SD##_id,			\
+		.owner	= THIS_MODULE,				\
+	},							\
+	.min_uV		= min * 1000,				\
+	.max_uV		= max * 1000,				\
+	.step_uV	= step * 1000,				\
+	.vol_reg	= MAX8925_SDV##_id,			\
+	.vol_shift	= 0,					\
+	.vol_nbits	= 6,					\
+	.enable_reg	= MAX8925_SDCTL##_id,			\
+}
+
+#define MAX8925_LDO(_id, min, max, step)			\
+{								\
+	.desc	= {						\
+		.name	= "LDO" #_id,				\
+		.ops	= &max8925_regulator_ldo_ops,		\
+		.type	= REGULATOR_VOLTAGE,			\
+		.id	= MAX8925_ID_LDO##_id,			\
+		.owner	= THIS_MODULE,				\
+	},							\
+	.min_uV		= min * 1000,				\
+	.max_uV		= max * 1000,				\
+	.step_uV	= step * 1000,				\
+	.vol_reg	= MAX8925_LDOVOUT##_id,			\
+	.vol_shift	= 0,					\
+	.vol_nbits	= 6,					\
+	.enable_reg	= MAX8925_LDOCTL##_id,			\
+}
+
+static struct max8925_regulator_info max8925_regulator_info[] = {
+	MAX8925_SDV(1, 637.5, 1425, 12.5),
+	MAX8925_SDV(2,   650, 2225,   25),
+	MAX8925_SDV(3,   750, 3900,   50),
+
+	MAX8925_LDO(1,  750, 3900, 50),
+	MAX8925_LDO(2,  650, 2250, 25),
+	MAX8925_LDO(3,  650, 2250, 25),
+	MAX8925_LDO(4,  750, 3900, 50),
+	MAX8925_LDO(5,  750, 3900, 50),
+	MAX8925_LDO(6,  750, 3900, 50),
+	MAX8925_LDO(7,  750, 3900, 50),
+	MAX8925_LDO(8,  750, 3900, 50),
+	MAX8925_LDO(9,  750, 3900, 50),
+	MAX8925_LDO(10, 750, 3900, 50),
+	MAX8925_LDO(11, 750, 3900, 50),
+	MAX8925_LDO(12, 750, 3900, 50),
+	MAX8925_LDO(13, 750, 3900, 50),
+	MAX8925_LDO(14, 750, 3900, 50),
+	MAX8925_LDO(15, 750, 3900, 50),
+	MAX8925_LDO(16, 750, 3900, 50),
+	MAX8925_LDO(17, 650, 2250, 25),
+	MAX8925_LDO(18, 650, 2250, 25),
+	MAX8925_LDO(19, 750, 3900, 50),
+	MAX8925_LDO(20, 750, 3900, 50),
+};
+
+static struct max8925_regulator_info * __devinit find_regulator_info(int id)
+{
+	struct max8925_regulator_info *ri;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) {
+		ri = &max8925_regulator_info[i];
+		if (ri->desc.id == id)
+			return ri;
+	}
+	return NULL;
+}
+
+static int __devinit max8925_regulator_probe(struct platform_device *pdev)
+{
+	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+	struct max8925_platform_data *pdata = chip->dev->platform_data;
+	struct max8925_regulator_info *ri;
+	struct regulator_dev *rdev;
+
+	ri = find_regulator_info(pdev->id);
+	if (ri == NULL) {
+		dev_err(&pdev->dev, "invalid regulator ID specified\n");
+		return -EINVAL;
+	}
+	ri->i2c = chip->i2c;
+	ri->chip = chip;
+
+	rdev = regulator_register(&ri->desc, &pdev->dev,
+				  pdata->regulator[pdev->id], ri, NULL);
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "failed to register regulator %s\n",
+				ri->desc.name);
+		return PTR_ERR(rdev);
+	}
+
+	platform_set_drvdata(pdev, rdev);
+	return 0;
+}
+
+static int __devexit max8925_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	regulator_unregister(rdev);
+
+	return 0;
+}
+
+static struct platform_driver max8925_regulator_driver = {
+	.driver		= {
+		.name	= "max8925-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= max8925_regulator_probe,
+	.remove		= __devexit_p(max8925_regulator_remove),
+};
+
+static int __init max8925_regulator_init(void)
+{
+	return platform_driver_register(&max8925_regulator_driver);
+}
+subsys_initcall(max8925_regulator_init);
+
+static void __exit max8925_regulator_exit(void)
+{
+	platform_driver_unregister(&max8925_regulator_driver);
+}
+module_exit(max8925_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC");
+MODULE_ALIAS("platform:max8925-regulator");
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/max8952.c b/ap/os/linux/linux-3.4.x/drivers/regulator/max8952.c
new file mode 100644
index 0000000..75d8940
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/max8952.c
@@ -0,0 +1,364 @@
+/*
+ * max8952.c - Voltage and current regulation for the Maxim 8952
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/max8952.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/* Registers */
+enum {
+	MAX8952_REG_MODE0,
+	MAX8952_REG_MODE1,
+	MAX8952_REG_MODE2,
+	MAX8952_REG_MODE3,
+	MAX8952_REG_CONTROL,
+	MAX8952_REG_SYNC,
+	MAX8952_REG_RAMP,
+	MAX8952_REG_CHIP_ID1,
+	MAX8952_REG_CHIP_ID2,
+};
+
+struct max8952_data {
+	struct i2c_client	*client;
+	struct device		*dev;
+	struct max8952_platform_data *pdata;
+	struct regulator_dev	*rdev;
+
+	bool vid0;
+	bool vid1;
+	bool en;
+};
+
+static int max8952_read_reg(struct max8952_data *max8952, u8 reg)
+{
+	int ret = i2c_smbus_read_byte_data(max8952->client, reg);
+	if (ret > 0)
+		ret &= 0xff;
+
+	return ret;
+}
+
+static int max8952_write_reg(struct max8952_data *max8952,
+		u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(max8952->client, reg, value);
+}
+
+static int max8952_voltage(struct max8952_data *max8952, u8 mode)
+{
+	return (max8952->pdata->dvs_mode[mode] * 10 + 770) * 1000;
+}
+
+static int max8952_list_voltage(struct regulator_dev *rdev,
+		unsigned int selector)
+{
+	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
+
+	if (rdev_get_id(rdev) != 0)
+		return -EINVAL;
+
+	return max8952_voltage(max8952, selector);
+}
+
+static int max8952_is_enabled(struct regulator_dev *rdev)
+{
+	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
+	return max8952->en;
+}
+
+static int max8952_enable(struct regulator_dev *rdev)
+{
+	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
+
+	/* If not valid, assume "ALWAYS_HIGH" */
+	if (gpio_is_valid(max8952->pdata->gpio_en))
+		gpio_set_value(max8952->pdata->gpio_en, 1);
+
+	max8952->en = true;
+	return 0;
+}
+
+static int max8952_disable(struct regulator_dev *rdev)
+{
+	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
+
+	/* If not valid, assume "ALWAYS_HIGH" -> not permitted */
+	if (gpio_is_valid(max8952->pdata->gpio_en))
+		gpio_set_value(max8952->pdata->gpio_en, 0);
+	else
+		return -EPERM;
+
+	max8952->en = false;
+	return 0;
+}
+
+static int max8952_get_voltage(struct regulator_dev *rdev)
+{
+	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
+	u8 vid = 0;
+
+	if (max8952->vid0)
+		vid += 1;
+	if (max8952->vid1)
+		vid += 2;
+
+	return max8952_voltage(max8952, vid);
+}
+
+static int max8952_set_voltage(struct regulator_dev *rdev,
+			       int min_uV, int max_uV, unsigned *selector)
+{
+	struct max8952_data *max8952 = rdev_get_drvdata(rdev);
+	s8 vid = -1, i;
+
+	if (!gpio_is_valid(max8952->pdata->gpio_vid0) ||
+			!gpio_is_valid(max8952->pdata->gpio_vid1)) {
+		/* DVS not supported */
+		return -EPERM;
+	}
+
+	for (i = 0; i < MAX8952_NUM_DVS_MODE; i++) {
+		int volt = max8952_voltage(max8952, i);
+
+		/* Set the voltage as low as possible within the range */
+		if (volt <= max_uV && volt >= min_uV)
+			if (vid == -1 || max8952_voltage(max8952, vid) > volt)
+				vid = i;
+	}
+
+	if (vid >= 0 && vid < MAX8952_NUM_DVS_MODE) {
+		max8952->vid0 = (vid % 2 == 1);
+		max8952->vid1 = (((vid >> 1) % 2) == 1);
+		*selector = vid;
+		gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0);
+		gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1);
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct regulator_ops max8952_ops = {
+	.list_voltage		= max8952_list_voltage,
+	.is_enabled		= max8952_is_enabled,
+	.enable			= max8952_enable,
+	.disable		= max8952_disable,
+	.get_voltage		= max8952_get_voltage,
+	.set_voltage		= max8952_set_voltage,
+	.set_suspend_disable	= max8952_disable,
+};
+
+static struct regulator_desc regulator = {
+	.name		= "MAX8952_VOUT",
+	.id		= 0,
+	.n_voltages	= MAX8952_NUM_DVS_MODE,
+	.ops		= &max8952_ops,
+	.type		= REGULATOR_VOLTAGE,
+	.owner		= THIS_MODULE,
+};
+
+static int __devinit max8952_pmic_probe(struct i2c_client *client,
+		const struct i2c_device_id *i2c_id)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct max8952_platform_data *pdata = client->dev.platform_data;
+	struct max8952_data *max8952;
+
+	int ret = 0, err = 0;
+
+	if (!pdata) {
+		dev_err(&client->dev, "Require the platform data\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+		return -EIO;
+
+	max8952 = kzalloc(sizeof(struct max8952_data), GFP_KERNEL);
+	if (!max8952)
+		return -ENOMEM;
+
+	max8952->client = client;
+	max8952->dev = &client->dev;
+	max8952->pdata = pdata;
+
+	max8952->rdev = regulator_register(&regulator, max8952->dev,
+			&pdata->reg_data, max8952, NULL);
+
+	if (IS_ERR(max8952->rdev)) {
+		ret = PTR_ERR(max8952->rdev);
+		dev_err(max8952->dev, "regulator init failed (%d)\n", ret);
+		goto err_reg;
+	}
+
+	max8952->en = !!(pdata->reg_data.constraints.boot_on);
+	max8952->vid0 = (pdata->default_mode % 2) == 1;
+	max8952->vid1 = ((pdata->default_mode >> 1) % 2) == 1;
+
+	if (gpio_is_valid(pdata->gpio_en)) {
+		if (!gpio_request(pdata->gpio_en, "MAX8952 EN"))
+			gpio_direction_output(pdata->gpio_en, max8952->en);
+		else
+			err = 1;
+	} else
+		err = 2;
+
+	if (err) {
+		dev_info(max8952->dev, "EN gpio invalid: assume that EN"
+				"is always High\n");
+		max8952->en = 1;
+		pdata->gpio_en = -1; /* Mark invalid */
+	}
+
+	err = 0;
+
+	if (gpio_is_valid(pdata->gpio_vid0) &&
+			gpio_is_valid(pdata->gpio_vid1)) {
+		if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0"))
+			gpio_direction_output(pdata->gpio_vid0,
+					(pdata->default_mode) % 2);
+		else
+			err = 1;
+
+		if (!gpio_request(pdata->gpio_vid1, "MAX8952 VID1"))
+			gpio_direction_output(pdata->gpio_vid1,
+				(pdata->default_mode >> 1) % 2);
+		else {
+			if (!err)
+				gpio_free(pdata->gpio_vid0);
+			err = 2;
+		}
+
+	} else
+		err = 3;
+
+	if (err) {
+		dev_warn(max8952->dev, "VID0/1 gpio invalid: "
+				"DVS not available.\n");
+		max8952->vid0 = 0;
+		max8952->vid1 = 0;
+		/* Mark invalid */
+		pdata->gpio_vid0 = -1;
+		pdata->gpio_vid1 = -1;
+
+		/* Disable Pulldown of EN only */
+		max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60);
+
+		dev_err(max8952->dev, "DVS modes disabled because VID0 and VID1"
+				" do not have proper controls.\n");
+	} else {
+		/*
+		 * Disable Pulldown on EN, VID0, VID1 to reduce
+		 * leakage current of MAX8952 assuming that MAX8952
+		 * is turned on (EN==1). Note that without having VID0/1
+		 * properly connected, turning pulldown off can be
+		 * problematic. Thus, turn this off only when they are
+		 * controllable by GPIO.
+		 */
+		max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x0);
+	}
+
+	max8952_write_reg(max8952, MAX8952_REG_MODE0,
+			(max8952_read_reg(max8952,
+					  MAX8952_REG_MODE0) & 0xC0) |
+			(pdata->dvs_mode[0] & 0x3F));
+	max8952_write_reg(max8952, MAX8952_REG_MODE1,
+			(max8952_read_reg(max8952,
+					  MAX8952_REG_MODE1) & 0xC0) |
+			(pdata->dvs_mode[1] & 0x3F));
+	max8952_write_reg(max8952, MAX8952_REG_MODE2,
+			(max8952_read_reg(max8952,
+					  MAX8952_REG_MODE2) & 0xC0) |
+			(pdata->dvs_mode[2] & 0x3F));
+	max8952_write_reg(max8952, MAX8952_REG_MODE3,
+			(max8952_read_reg(max8952,
+					  MAX8952_REG_MODE3) & 0xC0) |
+			(pdata->dvs_mode[3] & 0x3F));
+
+	max8952_write_reg(max8952, MAX8952_REG_SYNC,
+			(max8952_read_reg(max8952, MAX8952_REG_SYNC) & 0x3F) |
+			((pdata->sync_freq & 0x3) << 6));
+	max8952_write_reg(max8952, MAX8952_REG_RAMP,
+			(max8952_read_reg(max8952, MAX8952_REG_RAMP) & 0x1F) |
+			((pdata->ramp_speed & 0x7) << 5));
+
+	i2c_set_clientdata(client, max8952);
+
+	return 0;
+
+err_reg:
+	kfree(max8952);
+	return ret;
+}
+
+static int __devexit max8952_pmic_remove(struct i2c_client *client)
+{
+	struct max8952_data *max8952 = i2c_get_clientdata(client);
+	struct max8952_platform_data *pdata = max8952->pdata;
+	struct regulator_dev *rdev = max8952->rdev;
+
+	regulator_unregister(rdev);
+
+	gpio_free(pdata->gpio_vid0);
+	gpio_free(pdata->gpio_vid1);
+	gpio_free(pdata->gpio_en);
+
+	kfree(max8952);
+	return 0;
+}
+
+static const struct i2c_device_id max8952_ids[] = {
+	{ "max8952", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, max8952_ids);
+
+static struct i2c_driver max8952_pmic_driver = {
+	.probe		= max8952_pmic_probe,
+	.remove		= __devexit_p(max8952_pmic_remove),
+	.driver		= {
+		.name	= "max8952",
+	},
+	.id_table	= max8952_ids,
+};
+
+static int __init max8952_pmic_init(void)
+{
+	return i2c_add_driver(&max8952_pmic_driver);
+}
+subsys_initcall(max8952_pmic_init);
+
+static void __exit max8952_pmic_exit(void)
+{
+	i2c_del_driver(&max8952_pmic_driver);
+}
+module_exit(max8952_pmic_exit);
+
+MODULE_DESCRIPTION("MAXIM 8952 voltage regulator driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/max8997.c b/ap/os/linux/linux-3.4.x/drivers/regulator/max8997.c
new file mode 100644
index 0000000..8350f50
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/max8997.c
@@ -0,0 +1,1210 @@
+/*
+ * max8997.c - Regulator driver for the Maxim 8997/8966
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@smasung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8998.c
+ */
+
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+
+struct max8997_data {
+	struct device *dev;
+	struct max8997_dev *iodev;
+	int num_regulators;
+	struct regulator_dev **rdev;
+	int ramp_delay; /* in mV/us */
+
+	bool buck1_gpiodvs;
+	bool buck2_gpiodvs;
+	bool buck5_gpiodvs;
+	u8 buck1_vol[8];
+	u8 buck2_vol[8];
+	u8 buck5_vol[8];
+	int buck125_gpios[3];
+	int buck125_gpioindex;
+	bool ignore_gpiodvs_side_effect;
+
+	u8 saved_states[MAX8997_REG_MAX];
+};
+
+static inline void max8997_set_gpio(struct max8997_data *max8997)
+{
+	int set3 = (max8997->buck125_gpioindex) & 0x1;
+	int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1;
+	int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1;
+
+	gpio_set_value(max8997->buck125_gpios[0], set1);
+	gpio_set_value(max8997->buck125_gpios[1], set2);
+	gpio_set_value(max8997->buck125_gpios[2], set3);
+}
+
+struct voltage_map_desc {
+	int min;
+	int max;
+	int step;
+	unsigned int n_bits;
+};
+
+/* Voltage maps in uV */
+static const struct voltage_map_desc ldo_voltage_map_desc = {
+	.min = 800000,	.max = 3950000,	.step = 50000,	.n_bits = 6,
+}; /* LDO1 ~ 18, 21 all */
+
+static const struct voltage_map_desc buck1245_voltage_map_desc = {
+	.min = 650000,	.max = 2225000,	.step = 25000,	.n_bits = 6,
+}; /* Buck1, 2, 4, 5 */
+
+static const struct voltage_map_desc buck37_voltage_map_desc = {
+	.min = 750000,	.max = 3900000,	.step = 50000,	.n_bits = 6,
+}; /* Buck3, 7 */
+
+/* current map in uA */
+static const struct voltage_map_desc charger_current_map_desc = {
+	.min = 200000,	.max = 950000,	.step = 50000,	.n_bits = 4,
+};
+
+static const struct voltage_map_desc topoff_current_map_desc = {
+	.min = 50000,	.max = 200000,	.step = 10000,	.n_bits = 4,
+};
+
+static const struct voltage_map_desc *reg_voltage_map[] = {
+	[MAX8997_LDO1] = &ldo_voltage_map_desc,
+	[MAX8997_LDO2] = &ldo_voltage_map_desc,
+	[MAX8997_LDO3] = &ldo_voltage_map_desc,
+	[MAX8997_LDO4] = &ldo_voltage_map_desc,
+	[MAX8997_LDO5] = &ldo_voltage_map_desc,
+	[MAX8997_LDO6] = &ldo_voltage_map_desc,
+	[MAX8997_LDO7] = &ldo_voltage_map_desc,
+	[MAX8997_LDO8] = &ldo_voltage_map_desc,
+	[MAX8997_LDO9] = &ldo_voltage_map_desc,
+	[MAX8997_LDO10] = &ldo_voltage_map_desc,
+	[MAX8997_LDO11] = &ldo_voltage_map_desc,
+	[MAX8997_LDO12] = &ldo_voltage_map_desc,
+	[MAX8997_LDO13] = &ldo_voltage_map_desc,
+	[MAX8997_LDO14] = &ldo_voltage_map_desc,
+	[MAX8997_LDO15] = &ldo_voltage_map_desc,
+	[MAX8997_LDO16] = &ldo_voltage_map_desc,
+	[MAX8997_LDO17] = &ldo_voltage_map_desc,
+	[MAX8997_LDO18] = &ldo_voltage_map_desc,
+	[MAX8997_LDO21] = &ldo_voltage_map_desc,
+	[MAX8997_BUCK1] = &buck1245_voltage_map_desc,
+	[MAX8997_BUCK2] = &buck1245_voltage_map_desc,
+	[MAX8997_BUCK3] = &buck37_voltage_map_desc,
+	[MAX8997_BUCK4] = &buck1245_voltage_map_desc,
+	[MAX8997_BUCK5] = &buck1245_voltage_map_desc,
+	[MAX8997_BUCK6] = NULL,
+	[MAX8997_BUCK7] = &buck37_voltage_map_desc,
+	[MAX8997_EN32KHZ_AP] = NULL,
+	[MAX8997_EN32KHZ_CP] = NULL,
+	[MAX8997_ENVICHG] = NULL,
+	[MAX8997_ESAFEOUT1] = NULL,
+	[MAX8997_ESAFEOUT2] = NULL,
+	[MAX8997_CHARGER_CV] = NULL,
+	[MAX8997_CHARGER] = &charger_current_map_desc,
+	[MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc,
+};
+
+static int max8997_list_voltage_safeout(struct regulator_dev *rdev,
+		unsigned int selector)
+{
+	int rid = rdev_get_id(rdev);
+
+	if (rid == MAX8997_ESAFEOUT1 || rid == MAX8997_ESAFEOUT2) {
+		switch (selector) {
+		case 0:
+			return 4850000;
+		case 1:
+			return 4900000;
+		case 2:
+			return 4950000;
+		case 3:
+			return 3300000;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev,
+		unsigned int selector)
+{
+	int rid = rdev_get_id(rdev);
+
+	if (rid != MAX8997_CHARGER_CV)
+		goto err;
+
+	switch (selector) {
+	case 0x00:
+		return 4200000;
+	case 0x01 ... 0x0E:
+		return 4000000 + 20000 * (selector - 0x01);
+	case 0x0F:
+		return 4350000;
+	default:
+		return -EINVAL;
+	}
+err:
+	return -EINVAL;
+}
+
+static int max8997_list_voltage(struct regulator_dev *rdev,
+		unsigned int selector)
+{
+	const struct voltage_map_desc *desc;
+	int rid = rdev_get_id(rdev);
+	int val;
+
+	if (rid >= ARRAY_SIZE(reg_voltage_map) ||
+			rid < 0)
+		return -EINVAL;
+
+	desc = reg_voltage_map[rid];
+	if (desc == NULL)
+		return -EINVAL;
+
+	val = desc->min + desc->step * selector;
+	if (val > desc->max)
+		return -EINVAL;
+
+	return val;
+}
+
+static int max8997_get_enable_register(struct regulator_dev *rdev,
+		int *reg, int *mask, int *pattern)
+{
+	int rid = rdev_get_id(rdev);
+
+	switch (rid) {
+	case MAX8997_LDO1 ... MAX8997_LDO21:
+		*reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1);
+		*mask = 0xC0;
+		*pattern = 0xC0;
+		break;
+	case MAX8997_BUCK1:
+		*reg = MAX8997_REG_BUCK1CTRL;
+		*mask = 0x01;
+		*pattern = 0x01;
+		break;
+	case MAX8997_BUCK2:
+		*reg = MAX8997_REG_BUCK2CTRL;
+		*mask = 0x01;
+		*pattern = 0x01;
+		break;
+	case MAX8997_BUCK3:
+		*reg = MAX8997_REG_BUCK3CTRL;
+		*mask = 0x01;
+		*pattern = 0x01;
+		break;
+	case MAX8997_BUCK4:
+		*reg = MAX8997_REG_BUCK4CTRL;
+		*mask = 0x01;
+		*pattern = 0x01;
+		break;
+	case MAX8997_BUCK5:
+		*reg = MAX8997_REG_BUCK5CTRL;
+		*mask = 0x01;
+		*pattern = 0x01;
+		break;
+	case MAX8997_BUCK6:
+		*reg = MAX8997_REG_BUCK6CTRL;
+		*mask = 0x01;
+		*pattern = 0x01;
+		break;
+	case MAX8997_BUCK7:
+		*reg = MAX8997_REG_BUCK7CTRL;
+		*mask = 0x01;
+		*pattern = 0x01;
+		break;
+	case MAX8997_EN32KHZ_AP ... MAX8997_EN32KHZ_CP:
+		*reg = MAX8997_REG_MAINCON1;
+		*mask = 0x01 << (rid - MAX8997_EN32KHZ_AP);
+		*pattern = 0x01 << (rid - MAX8997_EN32KHZ_AP);
+		break;
+	case MAX8997_ENVICHG:
+		*reg = MAX8997_REG_MBCCTRL1;
+		*mask = 0x80;
+		*pattern = 0x80;
+		break;
+	case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2:
+		*reg = MAX8997_REG_SAFEOUTCTRL;
+		*mask = 0x40 << (rid - MAX8997_ESAFEOUT1);
+		*pattern = 0x40 << (rid - MAX8997_ESAFEOUT1);
+		break;
+	case MAX8997_CHARGER:
+		*reg = MAX8997_REG_MBCCTRL2;
+		*mask = 0x40;
+		*pattern = 0x40;
+		break;
+	default:
+		/* Not controllable or not exists */
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int max8997_reg_is_enabled(struct regulator_dev *rdev)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8997->iodev->i2c;
+	int ret, reg, mask, pattern;
+	u8 val;
+
+	ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
+	if (ret == -EINVAL)
+		return 1; /* "not controllable" */
+	else if (ret)
+		return ret;
+
+	ret = max8997_read_reg(i2c, reg, &val);
+	if (ret)
+		return ret;
+
+	return (val & mask) == pattern;
+}
+
+static int max8997_reg_enable(struct regulator_dev *rdev)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8997->iodev->i2c;
+	int ret, reg, mask, pattern;
+
+	ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
+	if (ret)
+		return ret;
+
+	return max8997_update_reg(i2c, reg, pattern, mask);
+}
+
+static int max8997_reg_disable(struct regulator_dev *rdev)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8997->iodev->i2c;
+	int ret, reg, mask, pattern;
+
+	ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
+	if (ret)
+		return ret;
+
+	return max8997_update_reg(i2c, reg, ~pattern, mask);
+}
+
+static int max8997_get_voltage_register(struct regulator_dev *rdev,
+		int *_reg, int *_shift, int *_mask)
+{
+	int rid = rdev_get_id(rdev);
+	int reg, shift = 0, mask = 0x3f;
+
+	switch (rid) {
+	case MAX8997_LDO1 ... MAX8997_LDO21:
+		reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1);
+		break;
+	case MAX8997_BUCK1:
+		reg = MAX8997_REG_BUCK1DVS1;
+		break;
+	case MAX8997_BUCK2:
+		reg = MAX8997_REG_BUCK2DVS1;
+		break;
+	case MAX8997_BUCK3:
+		reg = MAX8997_REG_BUCK3DVS;
+		break;
+	case MAX8997_BUCK4:
+		reg = MAX8997_REG_BUCK4DVS;
+		break;
+	case MAX8997_BUCK5:
+		reg = MAX8997_REG_BUCK5DVS1;
+		break;
+	case MAX8997_BUCK7:
+		reg = MAX8997_REG_BUCK7DVS;
+		break;
+	case MAX8997_ESAFEOUT1 ...  MAX8997_ESAFEOUT2:
+		reg = MAX8997_REG_SAFEOUTCTRL;
+		shift = (rid == MAX8997_ESAFEOUT2) ? 2 : 0;
+		mask = 0x3;
+		break;
+	case MAX8997_CHARGER_CV:
+		reg = MAX8997_REG_MBCCTRL3;
+		shift = 0;
+		mask = 0xf;
+		break;
+	case MAX8997_CHARGER:
+		reg = MAX8997_REG_MBCCTRL4;
+		shift = 0;
+		mask = 0xf;
+		break;
+	case MAX8997_CHARGER_TOPOFF:
+		reg = MAX8997_REG_MBCCTRL5;
+		shift = 0;
+		mask = 0xf;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_reg = reg;
+	*_shift = shift;
+	*_mask = mask;
+
+	return 0;
+}
+
+static int max8997_get_voltage(struct regulator_dev *rdev)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8997->iodev->i2c;
+	int reg, shift, mask, ret;
+	int rid = rdev_get_id(rdev);
+	u8 val;
+
+	ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	if ((rid == MAX8997_BUCK1 && max8997->buck1_gpiodvs) ||
+			(rid == MAX8997_BUCK2 && max8997->buck2_gpiodvs) ||
+			(rid == MAX8997_BUCK5 && max8997->buck5_gpiodvs))
+		reg += max8997->buck125_gpioindex;
+
+	ret = max8997_read_reg(i2c, reg, &val);
+	if (ret)
+		return ret;
+
+	val >>= shift;
+	val &= mask;
+
+	if (rdev->desc && rdev->desc->ops && rdev->desc->ops->list_voltage)
+		return rdev->desc->ops->list_voltage(rdev, val);
+
+	/*
+	 * max8997_list_voltage returns value for any rdev with voltage_map,
+	 * which works for "CHARGER" and "CHARGER TOPOFF" that do not have
+	 * list_voltage ops (they are current regulators).
+	 */
+	return max8997_list_voltage(rdev, val);
+}
+
+static inline int max8997_get_voltage_proper_val(
+		const struct voltage_map_desc *desc,
+		int min_vol, int max_vol)
+{
+	int i = 0;
+
+	if (desc == NULL)
+		return -EINVAL;
+
+	if (max_vol < desc->min || min_vol > desc->max)
+		return -EINVAL;
+
+	while (desc->min + desc->step * i < min_vol &&
+			desc->min + desc->step * i < desc->max)
+		i++;
+
+	if (desc->min + desc->step * i > max_vol)
+		return -EINVAL;
+
+	if (i >= (1 << desc->n_bits))
+		return -EINVAL;
+
+	return i;
+}
+
+static int max8997_set_voltage_charger_cv(struct regulator_dev *rdev,
+		int min_uV, int max_uV, unsigned *selector)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8997->iodev->i2c;
+	int rid = rdev_get_id(rdev);
+	int lb, ub;
+	int reg, shift = 0, mask, ret = 0;
+	u8 val = 0x0;
+
+	if (rid != MAX8997_CHARGER_CV)
+		return -EINVAL;
+
+	ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	if (max_uV < 4000000 || min_uV > 4350000)
+		return -EINVAL;
+
+	if (min_uV <= 4000000) {
+		if (max_uV >= 4000000)
+			return -EINVAL;
+		else
+			val = 0x1;
+	} else if (min_uV <= 4200000 && max_uV >= 4200000)
+		val = 0x0;
+	else {
+		lb = (min_uV - 4000001) / 20000 + 2;
+		ub = (max_uV - 4000000) / 20000 + 1;
+
+		if (lb > ub)
+			return -EINVAL;
+
+		if (lb < 0xf)
+			val = lb;
+		else {
+			if (ub >= 0xf)
+				val = 0xf;
+			else
+				return -EINVAL;
+		}
+	}
+
+	*selector = val;
+
+	ret = max8997_update_reg(i2c, reg, val << shift, mask);
+
+	return ret;
+}
+
+/*
+ * For LDO1 ~ LDO21, BUCK1~5, BUCK7, CHARGER, CHARGER_TOPOFF
+ * BUCK1, 2, and 5 are available if they are not controlled by gpio
+ */
+static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
+		int min_uV, int max_uV, unsigned *selector)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8997->iodev->i2c;
+	const struct voltage_map_desc *desc;
+	int rid = rdev_get_id(rdev);
+	int reg, shift = 0, mask, ret;
+	int i;
+	u8 org;
+
+	switch (rid) {
+	case MAX8997_LDO1 ... MAX8997_LDO21:
+		break;
+	case MAX8997_BUCK1 ... MAX8997_BUCK5:
+		break;
+	case MAX8997_BUCK6:
+		return -EINVAL;
+	case MAX8997_BUCK7:
+		break;
+	case MAX8997_CHARGER:
+		break;
+	case MAX8997_CHARGER_TOPOFF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	desc = reg_voltage_map[rid];
+
+	i = max8997_get_voltage_proper_val(desc, min_uV, max_uV);
+	if (i < 0)
+		return i;
+
+	ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	max8997_read_reg(i2c, reg, &org);
+	org = (org & mask) >> shift;
+
+	ret = max8997_update_reg(i2c, reg, i << shift, mask << shift);
+	*selector = i;
+
+	if (rid == MAX8997_BUCK1 || rid == MAX8997_BUCK2 ||
+			rid == MAX8997_BUCK4 || rid == MAX8997_BUCK5) {
+		/* If the voltage is increasing */
+		if (org < i)
+			udelay(DIV_ROUND_UP(desc->step * (i - org),
+						max8997->ramp_delay * 1000));
+	}
+
+	return ret;
+}
+
+/*
+ * Assess the damage on the voltage setting of BUCK1,2,5 by the change.
+ *
+ * When GPIO-DVS mode is used for multiple bucks, changing the voltage value
+ * of one of the bucks may affect that of another buck, which is the side
+ * effect of the change (set_voltage). This function examines the GPIO-DVS
+ * configurations and checks whether such side-effect exists.
+ */
+static int max8997_assess_side_effect(struct regulator_dev *rdev,
+		u8 new_val, int *best)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	int rid = rdev_get_id(rdev);
+	u8 *buckx_val[3];
+	bool buckx_gpiodvs[3];
+	int side_effect[8];
+	int min_side_effect = INT_MAX;
+	int i;
+
+	*best = -1;
+
+	switch (rid) {
+	case MAX8997_BUCK1:
+		rid = 0;
+		break;
+	case MAX8997_BUCK2:
+		rid = 1;
+		break;
+	case MAX8997_BUCK5:
+		rid = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	buckx_val[0] = max8997->buck1_vol;
+	buckx_val[1] = max8997->buck2_vol;
+	buckx_val[2] = max8997->buck5_vol;
+	buckx_gpiodvs[0] = max8997->buck1_gpiodvs;
+	buckx_gpiodvs[1] = max8997->buck2_gpiodvs;
+	buckx_gpiodvs[2] = max8997->buck5_gpiodvs;
+
+	for (i = 0; i < 8; i++) {
+		int others;
+
+		if (new_val != (buckx_val[rid])[i]) {
+			side_effect[i] = -1;
+			continue;
+		}
+
+		side_effect[i] = 0;
+		for (others = 0; others < 3; others++) {
+			int diff;
+
+			if (others == rid)
+				continue;
+			if (buckx_gpiodvs[others] == false)
+				continue; /* Not affected */
+			diff = (buckx_val[others])[i] -
+				(buckx_val[others])[max8997->buck125_gpioindex];
+			if (diff > 0)
+				side_effect[i] += diff;
+			else if (diff < 0)
+				side_effect[i] -= diff;
+		}
+		if (side_effect[i] == 0) {
+			*best = i;
+			return 0; /* NO SIDE EFFECT! Use This! */
+		}
+		if (side_effect[i] < min_side_effect) {
+			min_side_effect = side_effect[i];
+			*best = i;
+		}
+	}
+
+	if (*best == -1)
+		return -EINVAL;
+
+	return side_effect[*best];
+}
+
+/*
+ * For Buck 1 ~ 5 and 7. If it is not controlled by GPIO, this calls
+ * max8997_set_voltage_ldobuck to do the job.
+ */
+static int max8997_set_voltage_buck(struct regulator_dev *rdev,
+		int min_uV, int max_uV, unsigned *selector)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	int rid = rdev_get_id(rdev);
+	const struct voltage_map_desc *desc;
+	int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg;
+	bool gpio_dvs_mode = false;
+
+	if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7)
+		return -EINVAL;
+
+	switch (rid) {
+	case MAX8997_BUCK1:
+		if (max8997->buck1_gpiodvs)
+			gpio_dvs_mode = true;
+		break;
+	case MAX8997_BUCK2:
+		if (max8997->buck2_gpiodvs)
+			gpio_dvs_mode = true;
+		break;
+	case MAX8997_BUCK5:
+		if (max8997->buck5_gpiodvs)
+			gpio_dvs_mode = true;
+		break;
+	}
+
+	if (!gpio_dvs_mode)
+		return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV,
+						selector);
+
+	desc = reg_voltage_map[rid];
+	new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV);
+	if (new_val < 0)
+		return new_val;
+
+	tmp_dmg = INT_MAX;
+	tmp_idx = -1;
+	tmp_val = -1;
+	do {
+		damage = max8997_assess_side_effect(rdev, new_val, &new_idx);
+		if (damage == 0)
+			goto out;
+
+		if (tmp_dmg > damage) {
+			tmp_idx = new_idx;
+			tmp_val = new_val;
+			tmp_dmg = damage;
+		}
+
+		new_val++;
+	} while (desc->min + desc->step * new_val <= desc->max);
+
+	new_idx = tmp_idx;
+	new_val = tmp_val;
+
+	if (max8997->ignore_gpiodvs_side_effect == false)
+		return -EINVAL;
+
+	dev_warn(&rdev->dev, "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:"
+			" %d -> %d\n", max8997->buck125_gpioindex, tmp_idx);
+
+out:
+	if (new_idx < 0 || new_val < 0)
+		return -EINVAL;
+
+	max8997->buck125_gpioindex = new_idx;
+	max8997_set_gpio(max8997);
+	*selector = new_val;
+
+	return 0;
+}
+
+static const int safeoutvolt[] = {
+	3300000,
+	4850000,
+	4900000,
+	4950000,
+};
+
+/* For SAFEOUT1 and SAFEOUT2 */
+static int max8997_set_voltage_safeout(struct regulator_dev *rdev,
+		int min_uV, int max_uV, unsigned *selector)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8997->iodev->i2c;
+	int rid = rdev_get_id(rdev);
+	int reg, shift = 0, mask, ret;
+	int i = 0;
+	u8 val;
+
+	if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(safeoutvolt); i++) {
+		if (min_uV <= safeoutvolt[i] &&
+				max_uV >= safeoutvolt[i])
+			break;
+	}
+
+	if (i >= ARRAY_SIZE(safeoutvolt))
+		return -EINVAL;
+
+	if (i == 0)
+		val = 0x3;
+	else
+		val = i - 1;
+
+	ret = max8997_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	ret = max8997_update_reg(i2c, reg, val << shift, mask << shift);
+	*selector = val;
+
+	return ret;
+}
+
+static int max8997_reg_enable_suspend(struct regulator_dev *rdev)
+{
+	return 0;
+}
+
+static int max8997_reg_disable_suspend(struct regulator_dev *rdev)
+{
+	struct max8997_data *max8997 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8997->iodev->i2c;
+	int ret, reg, mask, pattern;
+	int rid = rdev_get_id(rdev);
+
+	ret = max8997_get_enable_register(rdev, &reg, &mask, &pattern);
+	if (ret)
+		return ret;
+
+	max8997_read_reg(i2c, reg, &max8997->saved_states[rid]);
+
+	if (rid == MAX8997_LDO1 ||
+			rid == MAX8997_LDO10 ||
+			rid == MAX8997_LDO21) {
+		dev_dbg(&rdev->dev, "Conditional Power-Off for %s\n",
+				rdev->desc->name);
+		return max8997_update_reg(i2c, reg, 0x40, mask);
+	}
+
+	dev_dbg(&rdev->dev, "Full Power-Off for %s (%xh -> %xh)\n",
+			rdev->desc->name, max8997->saved_states[rid] & mask,
+			(~pattern) & mask);
+	return max8997_update_reg(i2c, reg, ~pattern, mask);
+}
+
+static struct regulator_ops max8997_ldo_ops = {
+	.list_voltage		= max8997_list_voltage,
+	.is_enabled		= max8997_reg_is_enabled,
+	.enable			= max8997_reg_enable,
+	.disable		= max8997_reg_disable,
+	.get_voltage		= max8997_get_voltage,
+	.set_voltage		= max8997_set_voltage_ldobuck,
+	.set_suspend_enable	= max8997_reg_enable_suspend,
+	.set_suspend_disable	= max8997_reg_disable_suspend,
+};
+
+static struct regulator_ops max8997_buck_ops = {
+	.list_voltage		= max8997_list_voltage,
+	.is_enabled		= max8997_reg_is_enabled,
+	.enable			= max8997_reg_enable,
+	.disable		= max8997_reg_disable,
+	.get_voltage		= max8997_get_voltage,
+	.set_voltage		= max8997_set_voltage_buck,
+	.set_suspend_enable	= max8997_reg_enable_suspend,
+	.set_suspend_disable	= max8997_reg_disable_suspend,
+};
+
+static struct regulator_ops max8997_fixedvolt_ops = {
+	.list_voltage		= max8997_list_voltage,
+	.is_enabled		= max8997_reg_is_enabled,
+	.enable			= max8997_reg_enable,
+	.disable		= max8997_reg_disable,
+	.set_suspend_enable	= max8997_reg_enable_suspend,
+	.set_suspend_disable	= max8997_reg_disable_suspend,
+};
+
+static struct regulator_ops max8997_safeout_ops = {
+	.list_voltage		= max8997_list_voltage_safeout,
+	.is_enabled		= max8997_reg_is_enabled,
+	.enable			= max8997_reg_enable,
+	.disable		= max8997_reg_disable,
+	.get_voltage		= max8997_get_voltage,
+	.set_voltage		= max8997_set_voltage_safeout,
+	.set_suspend_enable	= max8997_reg_enable_suspend,
+	.set_suspend_disable	= max8997_reg_disable_suspend,
+};
+
+static struct regulator_ops max8997_fixedstate_ops = {
+	.list_voltage		= max8997_list_voltage_charger_cv,
+	.get_voltage		= max8997_get_voltage,
+	.set_voltage		= max8997_set_voltage_charger_cv,
+};
+
+static int max8997_set_voltage_ldobuck_wrap(struct regulator_dev *rdev,
+		int min_uV, int max_uV)
+{
+	unsigned dummy;
+
+	return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV, &dummy);
+}
+
+
+static struct regulator_ops max8997_charger_ops = {
+	.is_enabled		= max8997_reg_is_enabled,
+	.enable			= max8997_reg_enable,
+	.disable		= max8997_reg_disable,
+	.get_current_limit	= max8997_get_voltage,
+	.set_current_limit	= max8997_set_voltage_ldobuck_wrap,
+};
+
+static struct regulator_ops max8997_charger_fixedstate_ops = {
+	.is_enabled		= max8997_reg_is_enabled,
+	.get_current_limit	= max8997_get_voltage,
+	.set_current_limit	= max8997_set_voltage_ldobuck_wrap,
+};
+
+#define regulator_desc_ldo(num)		{	\
+	.name		= "LDO"#num,		\
+	.id		= MAX8997_LDO##num,	\
+	.ops		= &max8997_ldo_ops,	\
+	.type		= REGULATOR_VOLTAGE,	\
+	.owner		= THIS_MODULE,		\
+}
+#define regulator_desc_buck(num)		{	\
+	.name		= "BUCK"#num,		\
+	.id		= MAX8997_BUCK##num,	\
+	.ops		= &max8997_buck_ops,	\
+	.type		= REGULATOR_VOLTAGE,	\
+	.owner		= THIS_MODULE,		\
+}
+
+static struct regulator_desc regulators[] = {
+	regulator_desc_ldo(1),
+	regulator_desc_ldo(2),
+	regulator_desc_ldo(3),
+	regulator_desc_ldo(4),
+	regulator_desc_ldo(5),
+	regulator_desc_ldo(6),
+	regulator_desc_ldo(7),
+	regulator_desc_ldo(8),
+	regulator_desc_ldo(9),
+	regulator_desc_ldo(10),
+	regulator_desc_ldo(11),
+	regulator_desc_ldo(12),
+	regulator_desc_ldo(13),
+	regulator_desc_ldo(14),
+	regulator_desc_ldo(15),
+	regulator_desc_ldo(16),
+	regulator_desc_ldo(17),
+	regulator_desc_ldo(18),
+	regulator_desc_ldo(21),
+	regulator_desc_buck(1),
+	regulator_desc_buck(2),
+	regulator_desc_buck(3),
+	regulator_desc_buck(4),
+	regulator_desc_buck(5),
+	{
+		.name	= "BUCK6",
+		.id	= MAX8997_BUCK6,
+		.ops	= &max8997_fixedvolt_ops,
+		.type	= REGULATOR_VOLTAGE,
+		.owner	= THIS_MODULE,
+	},
+	regulator_desc_buck(7),
+	{
+		.name	= "EN32KHz_AP",
+		.id	= MAX8997_EN32KHZ_AP,
+		.ops	= &max8997_fixedvolt_ops,
+		.type	= REGULATOR_VOLTAGE,
+		.owner	= THIS_MODULE,
+	}, {
+		.name	= "EN32KHz_CP",
+		.id	= MAX8997_EN32KHZ_CP,
+		.ops	= &max8997_fixedvolt_ops,
+		.type	= REGULATOR_VOLTAGE,
+		.owner	= THIS_MODULE,
+	}, {
+		.name	= "ENVICHG",
+		.id	= MAX8997_ENVICHG,
+		.ops	= &max8997_fixedvolt_ops,
+		.type	= REGULATOR_VOLTAGE,
+		.owner	= THIS_MODULE,
+	}, {
+		.name	= "ESAFEOUT1",
+		.id	= MAX8997_ESAFEOUT1,
+		.ops	= &max8997_safeout_ops,
+		.type	= REGULATOR_VOLTAGE,
+		.owner	 = THIS_MODULE,
+	}, {
+		.name	= "ESAFEOUT2",
+		.id	= MAX8997_ESAFEOUT2,
+		.ops	= &max8997_safeout_ops,
+		.type	= REGULATOR_VOLTAGE,
+		.owner	 = THIS_MODULE,
+	}, {
+		.name	= "CHARGER_CV",
+		.id	= MAX8997_CHARGER_CV,
+		.ops	= &max8997_fixedstate_ops,
+		.type	= REGULATOR_VOLTAGE,
+		.owner	 = THIS_MODULE,
+	}, {
+		.name	= "CHARGER",
+		.id	= MAX8997_CHARGER,
+		.ops	= &max8997_charger_ops,
+		.type	= REGULATOR_CURRENT,
+		.owner	 = THIS_MODULE,
+	}, {
+		.name	= "CHARGER_TOPOFF",
+		.id	= MAX8997_CHARGER_TOPOFF,
+		.ops	= &max8997_charger_fixedstate_ops,
+		.type	= REGULATOR_CURRENT,
+		.owner	 = THIS_MODULE,
+	},
+};
+
+static __devinit int max8997_pmic_probe(struct platform_device *pdev)
+{
+	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct regulator_dev **rdev;
+	struct max8997_data *max8997;
+	struct i2c_client *i2c;
+	int i, ret, size;
+	u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;
+
+	if (!pdata) {
+		dev_err(pdev->dev.parent, "No platform init data supplied.\n");
+		return -ENODEV;
+	}
+
+	max8997 = kzalloc(sizeof(struct max8997_data), GFP_KERNEL);
+	if (!max8997)
+		return -ENOMEM;
+
+	size = sizeof(struct regulator_dev *) * pdata->num_regulators;
+	max8997->rdev = kzalloc(size, GFP_KERNEL);
+	if (!max8997->rdev) {
+		kfree(max8997);
+		return -ENOMEM;
+	}
+
+	rdev = max8997->rdev;
+	max8997->dev = &pdev->dev;
+	max8997->iodev = iodev;
+	max8997->num_regulators = pdata->num_regulators;
+	platform_set_drvdata(pdev, max8997);
+	i2c = max8997->iodev->i2c;
+
+	max8997->buck125_gpioindex = pdata->buck125_default_idx;
+	max8997->buck1_gpiodvs = pdata->buck1_gpiodvs;
+	max8997->buck2_gpiodvs = pdata->buck2_gpiodvs;
+	max8997->buck5_gpiodvs = pdata->buck5_gpiodvs;
+	memcpy(max8997->buck125_gpios, pdata->buck125_gpios, sizeof(int) * 3);
+	max8997->ignore_gpiodvs_side_effect = pdata->ignore_gpiodvs_side_effect;
+
+	for (i = 0; i < 8; i++) {
+		max8997->buck1_vol[i] = ret =
+			max8997_get_voltage_proper_val(
+					&buck1245_voltage_map_desc,
+					pdata->buck1_voltage[i],
+					pdata->buck1_voltage[i] +
+					buck1245_voltage_map_desc.step);
+		if (ret < 0)
+			goto err_alloc;
+
+		max8997->buck2_vol[i] = ret =
+			max8997_get_voltage_proper_val(
+					&buck1245_voltage_map_desc,
+					pdata->buck2_voltage[i],
+					pdata->buck2_voltage[i] +
+					buck1245_voltage_map_desc.step);
+		if (ret < 0)
+			goto err_alloc;
+
+		max8997->buck5_vol[i] = ret =
+			max8997_get_voltage_proper_val(
+					&buck1245_voltage_map_desc,
+					pdata->buck5_voltage[i],
+					pdata->buck5_voltage[i] +
+					buck1245_voltage_map_desc.step);
+		if (ret < 0)
+			goto err_alloc;
+
+		if (max_buck1 < max8997->buck1_vol[i])
+			max_buck1 = max8997->buck1_vol[i];
+		if (max_buck2 < max8997->buck2_vol[i])
+			max_buck2 = max8997->buck2_vol[i];
+		if (max_buck5 < max8997->buck5_vol[i])
+			max_buck5 = max8997->buck5_vol[i];
+	}
+
+	/* For the safety, set max voltage before setting up */
+	for (i = 0; i < 8; i++) {
+		max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
+				max_buck1, 0x3f);
+		max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
+				max_buck2, 0x3f);
+		max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
+				max_buck5, 0x3f);
+	}
+
+	/*
+	 * If buck 1, 2, and 5 do not care DVS GPIO settings, ignore them.
+	 * If at least one of them cares, set gpios.
+	 */
+	if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
+			pdata->buck5_gpiodvs) {
+		bool gpio1set = false, gpio2set = false;
+
+		if (!gpio_is_valid(pdata->buck125_gpios[0]) ||
+				!gpio_is_valid(pdata->buck125_gpios[1]) ||
+				!gpio_is_valid(pdata->buck125_gpios[2])) {
+			dev_err(&pdev->dev, "GPIO NOT VALID\n");
+			ret = -EINVAL;
+			goto err_alloc;
+		}
+
+		ret = gpio_request(pdata->buck125_gpios[0],
+				"MAX8997 SET1");
+		if (ret == -EBUSY)
+			dev_warn(&pdev->dev, "Duplicated gpio request"
+					" on SET1\n");
+		else if (ret)
+			goto err_alloc;
+		else
+			gpio1set = true;
+
+		ret = gpio_request(pdata->buck125_gpios[1],
+				"MAX8997 SET2");
+		if (ret == -EBUSY)
+			dev_warn(&pdev->dev, "Duplicated gpio request"
+					" on SET2\n");
+		else if (ret) {
+			if (gpio1set)
+				gpio_free(pdata->buck125_gpios[0]);
+			goto err_alloc;
+		} else
+			gpio2set = true;
+
+		ret = gpio_request(pdata->buck125_gpios[2],
+				"MAX8997 SET3");
+		if (ret == -EBUSY)
+			dev_warn(&pdev->dev, "Duplicated gpio request"
+					" on SET3\n");
+		else if (ret) {
+			if (gpio1set)
+				gpio_free(pdata->buck125_gpios[0]);
+			if (gpio2set)
+				gpio_free(pdata->buck125_gpios[1]);
+			goto err_alloc;
+		}
+
+		gpio_direction_output(pdata->buck125_gpios[0],
+				(max8997->buck125_gpioindex >> 2)
+				& 0x1); /* SET1 */
+		gpio_direction_output(pdata->buck125_gpios[1],
+				(max8997->buck125_gpioindex >> 1)
+				& 0x1); /* SET2 */
+		gpio_direction_output(pdata->buck125_gpios[2],
+				(max8997->buck125_gpioindex >> 0)
+				& 0x1); /* SET3 */
+		ret = 0;
+	}
+
+	/* DVS-GPIO disabled */
+	max8997_update_reg(i2c, MAX8997_REG_BUCK1CTRL, (pdata->buck1_gpiodvs) ?
+			(1 << 1) : (0 << 1), 1 << 1);
+	max8997_update_reg(i2c, MAX8997_REG_BUCK2CTRL, (pdata->buck2_gpiodvs) ?
+			(1 << 1) : (0 << 1), 1 << 1);
+	max8997_update_reg(i2c, MAX8997_REG_BUCK5CTRL, (pdata->buck5_gpiodvs) ?
+			(1 << 1) : (0 << 1), 1 << 1);
+
+	/* Initialize all the DVS related BUCK registers */
+	for (i = 0; i < 8; i++) {
+		max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
+				max8997->buck1_vol[i],
+				0x3f);
+		max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
+				max8997->buck2_vol[i],
+				0x3f);
+		max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
+				max8997->buck5_vol[i],
+				0x3f);
+	}
+
+	/* Misc Settings */
+	max8997->ramp_delay = 10; /* set 10mV/us, which is the default */
+	max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9);
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		const struct voltage_map_desc *desc;
+		int id = pdata->regulators[i].id;
+
+		desc = reg_voltage_map[id];
+		if (desc)
+			regulators[id].n_voltages =
+				(desc->max - desc->min) / desc->step + 1;
+		else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2)
+			regulators[id].n_voltages = 4;
+		else if (id == MAX8997_CHARGER_CV)
+			regulators[id].n_voltages = 16;
+
+		rdev[i] = regulator_register(&regulators[id], max8997->dev,
+				pdata->regulators[i].initdata, max8997, NULL);
+		if (IS_ERR(rdev[i])) {
+			ret = PTR_ERR(rdev[i]);
+			dev_err(max8997->dev, "regulator init failed for %d\n",
+					id);
+			rdev[i] = NULL;
+			goto err;
+		}
+	}
+
+	return 0;
+err:
+	for (i = 0; i < max8997->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+err_alloc:
+	kfree(max8997->rdev);
+	kfree(max8997);
+
+	return ret;
+}
+
+static int __devexit max8997_pmic_remove(struct platform_device *pdev)
+{
+	struct max8997_data *max8997 = platform_get_drvdata(pdev);
+	struct regulator_dev **rdev = max8997->rdev;
+	int i;
+
+	for (i = 0; i < max8997->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+	kfree(max8997->rdev);
+	kfree(max8997);
+
+	return 0;
+}
+
+static const struct platform_device_id max8997_pmic_id[] = {
+	{ "max8997-pmic", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, max8997_pmic_id);
+
+static struct platform_driver max8997_pmic_driver = {
+	.driver = {
+		.name = "max8997-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = max8997_pmic_probe,
+	.remove = __devexit_p(max8997_pmic_remove),
+	.id_table = max8997_pmic_id,
+};
+
+static int __init max8997_pmic_init(void)
+{
+	return platform_driver_register(&max8997_pmic_driver);
+}
+subsys_initcall(max8997_pmic_init);
+
+static void __exit max8997_pmic_cleanup(void)
+{
+	platform_driver_unregister(&max8997_pmic_driver);
+}
+module_exit(max8997_pmic_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 8997/8966 Regulator Driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/max8998.c b/ap/os/linux/linux-3.4.x/drivers/regulator/max8998.c
new file mode 100644
index 0000000..1300383
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/max8998.c
@@ -0,0 +1,914 @@
+/*
+ * max8998.c - Voltage regulator driver for the Maxim 8998
+ *
+ *  Copyright (C) 2009-2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *  Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/max8998.h>
+#include <linux/mfd/max8998-private.h>
+
+struct max8998_data {
+	struct device		*dev;
+	struct max8998_dev	*iodev;
+	int			num_regulators;
+	struct regulator_dev	**rdev;
+	u8                      buck1_vol[4]; /* voltages for selection */
+	u8                      buck2_vol[2];
+	unsigned int		buck1_idx; /* index to last changed voltage */
+					   /* value in a set */
+	unsigned int		buck2_idx;
+};
+
+struct voltage_map_desc {
+	int min;
+	int max;
+	int step;
+};
+
+/* Voltage maps */
+static const struct voltage_map_desc ldo23_voltage_map_desc = {
+	.min = 800,	.step = 50,	.max = 1300,
+};
+static const struct voltage_map_desc ldo456711_voltage_map_desc = {
+	.min = 1600,	.step = 100,	.max = 3600,
+};
+static const struct voltage_map_desc ldo8_voltage_map_desc = {
+	.min = 3000,	.step = 100,	.max = 3600,
+};
+static const struct voltage_map_desc ldo9_voltage_map_desc = {
+	.min = 2800,	.step = 100,	.max = 3100,
+};
+static const struct voltage_map_desc ldo10_voltage_map_desc = {
+	.min = 950,	.step = 50,	.max = 1300,
+};
+static const struct voltage_map_desc ldo1213_voltage_map_desc = {
+	.min = 800,	.step = 100,	.max = 3300,
+};
+static const struct voltage_map_desc ldo1415_voltage_map_desc = {
+	.min = 1200,	.step = 100,	.max = 3300,
+};
+static const struct voltage_map_desc ldo1617_voltage_map_desc = {
+	.min = 1600,	.step = 100,	.max = 3600,
+};
+static const struct voltage_map_desc buck12_voltage_map_desc = {
+	.min = 750,	.step = 25,	.max = 1525,
+};
+static const struct voltage_map_desc buck3_voltage_map_desc = {
+	.min = 1600,	.step = 100,	.max = 3600,
+};
+static const struct voltage_map_desc buck4_voltage_map_desc = {
+	.min = 800,	.step = 100,	.max = 2300,
+};
+
+static const struct voltage_map_desc *ldo_voltage_map[] = {
+	NULL,
+	NULL,
+	&ldo23_voltage_map_desc,	/* LDO2 */
+	&ldo23_voltage_map_desc,	/* LDO3 */
+	&ldo456711_voltage_map_desc,	/* LDO4 */
+	&ldo456711_voltage_map_desc,	/* LDO5 */
+	&ldo456711_voltage_map_desc,	/* LDO6 */
+	&ldo456711_voltage_map_desc,	/* LDO7 */
+	&ldo8_voltage_map_desc,		/* LDO8 */
+	&ldo9_voltage_map_desc,		/* LDO9 */
+	&ldo10_voltage_map_desc,	/* LDO10 */
+	&ldo456711_voltage_map_desc,	/* LDO11 */
+	&ldo1213_voltage_map_desc,	/* LDO12 */
+	&ldo1213_voltage_map_desc,	/* LDO13 */
+	&ldo1415_voltage_map_desc,	/* LDO14 */
+	&ldo1415_voltage_map_desc,	/* LDO15 */
+	&ldo1617_voltage_map_desc,	/* LDO16 */
+	&ldo1617_voltage_map_desc,	/* LDO17 */
+	&buck12_voltage_map_desc,	/* BUCK1 */
+	&buck12_voltage_map_desc,	/* BUCK2 */
+	&buck3_voltage_map_desc,	/* BUCK3 */
+	&buck4_voltage_map_desc,	/* BUCK4 */
+};
+
+static int max8998_list_voltage(struct regulator_dev *rdev,
+				unsigned int selector)
+{
+	const struct voltage_map_desc *desc;
+	int ldo = rdev_get_id(rdev);
+	int val;
+
+	if (ldo >= ARRAY_SIZE(ldo_voltage_map))
+		return -EINVAL;
+
+	desc = ldo_voltage_map[ldo];
+	if (desc == NULL)
+		return -EINVAL;
+
+	val = desc->min + desc->step * selector;
+	if (val > desc->max)
+		return -EINVAL;
+
+	return val * 1000;
+}
+
+static int max8998_get_enable_register(struct regulator_dev *rdev,
+					int *reg, int *shift)
+{
+	int ldo = rdev_get_id(rdev);
+
+	switch (ldo) {
+	case MAX8998_LDO2 ... MAX8998_LDO5:
+		*reg = MAX8998_REG_ONOFF1;
+		*shift = 3 - (ldo - MAX8998_LDO2);
+		break;
+	case MAX8998_LDO6 ... MAX8998_LDO13:
+		*reg = MAX8998_REG_ONOFF2;
+		*shift = 7 - (ldo - MAX8998_LDO6);
+		break;
+	case MAX8998_LDO14 ... MAX8998_LDO17:
+		*reg = MAX8998_REG_ONOFF3;
+		*shift = 7 - (ldo - MAX8998_LDO14);
+		break;
+	case MAX8998_BUCK1 ... MAX8998_BUCK4:
+		*reg = MAX8998_REG_ONOFF1;
+		*shift = 7 - (ldo - MAX8998_BUCK1);
+		break;
+	case MAX8998_EN32KHZ_AP ... MAX8998_ENVICHG:
+		*reg = MAX8998_REG_ONOFF4;
+		*shift = 7 - (ldo - MAX8998_EN32KHZ_AP);
+		break;
+	case MAX8998_ESAFEOUT1 ... MAX8998_ESAFEOUT2:
+		*reg = MAX8998_REG_CHGR2;
+		*shift = 7 - (ldo - MAX8998_ESAFEOUT1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int max8998_ldo_is_enabled(struct regulator_dev *rdev)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
+	int ret, reg, shift = 8;
+	u8 val;
+
+	ret = max8998_get_enable_register(rdev, &reg, &shift);
+	if (ret)
+		return ret;
+
+	ret = max8998_read_reg(i2c, reg, &val);
+	if (ret)
+		return ret;
+
+	return val & (1 << shift);
+}
+
+static int max8998_ldo_enable(struct regulator_dev *rdev)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
+	int reg, shift = 8, ret;
+
+	ret = max8998_get_enable_register(rdev, &reg, &shift);
+	if (ret)
+		return ret;
+
+	return max8998_update_reg(i2c, reg, 1<<shift, 1<<shift);
+}
+
+static int max8998_ldo_disable(struct regulator_dev *rdev)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
+	int reg, shift = 8, ret;
+
+	ret = max8998_get_enable_register(rdev, &reg, &shift);
+	if (ret)
+		return ret;
+
+	return max8998_update_reg(i2c, reg, 0, 1<<shift);
+}
+
+static int max8998_get_voltage_register(struct regulator_dev *rdev,
+				int *_reg, int *_shift, int *_mask)
+{
+	int ldo = rdev_get_id(rdev);
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	int reg, shift = 0, mask = 0xff;
+
+	switch (ldo) {
+	case MAX8998_LDO2 ... MAX8998_LDO3:
+		reg = MAX8998_REG_LDO2_LDO3;
+		mask = 0xf;
+		if (ldo == MAX8998_LDO2)
+			shift = 4;
+		else
+			shift = 0;
+		break;
+	case MAX8998_LDO4 ... MAX8998_LDO7:
+		reg = MAX8998_REG_LDO4 + (ldo - MAX8998_LDO4);
+		break;
+	case MAX8998_LDO8 ... MAX8998_LDO9:
+		reg = MAX8998_REG_LDO8_LDO9;
+		mask = 0xf;
+		if (ldo == MAX8998_LDO8)
+			shift = 4;
+		else
+			shift = 0;
+		break;
+	case MAX8998_LDO10 ... MAX8998_LDO11:
+		reg = MAX8998_REG_LDO10_LDO11;
+		if (ldo == MAX8998_LDO10) {
+			shift = 5;
+			mask = 0x7;
+		} else {
+			shift = 0;
+			mask = 0x1f;
+		}
+		break;
+	case MAX8998_LDO12 ... MAX8998_LDO17:
+		reg = MAX8998_REG_LDO12 + (ldo - MAX8998_LDO12);
+		break;
+	case MAX8998_BUCK1:
+		reg = MAX8998_REG_BUCK1_VOLTAGE1 + max8998->buck1_idx;
+		break;
+	case MAX8998_BUCK2:
+		reg = MAX8998_REG_BUCK2_VOLTAGE1 + max8998->buck2_idx;
+		break;
+	case MAX8998_BUCK3:
+		reg = MAX8998_REG_BUCK3;
+		break;
+	case MAX8998_BUCK4:
+		reg = MAX8998_REG_BUCK4;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_reg = reg;
+	*_shift = shift;
+	*_mask = mask;
+
+	return 0;
+}
+
+static int max8998_get_voltage(struct regulator_dev *rdev)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
+	int reg, shift = 0, mask, ret;
+	u8 val;
+
+	ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	ret = max8998_read_reg(i2c, reg, &val);
+	if (ret)
+		return ret;
+
+	val >>= shift;
+	val &= mask;
+
+	return max8998_list_voltage(rdev, val);
+}
+
+static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
+				   int min_uV, int max_uV, unsigned *selector)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
+	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+	const struct voltage_map_desc *desc;
+	int ldo = rdev_get_id(rdev);
+	int reg, shift = 0, mask, ret;
+	int i = 0;
+
+	if (ldo >= ARRAY_SIZE(ldo_voltage_map))
+		return -EINVAL;
+
+	desc = ldo_voltage_map[ldo];
+	if (desc == NULL)
+		return -EINVAL;
+
+	if (max_vol < desc->min || min_vol > desc->max)
+		return -EINVAL;
+
+	while (desc->min + desc->step*i < min_vol &&
+	       desc->min + desc->step*i < desc->max)
+		i++;
+
+	if (desc->min + desc->step*i > max_vol)
+		return -EINVAL;
+
+	*selector = i;
+
+	ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+
+	return ret;
+}
+
+static inline void buck1_gpio_set(int gpio1, int gpio2, int v)
+{
+	gpio_set_value(gpio1, v & 0x1);
+	gpio_set_value(gpio2, (v >> 1) & 0x1);
+}
+
+static inline void buck2_gpio_set(int gpio, int v)
+{
+	gpio_set_value(gpio, v & 0x1);
+}
+
+static int max8998_set_voltage_buck(struct regulator_dev *rdev,
+				    int min_uV, int max_uV, unsigned *selector)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	struct max8998_platform_data *pdata =
+		dev_get_platdata(max8998->iodev->dev);
+	struct i2c_client *i2c = max8998->iodev->i2c;
+	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+	const struct voltage_map_desc *desc;
+	int buck = rdev_get_id(rdev);
+	int reg, shift = 0, mask, ret;
+	int difference = 0, i = 0, j = 0, previous_vol = 0;
+	u8 val = 0;
+	static u8 buck1_last_val;
+
+	if (buck >= ARRAY_SIZE(ldo_voltage_map))
+		return -EINVAL;
+
+	desc = ldo_voltage_map[buck];
+
+	if (desc == NULL)
+		return -EINVAL;
+
+	if (max_vol < desc->min || min_vol > desc->max)
+		return -EINVAL;
+
+	while (desc->min + desc->step*i < min_vol &&
+	       desc->min + desc->step*i < desc->max)
+		i++;
+
+	if (desc->min + desc->step*i > max_vol)
+		return -EINVAL;
+
+	*selector = i;
+
+	ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	previous_vol = max8998_get_voltage(rdev);
+
+	/* Check if voltage needs to be changed */
+	/* if previous_voltage equal new voltage, return */
+	if (previous_vol == max8998_list_voltage(rdev, i)) {
+		dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
+			previous_vol, max8998_list_voltage(rdev, i));
+		return ret;
+	}
+
+	switch (buck) {
+	case MAX8998_BUCK1:
+		dev_dbg(max8998->dev,
+			"BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n"
+			"buck1_vol3:%d, buck1_vol4:%d\n",
+			i, max8998->buck1_vol[0], max8998->buck1_vol[1],
+			max8998->buck1_vol[2], max8998->buck1_vol[3]);
+
+		if (gpio_is_valid(pdata->buck1_set1) &&
+		    gpio_is_valid(pdata->buck1_set2)) {
+
+			/* check if requested voltage */
+			/* value is already defined */
+			for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) {
+				if (max8998->buck1_vol[j] == i) {
+					max8998->buck1_idx = j;
+					buck1_gpio_set(pdata->buck1_set1,
+						       pdata->buck1_set2, j);
+					goto buck1_exit;
+				}
+			}
+
+			if (pdata->buck_voltage_lock)
+				return -EINVAL;
+
+			/* no predefine regulator found */
+			max8998->buck1_idx = (buck1_last_val % 2) + 2;
+			dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
+				max8998->buck1_idx);
+			max8998->buck1_vol[max8998->buck1_idx] = i;
+			ret = max8998_get_voltage_register(rdev, &reg,
+							   &shift,
+							   &mask);
+			ret = max8998_write_reg(i2c, reg, i);
+			buck1_gpio_set(pdata->buck1_set1,
+				       pdata->buck1_set2, max8998->buck1_idx);
+			buck1_last_val++;
+buck1_exit:
+			dev_dbg(max8998->dev, "%s: SET1:%d, SET2:%d\n",
+				i2c->name, gpio_get_value(pdata->buck1_set1),
+				gpio_get_value(pdata->buck1_set2));
+			break;
+		} else {
+			ret = max8998_write_reg(i2c, reg, i);
+		}
+		break;
+
+	case MAX8998_BUCK2:
+		dev_dbg(max8998->dev,
+			"BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
+			, i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
+		if (gpio_is_valid(pdata->buck2_set3)) {
+
+			/* check if requested voltage */
+			/* value is already defined */
+			for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) {
+				if (max8998->buck2_vol[j] == i) {
+					max8998->buck2_idx = j;
+					buck2_gpio_set(pdata->buck2_set3, j);
+					goto buck2_exit;
+				}
+			}
+
+			if (pdata->buck_voltage_lock)
+				return -EINVAL;
+
+			max8998_get_voltage_register(rdev,
+					&reg, &shift, &mask);
+			ret = max8998_write_reg(i2c, reg, i);
+			max8998->buck2_vol[max8998->buck2_idx] = i;
+			buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx);
+buck2_exit:
+			dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
+				gpio_get_value(pdata->buck2_set3));
+		} else {
+			ret = max8998_write_reg(i2c, reg, i);
+		}
+		break;
+
+	case MAX8998_BUCK3:
+	case MAX8998_BUCK4:
+		ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+		break;
+	}
+
+	/* Voltage stabilization */
+	max8998_read_reg(i2c, MAX8998_REG_ONOFF4, &val);
+
+	/* lp3974 hasn't got ENRAMP bit - ramp is assumed as true */
+	/* MAX8998 has ENRAMP bit implemented, so test it*/
+	if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP))
+		return ret;
+
+	difference = desc->min + desc->step*i - previous_vol/1000;
+	if (difference > 0)
+		udelay(DIV_ROUND_UP(difference, (val & 0x0f) + 1));
+
+	return ret;
+}
+
+static struct regulator_ops max8998_ldo_ops = {
+	.list_voltage		= max8998_list_voltage,
+	.is_enabled		= max8998_ldo_is_enabled,
+	.enable			= max8998_ldo_enable,
+	.disable		= max8998_ldo_disable,
+	.get_voltage		= max8998_get_voltage,
+	.set_voltage		= max8998_set_voltage_ldo,
+	.set_suspend_enable	= max8998_ldo_enable,
+	.set_suspend_disable	= max8998_ldo_disable,
+};
+
+static struct regulator_ops max8998_buck_ops = {
+	.list_voltage		= max8998_list_voltage,
+	.is_enabled		= max8998_ldo_is_enabled,
+	.enable			= max8998_ldo_enable,
+	.disable		= max8998_ldo_disable,
+	.get_voltage		= max8998_get_voltage,
+	.set_voltage		= max8998_set_voltage_buck,
+	.set_suspend_enable	= max8998_ldo_enable,
+	.set_suspend_disable	= max8998_ldo_disable,
+};
+
+static struct regulator_ops max8998_others_ops = {
+	.is_enabled		= max8998_ldo_is_enabled,
+	.enable			= max8998_ldo_enable,
+	.disable		= max8998_ldo_disable,
+	.set_suspend_enable	= max8998_ldo_enable,
+	.set_suspend_disable	= max8998_ldo_disable,
+};
+
+static struct regulator_desc regulators[] = {
+	{
+		.name		= "LDO2",
+		.id		= MAX8998_LDO2,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO3",
+		.id		= MAX8998_LDO3,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO4",
+		.id		= MAX8998_LDO4,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO5",
+		.id		= MAX8998_LDO5,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO6",
+		.id		= MAX8998_LDO6,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO7",
+		.id		= MAX8998_LDO7,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO8",
+		.id		= MAX8998_LDO8,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO9",
+		.id		= MAX8998_LDO9,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO10",
+		.id		= MAX8998_LDO10,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO11",
+		.id		= MAX8998_LDO11,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO12",
+		.id		= MAX8998_LDO12,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO13",
+		.id		= MAX8998_LDO13,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO14",
+		.id		= MAX8998_LDO14,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO15",
+		.id		= MAX8998_LDO15,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO16",
+		.id		= MAX8998_LDO16,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO17",
+		.id		= MAX8998_LDO17,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "BUCK1",
+		.id		= MAX8998_BUCK1,
+		.ops		= &max8998_buck_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "BUCK2",
+		.id		= MAX8998_BUCK2,
+		.ops		= &max8998_buck_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "BUCK3",
+		.id		= MAX8998_BUCK3,
+		.ops		= &max8998_buck_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "BUCK4",
+		.id		= MAX8998_BUCK4,
+		.ops		= &max8998_buck_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "EN32KHz AP",
+		.id		= MAX8998_EN32KHZ_AP,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "EN32KHz CP",
+		.id		= MAX8998_EN32KHZ_CP,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "ENVICHG",
+		.id		= MAX8998_ENVICHG,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "ESAFEOUT1",
+		.id		= MAX8998_ESAFEOUT1,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "ESAFEOUT2",
+		.id		= MAX8998_ESAFEOUT2,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}
+};
+
+static __devinit int max8998_pmic_probe(struct platform_device *pdev)
+{
+	struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct regulator_dev **rdev;
+	struct max8998_data *max8998;
+	struct i2c_client *i2c;
+	int i, ret, size;
+
+	if (!pdata) {
+		dev_err(pdev->dev.parent, "No platform init data supplied\n");
+		return -ENODEV;
+	}
+
+	max8998 = kzalloc(sizeof(struct max8998_data), GFP_KERNEL);
+	if (!max8998)
+		return -ENOMEM;
+
+	size = sizeof(struct regulator_dev *) * pdata->num_regulators;
+	max8998->rdev = kzalloc(size, GFP_KERNEL);
+	if (!max8998->rdev) {
+		kfree(max8998);
+		return -ENOMEM;
+	}
+
+	rdev = max8998->rdev;
+	max8998->dev = &pdev->dev;
+	max8998->iodev = iodev;
+	max8998->num_regulators = pdata->num_regulators;
+	platform_set_drvdata(pdev, max8998);
+	i2c = max8998->iodev->i2c;
+
+	max8998->buck1_idx = pdata->buck1_default_idx;
+	max8998->buck2_idx = pdata->buck2_default_idx;
+
+	/* NOTE: */
+	/* For unused GPIO NOT marked as -1 (thereof equal to 0)  WARN_ON */
+	/* will be displayed */
+
+	/* Check if MAX8998 voltage selection GPIOs are defined */
+	if (gpio_is_valid(pdata->buck1_set1) &&
+	    gpio_is_valid(pdata->buck1_set2)) {
+		/* Check if SET1 is not equal to 0 */
+		if (!pdata->buck1_set1) {
+			printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n");
+			WARN_ON(!pdata->buck1_set1);
+			ret = -EIO;
+			goto err_free_mem;
+		}
+		/* Check if SET2 is not equal to 0 */
+		if (!pdata->buck1_set2) {
+			printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n");
+			WARN_ON(!pdata->buck1_set2);
+			ret = -EIO;
+			goto err_free_mem;
+		}
+
+		gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1");
+		gpio_direction_output(pdata->buck1_set1,
+				      max8998->buck1_idx & 0x1);
+
+
+		gpio_request(pdata->buck1_set2, "MAX8998 BUCK1_SET2");
+		gpio_direction_output(pdata->buck1_set2,
+				      (max8998->buck1_idx >> 1) & 0x1);
+		/* Set predefined value for BUCK1 register 1 */
+		i = 0;
+		while (buck12_voltage_map_desc.min +
+		       buck12_voltage_map_desc.step*i
+		       < (pdata->buck1_voltage1 / 1000))
+			i++;
+		max8998->buck1_vol[0] = i;
+		ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
+		if (ret)
+			goto err_free_mem;
+
+		/* Set predefined value for BUCK1 register 2 */
+		i = 0;
+		while (buck12_voltage_map_desc.min +
+		       buck12_voltage_map_desc.step*i
+		       < (pdata->buck1_voltage2 / 1000))
+			i++;
+
+		max8998->buck1_vol[1] = i;
+		ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
+		if (ret)
+			goto err_free_mem;
+
+		/* Set predefined value for BUCK1 register 3 */
+		i = 0;
+		while (buck12_voltage_map_desc.min +
+		       buck12_voltage_map_desc.step*i
+		       < (pdata->buck1_voltage3 / 1000))
+			i++;
+
+		max8998->buck1_vol[2] = i;
+		ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
+		if (ret)
+			goto err_free_mem;
+
+		/* Set predefined value for BUCK1 register 4 */
+		i = 0;
+		while (buck12_voltage_map_desc.min +
+		       buck12_voltage_map_desc.step*i
+		       < (pdata->buck1_voltage4 / 1000))
+			i++;
+
+		max8998->buck1_vol[3] = i;
+		ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
+		if (ret)
+			goto err_free_mem;
+
+	}
+
+	if (gpio_is_valid(pdata->buck2_set3)) {
+		/* Check if SET3 is not equal to 0 */
+		if (!pdata->buck2_set3) {
+			printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n");
+			WARN_ON(!pdata->buck2_set3);
+			ret = -EIO;
+			goto err_free_mem;
+		}
+		gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3");
+		gpio_direction_output(pdata->buck2_set3,
+				      max8998->buck2_idx & 0x1);
+
+		/* BUCK2 register 1 */
+		i = 0;
+		while (buck12_voltage_map_desc.min +
+		       buck12_voltage_map_desc.step*i
+		       < (pdata->buck2_voltage1 / 1000))
+			i++;
+		max8998->buck2_vol[0] = i;
+		ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
+		if (ret)
+			goto err_free_mem;
+
+		/* BUCK2 register 2 */
+		i = 0;
+		while (buck12_voltage_map_desc.min +
+		       buck12_voltage_map_desc.step*i
+		       < (pdata->buck2_voltage2 / 1000))
+			i++;
+		max8998->buck2_vol[1] = i;
+		ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
+		if (ret)
+			goto err_free_mem;
+	}
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		const struct voltage_map_desc *desc;
+		int id = pdata->regulators[i].id;
+		int index = id - MAX8998_LDO2;
+
+		desc = ldo_voltage_map[id];
+		if (desc && regulators[index].ops != &max8998_others_ops) {
+			int count = (desc->max - desc->min) / desc->step + 1;
+			regulators[index].n_voltages = count;
+		}
+		rdev[i] = regulator_register(&regulators[index], max8998->dev,
+				pdata->regulators[i].initdata, max8998, NULL);
+		if (IS_ERR(rdev[i])) {
+			ret = PTR_ERR(rdev[i]);
+			dev_err(max8998->dev, "regulator init failed\n");
+			rdev[i] = NULL;
+			goto err;
+		}
+	}
+
+
+	return 0;
+err:
+	for (i = 0; i < max8998->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+err_free_mem:
+	kfree(max8998->rdev);
+	kfree(max8998);
+
+	return ret;
+}
+
+static int __devexit max8998_pmic_remove(struct platform_device *pdev)
+{
+	struct max8998_data *max8998 = platform_get_drvdata(pdev);
+	struct regulator_dev **rdev = max8998->rdev;
+	int i;
+
+	for (i = 0; i < max8998->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+	kfree(max8998->rdev);
+	kfree(max8998);
+
+	return 0;
+}
+
+static const struct platform_device_id max8998_pmic_id[] = {
+	{ "max8998-pmic", TYPE_MAX8998 },
+	{ "lp3974-pmic", TYPE_LP3974 },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, max8998_pmic_id);
+
+static struct platform_driver max8998_pmic_driver = {
+	.driver = {
+		.name = "max8998-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = max8998_pmic_probe,
+	.remove = __devexit_p(max8998_pmic_remove),
+	.id_table = max8998_pmic_id,
+};
+
+static int __init max8998_pmic_init(void)
+{
+	return platform_driver_register(&max8998_pmic_driver);
+}
+subsys_initcall(max8998_pmic_init);
+
+static void __exit max8998_pmic_cleanup(void)
+{
+	platform_driver_unregister(&max8998_pmic_driver);
+}
+module_exit(max8998_pmic_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 8998 voltage regulator driver");
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/mc13783-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/mc13783-regulator.c
new file mode 100644
index 0000000..6c0face
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/mc13783-regulator.c
@@ -0,0 +1,422 @@
+/*
+ * Regulator Driver for Freescale MC13783 PMIC
+ *
+ * Copyright 2010 Yong Shen <yong.shen@linaro.org>
+ * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/mfd/mc13783.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include "mc13xxx.h"
+
+#define MC13783_REG_SWITCHERS5			29
+#define MC13783_REG_SWITCHERS5_SW3EN			(1 << 20)
+#define MC13783_REG_SWITCHERS5_SW3VSEL			18
+#define MC13783_REG_SWITCHERS5_SW3VSEL_M		(3 << 18)
+
+#define MC13783_REG_REGULATORSETTING0		30
+#define MC13783_REG_REGULATORSETTING0_VIOLOVSEL		2
+#define MC13783_REG_REGULATORSETTING0_VDIGVSEL		4
+#define MC13783_REG_REGULATORSETTING0_VGENVSEL		6
+#define MC13783_REG_REGULATORSETTING0_VRFDIGVSEL	9
+#define MC13783_REG_REGULATORSETTING0_VRFREFVSEL	11
+#define MC13783_REG_REGULATORSETTING0_VRFCPVSEL		13
+#define MC13783_REG_REGULATORSETTING0_VSIMVSEL		14
+#define MC13783_REG_REGULATORSETTING0_VESIMVSEL		15
+#define MC13783_REG_REGULATORSETTING0_VCAMVSEL		16
+
+#define MC13783_REG_REGULATORSETTING0_VIOLOVSEL_M	(3 << 2)
+#define MC13783_REG_REGULATORSETTING0_VDIGVSEL_M	(3 << 4)
+#define MC13783_REG_REGULATORSETTING0_VGENVSEL_M	(7 << 6)
+#define MC13783_REG_REGULATORSETTING0_VRFDIGVSEL_M	(3 << 9)
+#define MC13783_REG_REGULATORSETTING0_VRFREFVSEL_M	(3 << 11)
+#define MC13783_REG_REGULATORSETTING0_VRFCPVSEL_M	(1 << 13)
+#define MC13783_REG_REGULATORSETTING0_VSIMVSEL_M	(1 << 14)
+#define MC13783_REG_REGULATORSETTING0_VESIMVSEL_M	(1 << 15)
+#define MC13783_REG_REGULATORSETTING0_VCAMVSEL_M	(7 << 16)
+
+#define MC13783_REG_REGULATORSETTING1		31
+#define MC13783_REG_REGULATORSETTING1_VVIBVSEL		0
+#define MC13783_REG_REGULATORSETTING1_VRF1VSEL		2
+#define MC13783_REG_REGULATORSETTING1_VRF2VSEL		4
+#define MC13783_REG_REGULATORSETTING1_VMMC1VSEL		6
+#define MC13783_REG_REGULATORSETTING1_VMMC2VSEL		9
+
+#define MC13783_REG_REGULATORSETTING1_VVIBVSEL_M	(3 << 0)
+#define MC13783_REG_REGULATORSETTING1_VRF1VSEL_M	(3 << 2)
+#define MC13783_REG_REGULATORSETTING1_VRF2VSEL_M	(3 << 4)
+#define MC13783_REG_REGULATORSETTING1_VMMC1VSEL_M	(7 << 6)
+#define MC13783_REG_REGULATORSETTING1_VMMC2VSEL_M	(7 << 9)
+
+#define MC13783_REG_REGULATORMODE0		32
+#define MC13783_REG_REGULATORMODE0_VAUDIOEN		(1 << 0)
+#define MC13783_REG_REGULATORMODE0_VIOHIEN		(1 << 3)
+#define MC13783_REG_REGULATORMODE0_VIOLOEN		(1 << 6)
+#define MC13783_REG_REGULATORMODE0_VDIGEN		(1 << 9)
+#define MC13783_REG_REGULATORMODE0_VGENEN		(1 << 12)
+#define MC13783_REG_REGULATORMODE0_VRFDIGEN		(1 << 15)
+#define MC13783_REG_REGULATORMODE0_VRFREFEN		(1 << 18)
+#define MC13783_REG_REGULATORMODE0_VRFCPEN		(1 << 21)
+
+#define MC13783_REG_REGULATORMODE1		33
+#define MC13783_REG_REGULATORMODE1_VSIMEN		(1 << 0)
+#define MC13783_REG_REGULATORMODE1_VESIMEN		(1 << 3)
+#define MC13783_REG_REGULATORMODE1_VCAMEN		(1 << 6)
+#define MC13783_REG_REGULATORMODE1_VRFBGEN		(1 << 9)
+#define MC13783_REG_REGULATORMODE1_VVIBEN		(1 << 11)
+#define MC13783_REG_REGULATORMODE1_VRF1EN		(1 << 12)
+#define MC13783_REG_REGULATORMODE1_VRF2EN		(1 << 15)
+#define MC13783_REG_REGULATORMODE1_VMMC1EN		(1 << 18)
+#define MC13783_REG_REGULATORMODE1_VMMC2EN		(1 << 21)
+
+#define MC13783_REG_POWERMISC			34
+#define MC13783_REG_POWERMISC_GPO1EN			(1 << 6)
+#define MC13783_REG_POWERMISC_GPO2EN			(1 << 8)
+#define MC13783_REG_POWERMISC_GPO3EN			(1 << 10)
+#define MC13783_REG_POWERMISC_GPO4EN			(1 << 12)
+#define MC13783_REG_POWERMISC_PWGT1SPIEN		(1 << 15)
+#define MC13783_REG_POWERMISC_PWGT2SPIEN		(1 << 16)
+
+#define MC13783_REG_POWERMISC_PWGTSPI_M			(3 << 15)
+
+
+/* Voltage Values */
+static const int mc13783_sw3_val[] = {
+	5000000, 5000000, 5000000, 5500000,
+};
+
+static const int mc13783_vaudio_val[] = {
+	2775000,
+};
+
+static const int mc13783_viohi_val[] = {
+	2775000,
+};
+
+static const int mc13783_violo_val[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static const int mc13783_vdig_val[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static const int mc13783_vgen_val[] = {
+	1200000, 1300000, 1500000, 1800000,
+	1100000, 2000000, 2775000, 2400000,
+};
+
+static const int mc13783_vrfdig_val[] = {
+	1200000, 1500000, 1800000, 1875000,
+};
+
+static const int mc13783_vrfref_val[] = {
+	2475000, 2600000, 2700000, 2775000,
+};
+
+static const int mc13783_vrfcp_val[] = {
+	2700000, 2775000,
+};
+
+static const int mc13783_vsim_val[] = {
+	1800000, 2900000, 3000000,
+};
+
+static const int mc13783_vesim_val[] = {
+	1800000, 2900000,
+};
+
+static const int mc13783_vcam_val[] = {
+	1500000, 1800000, 2500000, 2550000,
+	2600000, 2750000, 2800000, 3000000,
+};
+
+static const int mc13783_vrfbg_val[] = {
+	1250000,
+};
+
+static const int mc13783_vvib_val[] = {
+	1300000, 1800000, 2000000, 3000000,
+};
+
+static const int mc13783_vmmc_val[] = {
+	1600000, 1800000, 2000000, 2600000,
+	2700000, 2800000, 2900000, 3000000,
+};
+
+static const int mc13783_vrf_val[] = {
+	1500000, 1875000, 2700000, 2775000,
+};
+
+static const int mc13783_gpo_val[] = {
+	3100000,
+};
+
+static const int mc13783_pwgtdrv_val[] = {
+	5500000,
+};
+
+static struct regulator_ops mc13783_gpo_regulator_ops;
+
+#define MC13783_DEFINE(prefix, name, reg, vsel_reg, voltages)	\
+	MC13xxx_DEFINE(MC13783_REG_, name, reg, vsel_reg, voltages, \
+			mc13xxx_regulator_ops)
+
+#define MC13783_FIXED_DEFINE(prefix, name, reg, voltages)		\
+	MC13xxx_FIXED_DEFINE(MC13783_REG_, name, reg, voltages, \
+			mc13xxx_fixed_regulator_ops)
+
+#define MC13783_GPO_DEFINE(prefix, name, reg, voltages)		\
+	MC13xxx_GPO_DEFINE(MC13783_REG_, name, reg, voltages, \
+			mc13783_gpo_regulator_ops)
+
+#define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages)		\
+	MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages)
+#define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages)		\
+	MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages)
+
+static struct mc13xxx_regulator mc13783_regulators[] = {
+	MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val),
+
+	MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val),
+	MC13783_FIXED_DEFINE(REG, VIOHI, REGULATORMODE0, mc13783_viohi_val),
+	MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13783_violo_val),
+	MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13783_vdig_val),
+	MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13783_vgen_val),
+	MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13783_vrfdig_val),
+	MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13783_vrfref_val),
+	MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0,	\
+			    mc13783_vrfcp_val),
+	MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0,	\
+			    mc13783_vsim_val),
+	MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0,	\
+			    mc13783_vesim_val),
+	MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0,	\
+			    mc13783_vcam_val),
+	MC13783_FIXED_DEFINE(REG, VRFBG, REGULATORMODE1, mc13783_vrfbg_val),
+	MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1,	\
+			    mc13783_vvib_val),
+	MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1,	\
+			    mc13783_vrf_val),
+	MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1,	\
+			    mc13783_vrf_val),
+	MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1,	\
+			    mc13783_vmmc_val),
+	MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1,	\
+			    mc13783_vmmc_val),
+	MC13783_GPO_DEFINE(REG, GPO1, POWERMISC, mc13783_gpo_val),
+	MC13783_GPO_DEFINE(REG, GPO2, POWERMISC, mc13783_gpo_val),
+	MC13783_GPO_DEFINE(REG, GPO3, POWERMISC, mc13783_gpo_val),
+	MC13783_GPO_DEFINE(REG, GPO4, POWERMISC, mc13783_gpo_val),
+	MC13783_GPO_DEFINE(REG, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val),
+	MC13783_GPO_DEFINE(REG, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val),
+};
+
+static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
+		u32 val)
+{
+	struct mc13xxx *mc13783 = priv->mc13xxx;
+	int ret;
+	u32 valread;
+
+	BUG_ON(val & ~mask);
+
+	ret = mc13xxx_reg_read(mc13783, MC13783_REG_POWERMISC, &valread);
+	if (ret)
+		return ret;
+
+	/* Update the stored state for Power Gates. */
+	priv->powermisc_pwgt_state =
+				(priv->powermisc_pwgt_state & ~mask) | val;
+	priv->powermisc_pwgt_state &= MC13783_REG_POWERMISC_PWGTSPI_M;
+
+	/* Construct the new register value */
+	valread = (valread & ~mask) | val;
+	/* Overwrite the PWGTxEN with the stored version */
+	valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
+						priv->powermisc_pwgt_state;
+
+	return mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread);
+}
+
+static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int id = rdev_get_id(rdev);
+	int ret;
+	u32 en_val = mc13xxx_regulators[id].enable_bit;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	/* Power Gate enable value is 0 */
+	if (id == MC13783_REG_PWGT1SPI ||
+	    id == MC13783_REG_PWGT2SPI)
+		en_val = 0;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
+					en_val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int id = rdev_get_id(rdev);
+	int ret;
+	u32 dis_val = 0;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	/* Power Gate disable value is 1 */
+	if (id == MC13783_REG_PWGT1SPI ||
+	    id == MC13783_REG_PWGT2SPI)
+		dis_val = mc13xxx_regulators[id].enable_bit;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
+					dis_val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int ret, id = rdev_get_id(rdev);
+	unsigned int val;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	if (ret)
+		return ret;
+
+	/* Power Gates state is stored in powermisc_pwgt_state
+	 * where the meaning of bits is negated */
+	val = (val & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
+	      (priv->powermisc_pwgt_state ^ MC13783_REG_POWERMISC_PWGTSPI_M);
+
+	return (val & mc13xxx_regulators[id].enable_bit) != 0;
+}
+
+static struct regulator_ops mc13783_gpo_regulator_ops = {
+	.enable = mc13783_gpo_regulator_enable,
+	.disable = mc13783_gpo_regulator_disable,
+	.is_enabled = mc13783_gpo_regulator_is_enabled,
+	.list_voltage = mc13xxx_regulator_list_voltage,
+	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
+	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
+};
+
+static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
+{
+	struct mc13xxx_regulator_priv *priv;
+	struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
+	struct mc13xxx_regulator_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
+	struct mc13xxx_regulator_init_data *init_data;
+	int i, ret;
+
+	dev_dbg(&pdev->dev, "%s id %d\n", __func__, pdev->id);
+
+	if (!pdata)
+		return -EINVAL;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv) +
+			pdata->num_regulators * sizeof(priv->regulators[0]),
+			GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->mc13xxx_regulators = mc13783_regulators;
+	priv->mc13xxx = mc13783;
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		init_data = &pdata->regulators[i];
+		priv->regulators[i] = regulator_register(
+				&mc13783_regulators[init_data->id].desc,
+				&pdev->dev, init_data->init_data, priv, NULL);
+
+		if (IS_ERR(priv->regulators[i])) {
+			dev_err(&pdev->dev, "failed to register regulator %s\n",
+				mc13783_regulators[i].desc.name);
+			ret = PTR_ERR(priv->regulators[i]);
+			goto err;
+		}
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+err:
+	while (--i >= 0)
+		regulator_unregister(priv->regulators[i]);
+
+	return ret;
+}
+
+static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
+{
+	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
+	struct mc13xxx_regulator_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
+	int i;
+
+	platform_set_drvdata(pdev, NULL);
+
+	for (i = 0; i < pdata->num_regulators; i++)
+		regulator_unregister(priv->regulators[i]);
+
+	return 0;
+}
+
+static struct platform_driver mc13783_regulator_driver = {
+	.driver	= {
+		.name	= "mc13783-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.remove		= __devexit_p(mc13783_regulator_remove),
+	.probe		= mc13783_regulator_probe,
+};
+
+static int __init mc13783_regulator_init(void)
+{
+	return platform_driver_register(&mc13783_regulator_driver);
+}
+subsys_initcall(mc13783_regulator_init);
+
+static void __exit mc13783_regulator_exit(void)
+{
+	platform_driver_unregister(&mc13783_regulator_driver);
+}
+module_exit(mc13783_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale MC13783 PMIC");
+MODULE_ALIAS("platform:mc13783-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/mc13892-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/mc13892-regulator.c
new file mode 100644
index 0000000..845aa22
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/mc13892-regulator.c
@@ -0,0 +1,659 @@
+/*
+ * Regulator Driver for Freescale MC13892 PMIC
+ *
+ * Copyright 2010 Yong Shen <yong.shen@linaro.org>
+ *
+ * Based on draft driver from Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * 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/mc13892.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include "mc13xxx.h"
+
+#define MC13892_REVISION			7
+
+#define MC13892_POWERCTL0			13
+#define MC13892_POWERCTL0_USEROFFSPI		3
+#define MC13892_POWERCTL0_VCOINCELLVSEL		20
+#define MC13892_POWERCTL0_VCOINCELLVSEL_M	(7<<20)
+#define MC13892_POWERCTL0_VCOINCELLEN		(1<<23)
+
+#define MC13892_SWITCHERS0_SWxHI		(1<<23)
+
+#define MC13892_SWITCHERS0			24
+#define MC13892_SWITCHERS0_SW1VSEL		0
+#define MC13892_SWITCHERS0_SW1VSEL_M		(0x1f<<0)
+#define MC13892_SWITCHERS0_SW1HI		(1<<23)
+#define MC13892_SWITCHERS0_SW1EN		0
+
+#define MC13892_SWITCHERS1			25
+#define MC13892_SWITCHERS1_SW2VSEL		0
+#define MC13892_SWITCHERS1_SW2VSEL_M		(0x1f<<0)
+#define MC13892_SWITCHERS1_SW2HI		(1<<23)
+#define MC13892_SWITCHERS1_SW2EN		0
+
+#define MC13892_SWITCHERS2			26
+#define MC13892_SWITCHERS2_SW3VSEL		0
+#define MC13892_SWITCHERS2_SW3VSEL_M		(0x1f<<0)
+#define MC13892_SWITCHERS2_SW3HI		(1<<23)
+#define MC13892_SWITCHERS2_SW3EN		0
+
+#define MC13892_SWITCHERS3			27
+#define MC13892_SWITCHERS3_SW4VSEL		0
+#define MC13892_SWITCHERS3_SW4VSEL_M		(0x1f<<0)
+#define MC13892_SWITCHERS3_SW4HI		(1<<23)
+#define MC13892_SWITCHERS3_SW4EN		0
+
+#define MC13892_SWITCHERS4			28
+#define MC13892_SWITCHERS4_SW1MODE		0
+#define MC13892_SWITCHERS4_SW1MODE_AUTO		(8<<0)
+#define MC13892_SWITCHERS4_SW1MODE_M		(0xf<<0)
+#define MC13892_SWITCHERS4_SW2MODE		10
+#define MC13892_SWITCHERS4_SW2MODE_AUTO		(8<<10)
+#define MC13892_SWITCHERS4_SW2MODE_M		(0xf<<10)
+
+#define MC13892_SWITCHERS5			29
+#define MC13892_SWITCHERS5_SW3MODE		0
+#define MC13892_SWITCHERS5_SW3MODE_AUTO		(8<<0)
+#define MC13892_SWITCHERS5_SW3MODE_M		(0xf<<0)
+#define MC13892_SWITCHERS5_SW4MODE		8
+#define MC13892_SWITCHERS5_SW4MODE_AUTO		(8<<8)
+#define MC13892_SWITCHERS5_SW4MODE_M		(0xf<<8)
+#define MC13892_SWITCHERS5_SWBSTEN		(1<<20)
+
+#define MC13892_REGULATORSETTING0		30
+#define MC13892_REGULATORSETTING0_VGEN1VSEL	0
+#define MC13892_REGULATORSETTING0_VDIGVSEL	4
+#define MC13892_REGULATORSETTING0_VGEN2VSEL	6
+#define MC13892_REGULATORSETTING0_VPLLVSEL	9
+#define MC13892_REGULATORSETTING0_VUSB2VSEL	11
+#define MC13892_REGULATORSETTING0_VGEN3VSEL	14
+#define MC13892_REGULATORSETTING0_VCAMVSEL	16
+
+#define MC13892_REGULATORSETTING0_VGEN1VSEL_M	(3<<0)
+#define MC13892_REGULATORSETTING0_VDIGVSEL_M	(3<<4)
+#define MC13892_REGULATORSETTING0_VGEN2VSEL_M	(7<<6)
+#define MC13892_REGULATORSETTING0_VPLLVSEL_M	(3<<9)
+#define MC13892_REGULATORSETTING0_VUSB2VSEL_M	(3<<11)
+#define MC13892_REGULATORSETTING0_VGEN3VSEL_M	(1<<14)
+#define MC13892_REGULATORSETTING0_VCAMVSEL_M	(3<<16)
+
+#define MC13892_REGULATORSETTING1		31
+#define MC13892_REGULATORSETTING1_VVIDEOVSEL	2
+#define MC13892_REGULATORSETTING1_VAUDIOVSEL	4
+#define MC13892_REGULATORSETTING1_VSDVSEL	6
+
+#define MC13892_REGULATORSETTING1_VVIDEOVSEL_M	(3<<2)
+#define MC13892_REGULATORSETTING1_VAUDIOVSEL_M	(3<<4)
+#define MC13892_REGULATORSETTING1_VSDVSEL_M	(7<<6)
+
+#define MC13892_REGULATORMODE0			32
+#define MC13892_REGULATORMODE0_VGEN1EN		(1<<0)
+#define MC13892_REGULATORMODE0_VGEN1STDBY	(1<<1)
+#define MC13892_REGULATORMODE0_VGEN1MODE	(1<<2)
+#define MC13892_REGULATORMODE0_VIOHIEN		(1<<3)
+#define MC13892_REGULATORMODE0_VIOHISTDBY	(1<<4)
+#define MC13892_REGULATORMODE0_VIOHIMODE	(1<<5)
+#define MC13892_REGULATORMODE0_VDIGEN		(1<<9)
+#define MC13892_REGULATORMODE0_VDIGSTDBY	(1<<10)
+#define MC13892_REGULATORMODE0_VDIGMODE		(1<<11)
+#define MC13892_REGULATORMODE0_VGEN2EN		(1<<12)
+#define MC13892_REGULATORMODE0_VGEN2STDBY	(1<<13)
+#define MC13892_REGULATORMODE0_VGEN2MODE	(1<<14)
+#define MC13892_REGULATORMODE0_VPLLEN		(1<<15)
+#define MC13892_REGULATORMODE0_VPLLSTDBY	(1<<16)
+#define MC13892_REGULATORMODE0_VPLLMODE		(1<<17)
+#define MC13892_REGULATORMODE0_VUSB2EN		(1<<18)
+#define MC13892_REGULATORMODE0_VUSB2STDBY	(1<<19)
+#define MC13892_REGULATORMODE0_VUSB2MODE	(1<<20)
+
+#define MC13892_REGULATORMODE1			33
+#define MC13892_REGULATORMODE1_VGEN3EN		(1<<0)
+#define MC13892_REGULATORMODE1_VGEN3STDBY	(1<<1)
+#define MC13892_REGULATORMODE1_VGEN3MODE	(1<<2)
+#define MC13892_REGULATORMODE1_VCAMEN		(1<<6)
+#define MC13892_REGULATORMODE1_VCAMSTDBY	(1<<7)
+#define MC13892_REGULATORMODE1_VCAMMODE		(1<<8)
+#define MC13892_REGULATORMODE1_VCAMCONFIGEN	(1<<9)
+#define MC13892_REGULATORMODE1_VVIDEOEN		(1<<12)
+#define MC13892_REGULATORMODE1_VVIDEOSTDBY	(1<<13)
+#define MC13892_REGULATORMODE1_VVIDEOMODE	(1<<14)
+#define MC13892_REGULATORMODE1_VAUDIOEN		(1<<15)
+#define MC13892_REGULATORMODE1_VAUDIOSTDBY	(1<<16)
+#define MC13892_REGULATORMODE1_VAUDIOMODE	(1<<17)
+#define MC13892_REGULATORMODE1_VSDEN		(1<<18)
+#define MC13892_REGULATORMODE1_VSDSTDBY		(1<<19)
+#define MC13892_REGULATORMODE1_VSDMODE		(1<<20)
+
+#define MC13892_POWERMISC			34
+#define MC13892_POWERMISC_GPO1EN		(1<<6)
+#define MC13892_POWERMISC_GPO2EN		(1<<8)
+#define MC13892_POWERMISC_GPO3EN		(1<<10)
+#define MC13892_POWERMISC_GPO4EN		(1<<12)
+#define MC13892_POWERMISC_PWGT1SPIEN		(1<<15)
+#define MC13892_POWERMISC_PWGT2SPIEN		(1<<16)
+#define MC13892_POWERMISC_GPO4ADINEN		(1<<21)
+
+#define MC13892_POWERMISC_PWGTSPI_M		(3 << 15)
+
+#define MC13892_USB1				50
+#define MC13892_USB1_VUSBEN			(1<<3)
+
+static const int mc13892_vcoincell[] = {
+	2500000, 2700000, 2800000, 2900000, 3000000, 3100000,
+	3200000, 3300000,
+};
+
+static const int mc13892_sw1[] = {
+	600000,   625000,  650000,  675000,  700000,  725000,
+	750000,   775000,  800000,  825000,  850000,  875000,
+	900000,   925000,  950000,  975000, 1000000, 1025000,
+	1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
+	1350000, 1375000
+};
+
+static const int mc13892_sw[] = {
+	600000,   625000,  650000,  675000,  700000,  725000,
+	750000,   775000,  800000,  825000,  850000,  875000,
+	900000,   925000,  950000,  975000, 1000000, 1025000,
+	1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
+	1350000, 1375000, 1400000, 1425000, 1450000, 1475000,
+	1500000, 1525000, 1550000, 1575000, 1600000, 1625000,
+	1650000, 1675000, 1700000, 1725000, 1750000, 1775000,
+	1800000, 1825000, 1850000, 1875000
+};
+
+static const int mc13892_swbst[] = {
+	5000000,
+};
+
+static const int mc13892_viohi[] = {
+	2775000,
+};
+
+static const int mc13892_vpll[] = {
+	1050000, 1250000, 1650000, 1800000,
+};
+
+static const int mc13892_vdig[] = {
+	1050000, 1250000, 1650000, 1800000,
+};
+
+static const int mc13892_vsd[] = {
+	1800000, 2000000, 2600000, 2700000,
+	2800000, 2900000, 3000000, 3150000,
+};
+
+static const int mc13892_vusb2[] = {
+	2400000, 2600000, 2700000, 2775000,
+};
+
+static const int mc13892_vvideo[] = {
+	2700000, 2775000, 2500000, 2600000,
+};
+
+static const int mc13892_vaudio[] = {
+	2300000, 2500000, 2775000, 3000000,
+};
+
+static const int mc13892_vcam[] = {
+	2500000, 2600000, 2750000, 3000000,
+};
+
+static const int mc13892_vgen1[] = {
+	1200000, 1500000, 2775000, 3150000,
+};
+
+static const int mc13892_vgen2[] = {
+	1200000, 1500000, 1600000, 1800000,
+	2700000, 2800000, 3000000, 3150000,
+};
+
+static const int mc13892_vgen3[] = {
+	1800000, 2900000,
+};
+
+static const int mc13892_vusb[] = {
+	3300000,
+};
+
+static const int mc13892_gpo[] = {
+	2750000,
+};
+
+static const int mc13892_pwgtdrv[] = {
+	5000000,
+};
+
+static struct regulator_ops mc13892_gpo_regulator_ops;
+/* sw regulators need special care due to the "hi bit" */
+static struct regulator_ops mc13892_sw_regulator_ops;
+
+
+#define MC13892_FIXED_DEFINE(name, reg, voltages)		\
+	MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages,	\
+			mc13xxx_fixed_regulator_ops)
+
+#define MC13892_GPO_DEFINE(name, reg, voltages)			\
+	MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages,	\
+			mc13892_gpo_regulator_ops)
+
+#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages)	\
+	MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
+			mc13892_sw_regulator_ops)
+
+#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages)	\
+	MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \
+			mc13xxx_regulator_ops)
+
+static struct mc13xxx_regulator mc13892_regulators[] = {
+	MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0, mc13892_vcoincell),
+	MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1),
+	MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw),
+	MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw),
+	MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw),
+	MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst),
+	MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi),
+	MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0,	\
+		mc13892_vpll),
+	MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,	\
+		mc13892_vdig),
+	MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1,	\
+		mc13892_vsd),
+	MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0,	\
+		mc13892_vusb2),
+	MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1,	\
+		mc13892_vvideo),
+	MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1,	\
+		mc13892_vaudio),
+	MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0,	\
+		mc13892_vcam),
+	MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0,	\
+		mc13892_vgen1),
+	MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0,	\
+		mc13892_vgen2),
+	MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0,	\
+		mc13892_vgen3),
+	MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb),
+	MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo),
+	MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo),
+	MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo),
+	MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo),
+	MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv),
+	MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv),
+};
+
+static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
+				 u32 val)
+{
+	struct mc13xxx *mc13892 = priv->mc13xxx;
+	int ret;
+	u32 valread;
+
+	BUG_ON(val & ~mask);
+
+	ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread);
+	if (ret)
+		return ret;
+
+	/* Update the stored state for Power Gates. */
+	priv->powermisc_pwgt_state =
+		(priv->powermisc_pwgt_state & ~mask) | val;
+	priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M;
+
+	/* Construct the new register value */
+	valread = (valread & ~mask) | val;
+	/* Overwrite the PWGTxEN with the stored version */
+	valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) |
+		priv->powermisc_pwgt_state;
+
+	return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
+}
+
+static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	int ret;
+	u32 en_val = mc13892_regulators[id].enable_bit;
+	u32 mask = mc13892_regulators[id].enable_bit;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	/* Power Gate enable value is 0 */
+	if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI)
+		en_val = 0;
+
+	if (id == MC13892_GPO4)
+		mask |= MC13892_POWERMISC_GPO4ADINEN;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13892_powermisc_rmw(priv, mask, en_val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int id = rdev_get_id(rdev);
+	int ret;
+	u32 dis_val = 0;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	/* Power Gate disable value is 1 */
+	if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI)
+		dis_val = mc13892_regulators[id].enable_bit;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
+		dis_val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int ret, id = rdev_get_id(rdev);
+	unsigned int val;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	if (ret)
+		return ret;
+
+	/* Power Gates state is stored in powermisc_pwgt_state
+	 * where the meaning of bits is negated */
+	val = (val & ~MC13892_POWERMISC_PWGTSPI_M) |
+		(priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M);
+
+	return (val & mc13892_regulators[id].enable_bit) != 0;
+}
+
+
+static struct regulator_ops mc13892_gpo_regulator_ops = {
+	.enable = mc13892_gpo_regulator_enable,
+	.disable = mc13892_gpo_regulator_disable,
+	.is_enabled = mc13892_gpo_regulator_is_enabled,
+	.list_voltage = mc13xxx_regulator_list_voltage,
+	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
+	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
+};
+
+static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int ret, id = rdev_get_id(rdev);
+	unsigned int val, hi;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx,
+		mc13892_regulators[id].vsel_reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+	if (ret)
+		return ret;
+
+	hi  = val & MC13892_SWITCHERS0_SWxHI;
+	val = (val & mc13892_regulators[id].vsel_mask)
+		>> mc13892_regulators[id].vsel_shift;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+
+	if (hi)
+		val = (25000 * val) + 1100000;
+	else
+		val = (25000 * val) + 600000;
+
+	return val;
+}
+
+static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
+		int min_uV, int max_uV, unsigned *selector)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int hi, value, mask, id = rdev_get_id(rdev);
+	u32 valread;
+	int ret;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+		__func__, id, min_uV, max_uV);
+
+	/* Find the best index */
+	value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
+	dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
+	if (value < 0)
+		return value;
+
+	value = mc13892_regulators[id].voltages[value];
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx,
+		mc13892_regulators[id].vsel_reg, &valread);
+	if (ret)
+		goto err;
+
+	if (value > 1375000)
+		hi = 1;
+	else if (value < 1100000)
+		hi = 0;
+	else
+		hi = valread & MC13892_SWITCHERS0_SWxHI;
+
+	if (hi) {
+		value = (value - 1100000) / 25000;
+		value |= MC13892_SWITCHERS0_SWxHI;
+	} else
+		value = (value - 600000) / 25000;
+
+	mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
+	valread = (valread & ~mask) |
+			(value << mc13892_regulators[id].vsel_shift);
+	ret = mc13xxx_reg_write(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
+			valread);
+err:
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static struct regulator_ops mc13892_sw_regulator_ops = {
+	.is_enabled = mc13xxx_sw_regulator_is_enabled,
+	.list_voltage = mc13xxx_regulator_list_voltage,
+	.set_voltage = mc13892_sw_regulator_set_voltage,
+	.get_voltage = mc13892_sw_regulator_get_voltage,
+};
+
+static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	unsigned int en_val = 0;
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int ret, id = rdev_get_id(rdev);
+
+	if (mode == REGULATOR_MODE_FAST)
+		en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg,
+		MC13892_REGULATORMODE1_VCAMCONFIGEN, en_val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	int ret, id = rdev_get_id(rdev);
+	unsigned int val;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	if (ret)
+		return ret;
+
+	if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN)
+		return REGULATOR_MODE_FAST;
+
+	return REGULATOR_MODE_NORMAL;
+}
+
+
+static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
+{
+	struct mc13xxx_regulator_priv *priv;
+	struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
+	struct mc13xxx_regulator_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
+	struct mc13xxx_regulator_init_data *mc13xxx_data;
+	int i, ret;
+	int num_regulators = 0;
+	u32 val;
+
+	num_regulators = mc13xxx_get_num_regulators_dt(pdev);
+	if (num_regulators <= 0 && pdata)
+		num_regulators = pdata->num_regulators;
+	if (num_regulators <= 0)
+		return -EINVAL;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv) +
+		num_regulators * sizeof(priv->regulators[0]),
+		GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->num_regulators = num_regulators;
+	priv->mc13xxx_regulators = mc13892_regulators;
+	priv->mc13xxx = mc13892;
+	platform_set_drvdata(pdev, priv);
+
+	mc13xxx_lock(mc13892);
+	ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val);
+	if (ret)
+		goto err_unlock;
+
+	/* enable switch auto mode */
+	if ((val & 0x0000FFFF) == 0x45d0) {
+		ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4,
+			MC13892_SWITCHERS4_SW1MODE_M |
+			MC13892_SWITCHERS4_SW2MODE_M,
+			MC13892_SWITCHERS4_SW1MODE_AUTO |
+			MC13892_SWITCHERS4_SW2MODE_AUTO);
+		if (ret)
+			goto err_unlock;
+
+		ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5,
+			MC13892_SWITCHERS5_SW3MODE_M |
+			MC13892_SWITCHERS5_SW4MODE_M,
+			MC13892_SWITCHERS5_SW3MODE_AUTO |
+			MC13892_SWITCHERS5_SW4MODE_AUTO);
+		if (ret)
+			goto err_unlock;
+	}
+	mc13xxx_unlock(mc13892);
+
+	mc13892_regulators[MC13892_VCAM].desc.ops->set_mode
+		= mc13892_vcam_set_mode;
+	mc13892_regulators[MC13892_VCAM].desc.ops->get_mode
+		= mc13892_vcam_get_mode;
+
+	mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators,
+					ARRAY_SIZE(mc13892_regulators));
+	for (i = 0; i < num_regulators; i++) {
+		struct regulator_init_data *init_data;
+		struct regulator_desc *desc;
+		struct device_node *node = NULL;
+		int id;
+
+		if (mc13xxx_data) {
+			id = mc13xxx_data[i].id;
+			init_data = mc13xxx_data[i].init_data;
+			node = mc13xxx_data[i].node;
+		} else {
+			id = pdata->regulators[i].id;
+			init_data = pdata->regulators[i].init_data;
+		}
+		desc = &mc13892_regulators[id].desc;
+
+		priv->regulators[i] = regulator_register(
+			desc, &pdev->dev, init_data, priv, node);
+
+		if (IS_ERR(priv->regulators[i])) {
+			dev_err(&pdev->dev, "failed to register regulator %s\n",
+				mc13892_regulators[i].desc.name);
+			ret = PTR_ERR(priv->regulators[i]);
+			goto err;
+		}
+	}
+
+	return 0;
+err:
+	while (--i >= 0)
+		regulator_unregister(priv->regulators[i]);
+	return ret;
+
+err_unlock:
+	mc13xxx_unlock(mc13892);
+	return ret;
+}
+
+static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
+{
+	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
+	int i;
+
+	platform_set_drvdata(pdev, NULL);
+
+	for (i = 0; i < priv->num_regulators; i++)
+		regulator_unregister(priv->regulators[i]);
+
+	return 0;
+}
+
+static struct platform_driver mc13892_regulator_driver = {
+	.driver	= {
+		.name	= "mc13892-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.remove	= __devexit_p(mc13892_regulator_remove),
+	.probe	= mc13892_regulator_probe,
+};
+
+static int __init mc13892_regulator_init(void)
+{
+	return platform_driver_register(&mc13892_regulator_driver);
+}
+subsys_initcall(mc13892_regulator_init);
+
+static void __exit mc13892_regulator_exit(void)
+{
+	platform_driver_unregister(&mc13892_regulator_driver);
+}
+module_exit(mc13892_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC");
+MODULE_ALIAS("platform:mc13892-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/mc13xxx-regulator-core.c b/ap/os/linux/linux-3.4.x/drivers/regulator/mc13xxx-regulator-core.c
new file mode 100644
index 0000000..62dcd0a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/mc13xxx-regulator-core.c
@@ -0,0 +1,301 @@
+/*
+ * Regulator Driver for Freescale MC13xxx PMIC
+ *
+ * Copyright 2010 Yong Shen <yong.shen@linaro.org>
+ *
+ * Based on mc13783 regulator driver :
+ * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Regs infos taken from mc13xxx drivers from freescale and mc13xxx.pdf file
+ * from freescale
+ */
+
+#include <linux/mfd/mc13xxx.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include "mc13xxx.h"
+
+static int mc13xxx_regulator_enable(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int id = rdev_get_id(rdev);
+	int ret;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg,
+			mc13xxx_regulators[id].enable_bit,
+			mc13xxx_regulators[id].enable_bit);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13xxx_regulator_disable(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int id = rdev_get_id(rdev);
+	int ret;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg,
+			mc13xxx_regulators[id].enable_bit, 0);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int ret, id = rdev_get_id(rdev);
+	unsigned int val;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	if (ret)
+		return ret;
+
+	return (val & mc13xxx_regulators[id].enable_bit) != 0;
+}
+
+int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
+						unsigned selector)
+{
+	int id = rdev_get_id(rdev);
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+
+	if (selector >= mc13xxx_regulators[id].desc.n_voltages)
+		return -EINVAL;
+
+	return mc13xxx_regulators[id].voltages[selector];
+}
+EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage);
+
+int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev,
+						int min_uV, int max_uV)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int reg_id = rdev_get_id(rdev);
+	int i;
+	int bestmatch;
+	int bestindex;
+
+	/*
+	 * Locate the minimum voltage fitting the criteria on
+	 * this regulator. The switchable voltages are not
+	 * in strict falling order so we need to check them
+	 * all for the best match.
+	 */
+	bestmatch = INT_MAX;
+	bestindex = -1;
+	for (i = 0; i < mc13xxx_regulators[reg_id].desc.n_voltages; i++) {
+		if (mc13xxx_regulators[reg_id].voltages[i] >= min_uV &&
+		    mc13xxx_regulators[reg_id].voltages[i] < bestmatch) {
+			bestmatch = mc13xxx_regulators[reg_id].voltages[i];
+			bestindex = i;
+		}
+	}
+
+	if (bestindex < 0 || bestmatch > max_uV) {
+		dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n",
+				min_uV, max_uV);
+		return -EINVAL;
+	}
+	return bestindex;
+}
+EXPORT_SYMBOL_GPL(mc13xxx_get_best_voltage_index);
+
+static int mc13xxx_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
+		int max_uV, unsigned *selector)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int value, id = rdev_get_id(rdev);
+	int ret;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+		__func__, id, min_uV, max_uV);
+
+	/* Find the best index */
+	value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV);
+	dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
+	if (value < 0)
+		return value;
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg,
+			mc13xxx_regulators[id].vsel_mask,
+			value << mc13xxx_regulators[id].vsel_shift);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	return ret;
+}
+
+static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int ret, id = rdev_get_id(rdev);
+	unsigned int val;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	mc13xxx_lock(priv->mc13xxx);
+	ret = mc13xxx_reg_read(priv->mc13xxx,
+				mc13xxx_regulators[id].vsel_reg, &val);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	if (ret)
+		return ret;
+
+	val = (val & mc13xxx_regulators[id].vsel_mask)
+		>> mc13xxx_regulators[id].vsel_shift;
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+
+	BUG_ON(val >= mc13xxx_regulators[id].desc.n_voltages);
+
+	return mc13xxx_regulators[id].voltages[val];
+}
+
+struct regulator_ops mc13xxx_regulator_ops = {
+	.enable = mc13xxx_regulator_enable,
+	.disable = mc13xxx_regulator_disable,
+	.is_enabled = mc13xxx_regulator_is_enabled,
+	.list_voltage = mc13xxx_regulator_list_voltage,
+	.set_voltage = mc13xxx_regulator_set_voltage,
+	.get_voltage = mc13xxx_regulator_get_voltage,
+};
+EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops);
+
+int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
+	       int max_uV, unsigned *selector)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int id = rdev_get_id(rdev);
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+		__func__, id, min_uV, max_uV);
+
+	if (min_uV >= mc13xxx_regulators[id].voltages[0] &&
+	    max_uV <= mc13xxx_regulators[id].voltages[0])
+		return 0;
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage);
+
+int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
+	struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
+	int id = rdev_get_id(rdev);
+
+	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+	return mc13xxx_regulators[id].voltages[0];
+}
+EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage);
+
+struct regulator_ops mc13xxx_fixed_regulator_ops = {
+	.enable = mc13xxx_regulator_enable,
+	.disable = mc13xxx_regulator_disable,
+	.is_enabled = mc13xxx_regulator_is_enabled,
+	.list_voltage = mc13xxx_regulator_list_voltage,
+	.set_voltage = mc13xxx_fixed_regulator_set_voltage,
+	.get_voltage = mc13xxx_fixed_regulator_get_voltage,
+};
+EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
+
+int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	return 1;
+}
+EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled);
+
+#ifdef CONFIG_OF
+int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
+{
+	struct device_node *parent, *child;
+	int num = 0;
+
+	of_node_get(pdev->dev.parent->of_node);
+	parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+	if (!parent)
+		return -ENODEV;
+
+	for_each_child_of_node(parent, child)
+		num++;
+
+	return num;
+}
+EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt);
+
+struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt(
+	struct platform_device *pdev, struct mc13xxx_regulator *regulators,
+	int num_regulators)
+{
+	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
+	struct mc13xxx_regulator_init_data *data, *p;
+	struct device_node *parent, *child;
+	int i;
+
+	of_node_get(pdev->dev.parent->of_node);
+	parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+	if (!parent)
+		return NULL;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data) * priv->num_regulators,
+			    GFP_KERNEL);
+	if (!data)
+		return NULL;
+	p = data;
+
+	for_each_child_of_node(parent, child) {
+		for (i = 0; i < num_regulators; i++) {
+			if (!of_node_cmp(child->name,
+					 regulators[i].desc.name)) {
+				p->id = i;
+				p->init_data = of_get_regulator_init_data(
+							&pdev->dev, child);
+				p->node = child;
+				p++;
+				break;
+			}
+		}
+	}
+
+	return data;
+}
+EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt);
+#endif
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale MC13xxx PMIC");
+MODULE_ALIAS("mc13xxx-regulator-core");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/mc13xxx.h b/ap/os/linux/linux-3.4.x/drivers/regulator/mc13xxx.h
new file mode 100644
index 0000000..b3961c6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/mc13xxx.h
@@ -0,0 +1,121 @@
+/*
+ * mc13xxx.h - regulators for the Freescale mc13xxx PMIC
+ *
+ *  Copyright (C) 2010 Yong Shen <yong.shen@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_REGULATOR_MC13XXX_H
+#define __LINUX_REGULATOR_MC13XXX_H
+
+#include <linux/regulator/driver.h>
+
+struct mc13xxx_regulator {
+	struct regulator_desc desc;
+	int reg;
+	int enable_bit;
+	int vsel_reg;
+	int vsel_shift;
+	int vsel_mask;
+	int hi_bit;
+	int const *voltages;
+};
+
+struct mc13xxx_regulator_priv {
+	struct mc13xxx *mc13xxx;
+	u32 powermisc_pwgt_state;
+	struct mc13xxx_regulator *mc13xxx_regulators;
+	int num_regulators;
+	struct regulator_dev *regulators[];
+};
+
+extern int mc13xxx_sw_regulator(struct regulator_dev *rdev);
+extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev);
+extern int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev,
+						int min_uV, int max_uV);
+extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
+						unsigned selector);
+extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
+		int min_uV, int max_uV, unsigned *selector);
+extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev);
+
+#ifdef CONFIG_OF
+extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev);
+extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
+	struct platform_device *pdev, struct mc13xxx_regulator *regulators,
+	int num_regulators);
+#else
+static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
+{
+	return -ENODEV;
+}
+
+static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
+	struct platform_device *pdev, struct mc13xxx_regulator *regulators,
+	int num_regulators)
+{
+	return NULL;
+}
+#endif
+
+extern struct regulator_ops mc13xxx_regulator_ops;
+extern struct regulator_ops mc13xxx_fixed_regulator_ops;
+
+#define MC13xxx_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages, _ops)	\
+	[prefix ## _name] = {				\
+		.desc = {						\
+			.name = #_name,					\
+			.n_voltages = ARRAY_SIZE(_voltages),		\
+			.ops = &_ops,			\
+			.type = REGULATOR_VOLTAGE,			\
+			.id = prefix ## _name,		\
+			.owner = THIS_MODULE,				\
+		},							\
+		.reg = prefix ## _reg,				\
+		.enable_bit = prefix ## _reg ## _ ## _name ## EN,	\
+		.vsel_reg = prefix ## _vsel_reg,			\
+		.vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\
+		.vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\
+		.voltages =  _voltages,					\
+	}
+
+#define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops)	\
+	[prefix ## _name] = {				\
+		.desc = {						\
+			.name = #_name,					\
+			.n_voltages = ARRAY_SIZE(_voltages),		\
+			.ops = &_ops,		\
+			.type = REGULATOR_VOLTAGE,			\
+			.id = prefix ## _name,		\
+			.owner = THIS_MODULE,				\
+		},							\
+		.reg = prefix ## _reg,				\
+		.enable_bit = prefix ## _reg ## _ ## _name ## EN,	\
+		.voltages =  _voltages,					\
+	}
+
+#define MC13xxx_GPO_DEFINE(prefix, _name, _reg,  _voltages, _ops)	\
+	[prefix ## _name] = {				\
+		.desc = {						\
+			.name = #_name,					\
+			.n_voltages = ARRAY_SIZE(_voltages),		\
+			.ops = &_ops,		\
+			.type = REGULATOR_VOLTAGE,			\
+			.id = prefix ## _name,		\
+			.owner = THIS_MODULE,				\
+		},							\
+		.reg = prefix ## _reg,				\
+		.enable_bit = prefix ## _reg ## _ ## _name ## EN,	\
+		.voltages =  _voltages,					\
+	}
+
+#define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops)	\
+	MC13xxx_DEFINE(SW, _name, _reg, _vsel_reg, _voltages, ops)
+#define MC13xxx_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages, ops)	\
+	MC13xxx_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages, ops)
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/of_regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/of_regulator.c
new file mode 100644
index 0000000..679734d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/of_regulator.c
@@ -0,0 +1,87 @@
+/*
+ * OF helpers for regulator framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/regulator/machine.h>
+
+static void of_get_regulation_constraints(struct device_node *np,
+					struct regulator_init_data **init_data)
+{
+	const __be32 *min_uV, *max_uV, *uV_offset;
+	const __be32 *min_uA, *max_uA;
+	struct regulation_constraints *constraints = &(*init_data)->constraints;
+
+	constraints->name = of_get_property(np, "regulator-name", NULL);
+
+	min_uV = of_get_property(np, "regulator-min-microvolt", NULL);
+	if (min_uV)
+		constraints->min_uV = be32_to_cpu(*min_uV);
+	max_uV = of_get_property(np, "regulator-max-microvolt", NULL);
+	if (max_uV)
+		constraints->max_uV = be32_to_cpu(*max_uV);
+
+	/* Voltage change possible? */
+	if (constraints->min_uV != constraints->max_uV)
+		constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
+	/* Only one voltage?  Then make sure it's set. */
+	if (min_uV && max_uV && constraints->min_uV == constraints->max_uV)
+		constraints->apply_uV = true;
+
+	uV_offset = of_get_property(np, "regulator-microvolt-offset", NULL);
+	if (uV_offset)
+		constraints->uV_offset = be32_to_cpu(*uV_offset);
+	min_uA = of_get_property(np, "regulator-min-microamp", NULL);
+	if (min_uA)
+		constraints->min_uA = be32_to_cpu(*min_uA);
+	max_uA = of_get_property(np, "regulator-max-microamp", NULL);
+	if (max_uA)
+		constraints->max_uA = be32_to_cpu(*max_uA);
+
+	/* Current change possible? */
+	if (constraints->min_uA != constraints->max_uA)
+		constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
+
+	if (of_find_property(np, "regulator-boot-on", NULL))
+		constraints->boot_on = true;
+
+	if (of_find_property(np, "regulator-always-on", NULL))
+		constraints->always_on = true;
+	else /* status change should be possible if not always on. */
+		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+}
+
+/**
+ * of_get_regulator_init_data - extract regulator_init_data structure info
+ * @dev: device requesting for regulator_init_data
+ *
+ * Populates regulator_init_data structure by extracting data from device
+ * tree node, returns a pointer to the populated struture or NULL if memory
+ * alloc fails.
+ */
+struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
+						struct device_node *node)
+{
+	struct regulator_init_data *init_data;
+
+	if (!node)
+		return NULL;
+
+	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
+	if (!init_data)
+		return NULL; /* Out of memory? */
+
+	of_get_regulation_constraints(node, &init_data);
+	return init_data;
+}
+EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/pcap-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/pcap-regulator.c
new file mode 100644
index 0000000..a5aab1b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/pcap-regulator.c
@@ -0,0 +1,323 @@
+/*
+ * PCAP2 Regulator Driver
+ *
+ * Copyright (c) 2009 Daniel Ribeiro <drwyrm@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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/ezx-pcap.h>
+
+static const u16 V1_table[] = {
+	2775, 1275, 1600, 1725, 1825, 1925, 2075, 2275,
+};
+
+static const u16 V2_table[] = {
+	2500, 2775,
+};
+
+static const u16 V3_table[] = {
+	1075, 1275, 1550, 1725, 1876, 1950, 2075, 2275,
+};
+
+static const u16 V4_table[] = {
+	1275, 1550, 1725, 1875, 1950, 2075, 2275, 2775,
+};
+
+static const u16 V5_table[] = {
+	1875, 2275, 2475, 2775,
+};
+
+static const u16 V6_table[] = {
+	2475, 2775,
+};
+
+static const u16 V7_table[] = {
+	1875, 2775,
+};
+
+#define V8_table V4_table
+
+static const u16 V9_table[] = {
+	1575, 1875, 2475, 2775,
+};
+
+static const u16 V10_table[] = {
+	5000,
+};
+
+static const u16 VAUX1_table[] = {
+	1875, 2475, 2775, 3000,
+};
+
+#define VAUX2_table VAUX1_table
+
+static const u16 VAUX3_table[] = {
+	1200, 1200, 1200, 1200, 1400, 1600, 1800, 2000,
+	2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600,
+};
+
+static const u16 VAUX4_table[] = {
+	1800, 1800, 3000, 5000,
+};
+
+static const u16 VSIM_table[] = {
+	1875, 3000,
+};
+
+static const u16 VSIM2_table[] = {
+	1875,
+};
+
+static const u16 VVIB_table[] = {
+	1300, 1800, 2000, 3000,
+};
+
+static const u16 SW1_table[] = {
+	900, 950, 1000, 1050, 1100, 1150, 1200, 1250,
+	1300, 1350, 1400, 1450, 1500, 1600, 1875, 2250,
+};
+
+#define SW2_table SW1_table
+
+static const u16 SW3_table[] = {
+	4000, 4500, 5000, 5500,
+};
+
+struct pcap_regulator {
+	const u8 reg;
+	const u8 en;
+	const u8 index;
+	const u8 stby;
+	const u8 lowpwr;
+	const u8 n_voltages;
+	const u16 *voltage_table;
+};
+
+#define NA 0xff
+
+#define VREG_INFO(_vreg, _reg, _en, _index, _stby, _lowpwr)		\
+	[_vreg]	= {							\
+		.reg		= _reg,					\
+		.en		= _en,					\
+		.index		= _index,				\
+		.stby		= _stby,				\
+		.lowpwr		= _lowpwr,				\
+		.n_voltages	= ARRAY_SIZE(_vreg##_table),		\
+		.voltage_table	= _vreg##_table,			\
+	}
+
+static struct pcap_regulator vreg_table[] = {
+	VREG_INFO(V1,    PCAP_REG_VREG1,   1,  2,  18, 0),
+	VREG_INFO(V2,    PCAP_REG_VREG1,   5,  6,  19, 22),
+	VREG_INFO(V3,    PCAP_REG_VREG1,   7,  8,  20, 23),
+	VREG_INFO(V4,    PCAP_REG_VREG1,   11, 12, 21, 24),
+	/* V5 STBY and LOWPWR are on PCAP_REG_VREG2 */
+	VREG_INFO(V5,    PCAP_REG_VREG1,   15, 16, 12, 19),
+
+	VREG_INFO(V6,    PCAP_REG_VREG2,   1,  2,  14, 20),
+	VREG_INFO(V7,    PCAP_REG_VREG2,   3,  4,  15, 21),
+	VREG_INFO(V8,    PCAP_REG_VREG2,   5,  6,  16, 22),
+	VREG_INFO(V9,    PCAP_REG_VREG2,   9,  10, 17, 23),
+	VREG_INFO(V10,   PCAP_REG_VREG2,   10, NA, 18, 24),
+
+	VREG_INFO(VAUX1, PCAP_REG_AUXVREG, 1,  2,  22, 23),
+	/* VAUX2 ... VSIM2 STBY and LOWPWR are on PCAP_REG_LOWPWR */
+	VREG_INFO(VAUX2, PCAP_REG_AUXVREG, 4,  5,  0,  1),
+	VREG_INFO(VAUX3, PCAP_REG_AUXVREG, 7,  8,  2,  3),
+	VREG_INFO(VAUX4, PCAP_REG_AUXVREG, 12, 13, 4,  5),
+	VREG_INFO(VSIM,  PCAP_REG_AUXVREG, 17, 18, NA, 6),
+	VREG_INFO(VSIM2, PCAP_REG_AUXVREG, 16, NA, NA, 7),
+	VREG_INFO(VVIB,  PCAP_REG_AUXVREG, 19, 20, NA, NA),
+
+	VREG_INFO(SW1,   PCAP_REG_SWCTRL,  1,  2,  NA, NA),
+	VREG_INFO(SW2,   PCAP_REG_SWCTRL,  6,  7,  NA, NA),
+	/* SW3 STBY is on PCAP_REG_AUXVREG */
+	VREG_INFO(SW3,   PCAP_REG_SWCTRL,  11, 12, 24, NA),
+
+	/* SWxS used to control SWx voltage on standby */
+/*	VREG_INFO(SW1S,  PCAP_REG_LOWPWR,  NA, 12, NA, NA),
+	VREG_INFO(SW2S,  PCAP_REG_LOWPWR,  NA, 20, NA, NA), */
+};
+
+static int pcap_regulator_set_voltage(struct regulator_dev *rdev,
+				      int min_uV, int max_uV,
+				      unsigned *selector)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+	int uV;
+	u8 i;
+
+	/* the regulator doesn't support voltage switching */
+	if (vreg->n_voltages == 1)
+		return -EINVAL;
+
+	for (i = 0; i < vreg->n_voltages; i++) {
+		/* For V1 the first is not the best match */
+		if (i == 0 && rdev_get_id(rdev) == V1)
+			i = 1;
+		else if (i + 1 == vreg->n_voltages && rdev_get_id(rdev) == V1)
+			i = 0;
+
+		uV = vreg->voltage_table[i] * 1000;
+		if (min_uV <= uV && uV <= max_uV) {
+			*selector = i;
+			return ezx_pcap_set_bits(pcap, vreg->reg,
+					(vreg->n_voltages - 1) << vreg->index,
+					i << vreg->index);
+		}
+
+		if (i == 0 && rdev_get_id(rdev) == V1)
+			i = vreg->n_voltages - 1;
+	}
+
+	/* the requested voltage range is not supported by this regulator */
+	return -EINVAL;
+}
+
+static int pcap_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+	u32 tmp;
+	int mV;
+
+	if (vreg->n_voltages == 1)
+		return vreg->voltage_table[0] * 1000;
+
+	ezx_pcap_read(pcap, vreg->reg, &tmp);
+	tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1));
+	mV = vreg->voltage_table[tmp];
+
+	return mV * 1000;
+}
+
+static int pcap_regulator_enable(struct regulator_dev *rdev)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+
+	if (vreg->en == NA)
+		return -EINVAL;
+
+	return ezx_pcap_set_bits(pcap, vreg->reg, 1 << vreg->en, 1 << vreg->en);
+}
+
+static int pcap_regulator_disable(struct regulator_dev *rdev)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+
+	if (vreg->en == NA)
+		return -EINVAL;
+
+	return ezx_pcap_set_bits(pcap, vreg->reg, 1 << vreg->en, 0);
+}
+
+static int pcap_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+	void *pcap = rdev_get_drvdata(rdev);
+	u32 tmp;
+
+	if (vreg->en == NA)
+		return -EINVAL;
+
+	ezx_pcap_read(pcap, vreg->reg, &tmp);
+	return (tmp >> vreg->en) & 1;
+}
+
+static int pcap_regulator_list_voltage(struct regulator_dev *rdev,
+							unsigned int index)
+{
+	struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
+
+	return vreg->voltage_table[index] * 1000;
+}
+
+static struct regulator_ops pcap_regulator_ops = {
+	.list_voltage	= pcap_regulator_list_voltage,
+	.set_voltage	= pcap_regulator_set_voltage,
+	.get_voltage	= pcap_regulator_get_voltage,
+	.enable		= pcap_regulator_enable,
+	.disable	= pcap_regulator_disable,
+	.is_enabled	= pcap_regulator_is_enabled,
+};
+
+#define VREG(_vreg)						\
+	[_vreg]	= {						\
+		.name		= #_vreg,			\
+		.id		= _vreg,			\
+		.n_voltages	= ARRAY_SIZE(_vreg##_table),	\
+		.ops		= &pcap_regulator_ops,		\
+		.type		= REGULATOR_VOLTAGE,		\
+		.owner		= THIS_MODULE,			\
+	}
+
+static struct regulator_desc pcap_regulators[] = {
+	VREG(V1), VREG(V2), VREG(V3), VREG(V4), VREG(V5), VREG(V6), VREG(V7),
+	VREG(V8), VREG(V9), VREG(V10), VREG(VAUX1), VREG(VAUX2), VREG(VAUX3),
+	VREG(VAUX4), VREG(VSIM), VREG(VSIM2), VREG(VVIB), VREG(SW1), VREG(SW2),
+};
+
+static int __devinit pcap_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev;
+	void *pcap = dev_get_drvdata(pdev->dev.parent);
+
+	rdev = regulator_register(&pcap_regulators[pdev->id], &pdev->dev,
+				pdev->dev.platform_data, pcap, NULL);
+	if (IS_ERR(rdev))
+		return PTR_ERR(rdev);
+
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+}
+
+static int __devexit pcap_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	regulator_unregister(rdev);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver pcap_regulator_driver = {
+	.driver = {
+		.name	= "pcap-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= pcap_regulator_probe,
+	.remove	= __devexit_p(pcap_regulator_remove),
+};
+
+static int __init pcap_regulator_init(void)
+{
+	return platform_driver_register(&pcap_regulator_driver);
+}
+
+static void __exit pcap_regulator_exit(void)
+{
+	platform_driver_unregister(&pcap_regulator_driver);
+}
+
+subsys_initcall(pcap_regulator_init);
+module_exit(pcap_regulator_exit);
+
+MODULE_AUTHOR("Daniel Ribeiro <drwyrm@gmail.com>");
+MODULE_DESCRIPTION("PCAP2 Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/pcf50633-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/pcf50633-regulator.c
new file mode 100644
index 0000000..6db46c6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/pcf50633-regulator.c
@@ -0,0 +1,367 @@
+/* NXP PCF50633 PMIC Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50633 driver mainly by
+ * Harald Welte and Andy Green and Werner Almesberger
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/pmic.h>
+
+#define PCF50633_REGULATOR(_name, _id, _n) 		\
+	{					\
+		.name = _name, 			\
+		.id = _id,			\
+		.ops = &pcf50633_regulator_ops,	\
+		.n_voltages = _n, \
+		.type = REGULATOR_VOLTAGE, 	\
+		.owner = THIS_MODULE, 		\
+	}
+
+static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
+	[PCF50633_REGULATOR_AUTO]	= PCF50633_REG_AUTOOUT,
+	[PCF50633_REGULATOR_DOWN1]	= PCF50633_REG_DOWN1OUT,
+	[PCF50633_REGULATOR_DOWN2]	= PCF50633_REG_DOWN2OUT,
+	[PCF50633_REGULATOR_MEMLDO]	= PCF50633_REG_MEMLDOOUT,
+	[PCF50633_REGULATOR_LDO1]	= PCF50633_REG_LDO1OUT,
+	[PCF50633_REGULATOR_LDO2]	= PCF50633_REG_LDO2OUT,
+	[PCF50633_REGULATOR_LDO3]	= PCF50633_REG_LDO3OUT,
+	[PCF50633_REGULATOR_LDO4]	= PCF50633_REG_LDO4OUT,
+	[PCF50633_REGULATOR_LDO5]	= PCF50633_REG_LDO5OUT,
+	[PCF50633_REGULATOR_LDO6]	= PCF50633_REG_LDO6OUT,
+	[PCF50633_REGULATOR_HCLDO]	= PCF50633_REG_HCLDOOUT,
+};
+
+/* Bits from voltage value */
+static u8 auto_voltage_bits(unsigned int millivolts)
+{
+	if (millivolts < 1800)
+		return 0;
+	if (millivolts > 3800)
+		return 0xff;
+
+	millivolts -= 625;
+
+	return millivolts / 25;
+}
+
+static u8 down_voltage_bits(unsigned int millivolts)
+{
+	if (millivolts < 625)
+		return 0;
+	else if (millivolts > 3000)
+		return 0xff;
+
+	millivolts -= 625;
+
+	return millivolts / 25;
+}
+
+static u8 ldo_voltage_bits(unsigned int millivolts)
+{
+	if (millivolts < 900)
+		return 0;
+	else if (millivolts > 3600)
+		return 0x1f;
+
+	millivolts -= 900;
+	return millivolts / 100;
+}
+
+/* Obtain voltage value from bits */
+static unsigned int auto_voltage_value(u8 bits)
+{
+	if (bits < 0x2f)
+		return 0;
+
+	return 625 + (bits * 25);
+}
+
+
+static unsigned int down_voltage_value(u8 bits)
+{
+	return 625 + (bits * 25);
+}
+
+
+static unsigned int ldo_voltage_value(u8 bits)
+{
+	bits &= 0x1f;
+
+	return 900 + (bits * 100);
+}
+
+static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
+					  int min_uV, int max_uV,
+					  unsigned *selector)
+{
+	struct pcf50633 *pcf;
+	int regulator_id, millivolts;
+	u8 volt_bits, regnr;
+
+	pcf = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= PCF50633_NUM_REGULATORS)
+		return -EINVAL;
+
+	millivolts = min_uV / 1000;
+
+	regnr = pcf50633_regulator_registers[regulator_id];
+
+	switch (regulator_id) {
+	case PCF50633_REGULATOR_AUTO:
+		volt_bits = auto_voltage_bits(millivolts);
+		break;
+	case PCF50633_REGULATOR_DOWN1:
+		volt_bits = down_voltage_bits(millivolts);
+		break;
+	case PCF50633_REGULATOR_DOWN2:
+		volt_bits = down_voltage_bits(millivolts);
+		break;
+	case PCF50633_REGULATOR_LDO1:
+	case PCF50633_REGULATOR_LDO2:
+	case PCF50633_REGULATOR_LDO3:
+	case PCF50633_REGULATOR_LDO4:
+	case PCF50633_REGULATOR_LDO5:
+	case PCF50633_REGULATOR_LDO6:
+	case PCF50633_REGULATOR_HCLDO:
+	case PCF50633_REGULATOR_MEMLDO:
+		volt_bits = ldo_voltage_bits(millivolts);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*selector = volt_bits;
+
+	return pcf50633_reg_write(pcf, regnr, volt_bits);
+}
+
+static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id,
+						u8 bits)
+{
+	int millivolts;
+
+	switch (id) {
+	case PCF50633_REGULATOR_AUTO:
+		millivolts = auto_voltage_value(bits);
+		break;
+	case PCF50633_REGULATOR_DOWN1:
+		millivolts = down_voltage_value(bits);
+		break;
+	case PCF50633_REGULATOR_DOWN2:
+		millivolts = down_voltage_value(bits);
+		break;
+	case PCF50633_REGULATOR_LDO1:
+	case PCF50633_REGULATOR_LDO2:
+	case PCF50633_REGULATOR_LDO3:
+	case PCF50633_REGULATOR_LDO4:
+	case PCF50633_REGULATOR_LDO5:
+	case PCF50633_REGULATOR_LDO6:
+	case PCF50633_REGULATOR_HCLDO:
+	case PCF50633_REGULATOR_MEMLDO:
+		millivolts = ldo_voltage_value(bits);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return millivolts * 1000;
+}
+
+static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct pcf50633 *pcf;
+	int regulator_id;
+	u8 volt_bits, regnr;
+
+	pcf = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= PCF50633_NUM_REGULATORS)
+		return -EINVAL;
+
+	regnr = pcf50633_regulator_registers[regulator_id];
+
+	volt_bits = pcf50633_reg_read(pcf, regnr);
+
+	return pcf50633_regulator_voltage_value(regulator_id, volt_bits);
+}
+
+static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
+						unsigned int index)
+{
+	struct pcf50633 *pcf;
+	int regulator_id;
+
+	pcf = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+
+	switch (regulator_id) {
+	case PCF50633_REGULATOR_AUTO:
+		index += 0x2f;
+		break;
+	default:
+		break;
+	}
+
+	return pcf50633_regulator_voltage_value(regulator_id, index);
+}
+
+static int pcf50633_regulator_enable(struct regulator_dev *rdev)
+{
+	struct pcf50633 *pcf = rdev_get_drvdata(rdev);
+	int regulator_id;
+	u8 regnr;
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= PCF50633_NUM_REGULATORS)
+		return -EINVAL;
+
+	/* The *ENA register is always one after the *OUT register */
+	regnr = pcf50633_regulator_registers[regulator_id] + 1;
+
+	return pcf50633_reg_set_bit_mask(pcf, regnr, PCF50633_REGULATOR_ON,
+						       PCF50633_REGULATOR_ON);
+}
+
+static int pcf50633_regulator_disable(struct regulator_dev *rdev)
+{
+	struct pcf50633 *pcf = rdev_get_drvdata(rdev);
+	int regulator_id;
+	u8 regnr;
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= PCF50633_NUM_REGULATORS)
+		return -EINVAL;
+
+	/* the *ENA register is always one after the *OUT register */
+	regnr = pcf50633_regulator_registers[regulator_id] + 1;
+
+	return pcf50633_reg_set_bit_mask(pcf, regnr,
+					PCF50633_REGULATOR_ON, 0);
+}
+
+static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct pcf50633 *pcf = rdev_get_drvdata(rdev);
+	int regulator_id = rdev_get_id(rdev);
+	u8 regnr;
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= PCF50633_NUM_REGULATORS)
+		return -EINVAL;
+
+	/* the *ENA register is always one after the *OUT register */
+	regnr = pcf50633_regulator_registers[regulator_id] + 1;
+
+	return pcf50633_reg_read(pcf, regnr) & PCF50633_REGULATOR_ON;
+}
+
+static struct regulator_ops pcf50633_regulator_ops = {
+	.set_voltage = pcf50633_regulator_set_voltage,
+	.get_voltage = pcf50633_regulator_get_voltage,
+	.list_voltage = pcf50633_regulator_list_voltage,
+	.enable = pcf50633_regulator_enable,
+	.disable = pcf50633_regulator_disable,
+	.is_enabled = pcf50633_regulator_is_enabled,
+};
+
+static struct regulator_desc regulators[] = {
+	[PCF50633_REGULATOR_AUTO] =
+		PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO, 81),
+	[PCF50633_REGULATOR_DOWN1] =
+		PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1, 96),
+	[PCF50633_REGULATOR_DOWN2] =
+		PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2, 96),
+	[PCF50633_REGULATOR_LDO1] =
+		PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1, 28),
+	[PCF50633_REGULATOR_LDO2] =
+		PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2, 28),
+	[PCF50633_REGULATOR_LDO3] =
+		PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3, 28),
+	[PCF50633_REGULATOR_LDO4] =
+		PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4, 28),
+	[PCF50633_REGULATOR_LDO5] =
+		PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5, 28),
+	[PCF50633_REGULATOR_LDO6] =
+		PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6, 28),
+	[PCF50633_REGULATOR_HCLDO] =
+		PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO, 28),
+	[PCF50633_REGULATOR_MEMLDO] =
+		PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO, 28),
+};
+
+static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev;
+	struct pcf50633 *pcf;
+
+	/* Already set by core driver */
+	pcf = dev_to_pcf50633(pdev->dev.parent);
+
+	rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
+				  pdev->dev.platform_data, pcf, NULL);
+	if (IS_ERR(rdev))
+		return PTR_ERR(rdev);
+
+	platform_set_drvdata(pdev, rdev);
+
+	if (pcf->pdata->regulator_registered)
+		pcf->pdata->regulator_registered(pcf, pdev->id);
+
+	return 0;
+}
+
+static int __devexit pcf50633_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	regulator_unregister(rdev);
+
+	return 0;
+}
+
+static struct platform_driver pcf50633_regulator_driver = {
+	.driver = {
+		.name = "pcf50633-regltr",
+	},
+	.probe = pcf50633_regulator_probe,
+	.remove = __devexit_p(pcf50633_regulator_remove),
+};
+
+static int __init pcf50633_regulator_init(void)
+{
+	return platform_driver_register(&pcf50633_regulator_driver);
+}
+subsys_initcall(pcf50633_regulator_init);
+
+static void __exit pcf50633_regulator_exit(void)
+{
+	platform_driver_unregister(&pcf50633_regulator_driver);
+}
+module_exit(pcf50633_regulator_exit);
+
+MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
+MODULE_DESCRIPTION("PCF50633 regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcf50633-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/s5m8767.c b/ap/os/linux/linux-3.4.x/drivers/regulator/s5m8767.c
new file mode 100644
index 0000000..4ca2db0
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/s5m8767.c
@@ -0,0 +1,790 @@
+/*
+ * s5m8767.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/s5m87xx/s5m-core.h>
+#include <linux/mfd/s5m87xx/s5m-pmic.h>
+
+struct s5m8767_info {
+	struct device *dev;
+	struct s5m87xx_dev *iodev;
+	int num_regulators;
+	struct regulator_dev **rdev;
+
+	int ramp_delay;
+	bool buck2_ramp;
+	bool buck3_ramp;
+	bool buck4_ramp;
+
+	bool buck2_gpiodvs;
+	bool buck3_gpiodvs;
+	bool buck4_gpiodvs;
+	u8 buck2_vol[8];
+	u8 buck3_vol[8];
+	u8 buck4_vol[8];
+	int buck_gpios[3];
+	int buck_gpioindex;
+};
+
+struct s5m_voltage_desc {
+	int max;
+	int min;
+	int step;
+};
+
+static const struct s5m_voltage_desc buck_voltage_val1 = {
+	.max = 2225000,
+	.min =  650000,
+	.step =   6250,
+};
+
+static const struct s5m_voltage_desc buck_voltage_val2 = {
+	.max = 1600000,
+	.min =  600000,
+	.step =   6250,
+};
+
+static const struct s5m_voltage_desc buck_voltage_val3 = {
+	.max = 3000000,
+	.min =  750000,
+	.step =  12500,
+};
+
+static const struct s5m_voltage_desc ldo_voltage_val1 = {
+	.max = 3950000,
+	.min =  800000,
+	.step =  50000,
+};
+
+static const struct s5m_voltage_desc ldo_voltage_val2 = {
+	.max = 2375000,
+	.min =  800000,
+	.step =  25000,
+};
+
+static const struct s5m_voltage_desc *reg_voltage_map[] = {
+	[S5M8767_LDO1] = &ldo_voltage_val2,
+	[S5M8767_LDO2] = &ldo_voltage_val2,
+	[S5M8767_LDO3] = &ldo_voltage_val1,
+	[S5M8767_LDO4] = &ldo_voltage_val1,
+	[S5M8767_LDO5] = &ldo_voltage_val1,
+	[S5M8767_LDO6] = &ldo_voltage_val2,
+	[S5M8767_LDO7] = &ldo_voltage_val2,
+	[S5M8767_LDO8] = &ldo_voltage_val2,
+	[S5M8767_LDO9] = &ldo_voltage_val1,
+	[S5M8767_LDO10] = &ldo_voltage_val1,
+	[S5M8767_LDO11] = &ldo_voltage_val1,
+	[S5M8767_LDO12] = &ldo_voltage_val1,
+	[S5M8767_LDO13] = &ldo_voltage_val1,
+	[S5M8767_LDO14] = &ldo_voltage_val1,
+	[S5M8767_LDO15] = &ldo_voltage_val2,
+	[S5M8767_LDO16] = &ldo_voltage_val1,
+	[S5M8767_LDO17] = &ldo_voltage_val1,
+	[S5M8767_LDO18] = &ldo_voltage_val1,
+	[S5M8767_LDO19] = &ldo_voltage_val1,
+	[S5M8767_LDO20] = &ldo_voltage_val1,
+	[S5M8767_LDO21] = &ldo_voltage_val1,
+	[S5M8767_LDO22] = &ldo_voltage_val1,
+	[S5M8767_LDO23] = &ldo_voltage_val1,
+	[S5M8767_LDO24] = &ldo_voltage_val1,
+	[S5M8767_LDO25] = &ldo_voltage_val1,
+	[S5M8767_LDO26] = &ldo_voltage_val1,
+	[S5M8767_LDO27] = &ldo_voltage_val1,
+	[S5M8767_LDO28] = &ldo_voltage_val1,
+	[S5M8767_BUCK1] = &buck_voltage_val1,
+	[S5M8767_BUCK2] = &buck_voltage_val2,
+	[S5M8767_BUCK3] = &buck_voltage_val2,
+	[S5M8767_BUCK4] = &buck_voltage_val2,
+	[S5M8767_BUCK5] = &buck_voltage_val1,
+	[S5M8767_BUCK6] = &buck_voltage_val1,
+	[S5M8767_BUCK7] = NULL,
+	[S5M8767_BUCK8] = NULL,
+	[S5M8767_BUCK9] = &buck_voltage_val3,
+};
+
+static int s5m8767_list_voltage(struct regulator_dev *rdev,
+				unsigned int selector)
+{
+	const struct s5m_voltage_desc *desc;
+	int reg_id = rdev_get_id(rdev);
+	int val;
+
+	if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0)
+		return -EINVAL;
+
+	desc = reg_voltage_map[reg_id];
+	if (desc == NULL)
+		return -EINVAL;
+
+	val = desc->min + desc->step * selector;
+	if (val > desc->max)
+		return -EINVAL;
+
+	return val;
+}
+
+static int s5m8767_get_register(struct regulator_dev *rdev, int *reg)
+{
+	int reg_id = rdev_get_id(rdev);
+
+	switch (reg_id) {
+	case S5M8767_LDO1 ... S5M8767_LDO2:
+		*reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
+		break;
+	case S5M8767_LDO3 ... S5M8767_LDO28:
+		*reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
+		break;
+	case S5M8767_BUCK1:
+		*reg = S5M8767_REG_BUCK1CTRL1;
+		break;
+	case S5M8767_BUCK2 ... S5M8767_BUCK4:
+		*reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9;
+		break;
+	case S5M8767_BUCK5:
+		*reg = S5M8767_REG_BUCK5CTRL1;
+		break;
+	case S5M8767_BUCK6 ... S5M8767_BUCK9:
+		*reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
+{
+	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+	int ret, reg;
+	int mask = 0xc0, pattern = 0xc0;
+	u8 val;
+
+	ret = s5m8767_get_register(rdev, &reg);
+	if (ret == -EINVAL)
+		return 1;
+	else if (ret)
+		return ret;
+
+	ret = s5m_reg_read(s5m8767->iodev, reg, &val);
+	if (ret)
+		return ret;
+
+	return (val & mask) == pattern;
+}
+
+static int s5m8767_reg_enable(struct regulator_dev *rdev)
+{
+	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+	int ret, reg;
+	int mask = 0xc0, pattern = 0xc0;
+
+	ret = s5m8767_get_register(rdev, &reg);
+	if (ret)
+		return ret;
+
+	return s5m_reg_update(s5m8767->iodev, reg, pattern, mask);
+}
+
+static int s5m8767_reg_disable(struct regulator_dev *rdev)
+{
+	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+	int ret, reg;
+	int  mask = 0xc0, pattern = 0xc0;
+
+	ret = s5m8767_get_register(rdev, &reg);
+	if (ret)
+		return ret;
+
+	return s5m_reg_update(s5m8767->iodev, reg, ~pattern, mask);
+}
+
+static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
+{
+	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+	int reg_id = rdev_get_id(rdev);
+	int reg;
+
+	switch (reg_id) {
+	case S5M8767_LDO1 ... S5M8767_LDO2:
+		reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
+		break;
+	case S5M8767_LDO3 ... S5M8767_LDO28:
+		reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
+		break;
+	case S5M8767_BUCK1:
+		reg = S5M8767_REG_BUCK1CTRL2;
+		break;
+	case S5M8767_BUCK2:
+		reg = S5M8767_REG_BUCK2DVS1;
+		if (s5m8767->buck2_gpiodvs)
+			reg += s5m8767->buck_gpioindex;
+		break;
+	case S5M8767_BUCK3:
+		reg = S5M8767_REG_BUCK3DVS1;
+		if (s5m8767->buck3_gpiodvs)
+			reg += s5m8767->buck_gpioindex;
+		break;
+	case S5M8767_BUCK4:
+		reg = S5M8767_REG_BUCK4DVS1;
+		if (s5m8767->buck4_gpiodvs)
+			reg += s5m8767->buck_gpioindex;
+		break;
+	case S5M8767_BUCK5:
+		reg = S5M8767_REG_BUCK5CTRL2;
+		break;
+	case S5M8767_BUCK6 ... S5M8767_BUCK9:
+		reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_reg = reg;
+
+	return 0;
+}
+
+static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+	int reg, mask, ret;
+	int reg_id = rdev_get_id(rdev);
+	u8 val;
+
+	ret = s5m8767_get_voltage_register(rdev, &reg);
+	if (ret)
+		return ret;
+
+	mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff;
+
+	ret = s5m_reg_read(s5m8767->iodev, reg, &val);
+	if (ret)
+		return ret;
+
+	val &= mask;
+
+	return val;
+}
+
+static int s5m8767_convert_voltage_to_sel(
+		const struct s5m_voltage_desc *desc,
+		int min_vol, int max_vol)
+{
+	int selector = 0;
+
+	if (desc == NULL)
+		return -EINVAL;
+
+	if (max_vol < desc->min || min_vol > desc->max)
+		return -EINVAL;
+
+	selector = (min_vol - desc->min) / desc->step;
+
+	if (desc->min + desc->step * selector > max_vol)
+		return -EINVAL;
+
+	return selector;
+}
+
+static int s5m8767_set_voltage(struct regulator_dev *rdev,
+				int min_uV, int max_uV, unsigned *selector)
+{
+	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+	const struct s5m_voltage_desc *desc;
+	int reg_id = rdev_get_id(rdev);
+	int sel, reg, mask, ret;
+	u8 val;
+
+	switch (reg_id) {
+	case S5M8767_LDO1 ... S5M8767_LDO28:
+		mask = 0x3f;
+		break;
+	case S5M8767_BUCK1 ... S5M8767_BUCK6:
+		mask = 0xff;
+		break;
+	case S5M8767_BUCK7 ... S5M8767_BUCK8:
+		return -EINVAL;
+	case S5M8767_BUCK9:
+		mask = 0xff;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	desc = reg_voltage_map[reg_id];
+
+	sel = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
+	if (sel < 0)
+		return sel;
+
+	ret = s5m8767_get_voltage_register(rdev, &reg);
+	if (ret)
+		return ret;
+
+	s5m_reg_read(s5m8767->iodev, reg, &val);
+	val &= ~mask;
+	val |= sel;
+
+	ret = s5m_reg_write(s5m8767->iodev, reg, val);
+	*selector = sel;
+
+	return ret;
+}
+
+static inline void s5m8767_set_high(struct s5m8767_info *s5m8767)
+{
+	int temp_index = s5m8767->buck_gpioindex;
+
+	gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
+	gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
+	gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
+}
+
+static inline void s5m8767_set_low(struct s5m8767_info *s5m8767)
+{
+	int temp_index = s5m8767->buck_gpioindex;
+
+	gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
+	gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
+	gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
+}
+
+static int s5m8767_set_voltage_buck(struct regulator_dev *rdev,
+				    int min_uV, int max_uV, unsigned *selector)
+{
+	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+	int reg_id = rdev_get_id(rdev);
+	const struct s5m_voltage_desc *desc;
+	int new_val, old_val, i = 0;
+
+	if (reg_id < S5M8767_BUCK1 || reg_id > S5M8767_BUCK6)
+		return -EINVAL;
+
+	switch (reg_id) {
+	case S5M8767_BUCK1:
+		return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
+	case S5M8767_BUCK2 ... S5M8767_BUCK4:
+		break;
+	case S5M8767_BUCK5 ... S5M8767_BUCK6:
+		return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
+	case S5M8767_BUCK9:
+		return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
+	}
+
+	desc = reg_voltage_map[reg_id];
+	new_val = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
+	if (new_val < 0)
+		return new_val;
+
+	switch (reg_id) {
+	case S5M8767_BUCK2:
+		if (s5m8767->buck2_gpiodvs) {
+			while (s5m8767->buck2_vol[i] != new_val)
+				i++;
+		} else
+			return s5m8767_set_voltage(rdev, min_uV,
+						   max_uV, selector);
+		break;
+	case S5M8767_BUCK3:
+		if (s5m8767->buck3_gpiodvs) {
+			while (s5m8767->buck3_vol[i] != new_val)
+				i++;
+		} else
+			return s5m8767_set_voltage(rdev, min_uV,
+						   max_uV, selector);
+		break;
+	case S5M8767_BUCK4:
+		if (s5m8767->buck3_gpiodvs) {
+			while (s5m8767->buck4_vol[i] != new_val)
+				i++;
+		} else
+			return s5m8767_set_voltage(rdev, min_uV,
+						   max_uV, selector);
+		break;
+	}
+
+	old_val = s5m8767->buck_gpioindex;
+	s5m8767->buck_gpioindex = i;
+
+	if (i > old_val)
+		s5m8767_set_high(s5m8767);
+	else
+		s5m8767_set_low(s5m8767);
+
+	*selector = new_val;
+	return 0;
+}
+
+static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
+					     unsigned int old_sel,
+					     unsigned int new_sel)
+{
+	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
+	const struct s5m_voltage_desc *desc;
+	int reg_id = rdev_get_id(rdev);
+
+	desc = reg_voltage_map[reg_id];
+
+	if (old_sel < new_sel)
+		return DIV_ROUND_UP(desc->step * (new_sel - old_sel),
+					s5m8767->ramp_delay * 1000);
+	return 0;
+}
+
+static struct regulator_ops s5m8767_ldo_ops = {
+	.list_voltage		= s5m8767_list_voltage,
+	.is_enabled		= s5m8767_reg_is_enabled,
+	.enable			= s5m8767_reg_enable,
+	.disable		= s5m8767_reg_disable,
+	.get_voltage_sel	= s5m8767_get_voltage_sel,
+	.set_voltage		= s5m8767_set_voltage,
+	.set_voltage_time_sel	= s5m8767_set_voltage_time_sel,
+};
+
+static struct regulator_ops s5m8767_buck_ops = {
+	.list_voltage		= s5m8767_list_voltage,
+	.is_enabled		= s5m8767_reg_is_enabled,
+	.enable			= s5m8767_reg_enable,
+	.disable		= s5m8767_reg_disable,
+	.get_voltage_sel	= s5m8767_get_voltage_sel,
+	.set_voltage		= s5m8767_set_voltage_buck,
+	.set_voltage_time_sel	= s5m8767_set_voltage_time_sel,
+};
+
+#define regulator_desc_ldo(num)		{	\
+	.name		= "LDO"#num,		\
+	.id		= S5M8767_LDO##num,	\
+	.ops		= &s5m8767_ldo_ops,	\
+	.type		= REGULATOR_VOLTAGE,	\
+	.owner		= THIS_MODULE,		\
+}
+#define regulator_desc_buck(num)	{	\
+	.name		= "BUCK"#num,		\
+	.id		= S5M8767_BUCK##num,	\
+	.ops		= &s5m8767_buck_ops,	\
+	.type		= REGULATOR_VOLTAGE,	\
+	.owner		= THIS_MODULE,		\
+}
+
+static struct regulator_desc regulators[] = {
+	regulator_desc_ldo(1),
+	regulator_desc_ldo(2),
+	regulator_desc_ldo(3),
+	regulator_desc_ldo(4),
+	regulator_desc_ldo(5),
+	regulator_desc_ldo(6),
+	regulator_desc_ldo(7),
+	regulator_desc_ldo(8),
+	regulator_desc_ldo(9),
+	regulator_desc_ldo(10),
+	regulator_desc_ldo(11),
+	regulator_desc_ldo(12),
+	regulator_desc_ldo(13),
+	regulator_desc_ldo(14),
+	regulator_desc_ldo(15),
+	regulator_desc_ldo(16),
+	regulator_desc_ldo(17),
+	regulator_desc_ldo(18),
+	regulator_desc_ldo(19),
+	regulator_desc_ldo(20),
+	regulator_desc_ldo(21),
+	regulator_desc_ldo(22),
+	regulator_desc_ldo(23),
+	regulator_desc_ldo(24),
+	regulator_desc_ldo(25),
+	regulator_desc_ldo(26),
+	regulator_desc_ldo(27),
+	regulator_desc_ldo(28),
+	regulator_desc_buck(1),
+	regulator_desc_buck(2),
+	regulator_desc_buck(3),
+	regulator_desc_buck(4),
+	regulator_desc_buck(5),
+	regulator_desc_buck(6),
+	regulator_desc_buck(7),
+	regulator_desc_buck(8),
+	regulator_desc_buck(9),
+};
+
+static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
+{
+	struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct regulator_dev **rdev;
+	struct s5m8767_info *s5m8767;
+	int i, ret, size;
+
+	if (!pdata) {
+		dev_err(pdev->dev.parent, "Platform data not supplied\n");
+		return -ENODEV;
+	}
+
+	if (pdata->buck2_gpiodvs) {
+		if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
+			dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
+			return -EINVAL;
+		}
+	}
+
+	if (pdata->buck3_gpiodvs) {
+		if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) {
+			dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
+			return -EINVAL;
+		}
+	}
+
+	if (pdata->buck4_gpiodvs) {
+		if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) {
+			dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
+			return -EINVAL;
+		}
+	}
+
+	s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info),
+				GFP_KERNEL);
+	if (!s5m8767)
+		return -ENOMEM;
+
+	size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2);
+	s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+	if (!s5m8767->rdev)
+		return -ENOMEM;
+
+	rdev = s5m8767->rdev;
+	s5m8767->dev = &pdev->dev;
+	s5m8767->iodev = iodev;
+	s5m8767->num_regulators = S5M8767_REG_MAX - 2;
+	platform_set_drvdata(pdev, s5m8767);
+
+	s5m8767->buck_gpioindex = pdata->buck_default_idx;
+	s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs;
+	s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs;
+	s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs;
+	s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
+	s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
+	s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
+	s5m8767->ramp_delay = pdata->buck_ramp_delay;
+	s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
+	s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
+	s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
+
+	for (i = 0; i < 8; i++) {
+		if (s5m8767->buck2_gpiodvs) {
+			s5m8767->buck2_vol[i] =
+				s5m8767_convert_voltage_to_sel(
+						&buck_voltage_val2,
+						pdata->buck2_voltage[i],
+						pdata->buck2_voltage[i] +
+						buck_voltage_val2.step);
+		}
+
+		if (s5m8767->buck3_gpiodvs) {
+			s5m8767->buck3_vol[i] =
+				s5m8767_convert_voltage_to_sel(
+						&buck_voltage_val2,
+						pdata->buck3_voltage[i],
+						pdata->buck3_voltage[i] +
+						buck_voltage_val2.step);
+		}
+
+		if (s5m8767->buck4_gpiodvs) {
+			s5m8767->buck4_vol[i] =
+				s5m8767_convert_voltage_to_sel(
+						&buck_voltage_val2,
+						pdata->buck4_voltage[i],
+						pdata->buck4_voltage[i] +
+						buck_voltage_val2.step);
+		}
+	}
+
+	if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
+		pdata->buck4_gpiodvs) {
+		if (gpio_is_valid(pdata->buck_gpios[0]) &&
+			gpio_is_valid(pdata->buck_gpios[1]) &&
+			gpio_is_valid(pdata->buck_gpios[2])) {
+			ret = gpio_request(pdata->buck_gpios[0],
+						"S5M8767 SET1");
+			if (ret == -EBUSY)
+				dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n");
+
+			ret = gpio_request(pdata->buck_gpios[1],
+					   "S5M8767 SET2");
+			if (ret == -EBUSY)
+				dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n");
+
+			ret = gpio_request(pdata->buck_gpios[2],
+					   "S5M8767 SET3");
+			if (ret == -EBUSY)
+				dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n");
+			/* SET1 GPIO */
+			gpio_direction_output(pdata->buck_gpios[0],
+					(s5m8767->buck_gpioindex >> 2) & 0x1);
+			/* SET2 GPIO */
+			gpio_direction_output(pdata->buck_gpios[1],
+					(s5m8767->buck_gpioindex >> 1) & 0x1);
+			/* SET3 GPIO */
+			gpio_direction_output(pdata->buck_gpios[2],
+					(s5m8767->buck_gpioindex >> 0) & 0x1);
+			ret = 0;
+		} else {
+			dev_err(&pdev->dev, "GPIO NOT VALID\n");
+			ret = -EINVAL;
+			return ret;
+		}
+	}
+
+	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
+			(pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
+	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
+			(pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
+	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
+			(pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
+
+	/* Initialize GPIO DVS registers */
+	for (i = 0; i < 8; i++) {
+		if (s5m8767->buck2_gpiodvs) {
+			s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i,
+					   s5m8767->buck2_vol[i]);
+		}
+
+		if (s5m8767->buck3_gpiodvs) {
+			s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i,
+					   s5m8767->buck3_vol[i]);
+		}
+
+		if (s5m8767->buck4_gpiodvs) {
+			s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i,
+					   s5m8767->buck4_vol[i]);
+		}
+	}
+	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, 0x78, 0xff);
+	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, 0x58, 0xff);
+	s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, 0x78, 0xff);
+
+	if (s5m8767->buck2_ramp)
+		s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08);
+
+	if (s5m8767->buck3_ramp)
+		s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04);
+
+	if (s5m8767->buck4_ramp)
+		s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02);
+
+	if (s5m8767->buck2_ramp || s5m8767->buck3_ramp
+		|| s5m8767->buck4_ramp) {
+		switch (s5m8767->ramp_delay) {
+		case 15:
+			s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+					0xc0, 0xf0);
+			break;
+		case 25:
+			s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+					0xd0, 0xf0);
+			break;
+		case 50:
+			s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+					0xe0, 0xf0);
+			break;
+		case 100:
+			s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+					0xf0, 0xf0);
+			break;
+		default:
+			s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+					0x90, 0xf0);
+		}
+	}
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		const struct s5m_voltage_desc *desc;
+		int id = pdata->regulators[i].id;
+
+		desc = reg_voltage_map[id];
+		if (desc)
+			regulators[id].n_voltages =
+				(desc->max - desc->min) / desc->step + 1;
+
+		rdev[i] = regulator_register(&regulators[id], s5m8767->dev,
+				pdata->regulators[i].initdata, s5m8767, NULL);
+		if (IS_ERR(rdev[i])) {
+			ret = PTR_ERR(rdev[i]);
+			dev_err(s5m8767->dev, "regulator init failed for %d\n",
+					id);
+			rdev[i] = NULL;
+			goto err;
+		}
+	}
+
+	return 0;
+err:
+	for (i = 0; i < s5m8767->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+	return ret;
+}
+
+static int __devexit s5m8767_pmic_remove(struct platform_device *pdev)
+{
+	struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev);
+	struct regulator_dev **rdev = s5m8767->rdev;
+	int i;
+
+	for (i = 0; i < s5m8767->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+	return 0;
+}
+
+static const struct platform_device_id s5m8767_pmic_id[] = {
+	{ "s5m8767-pmic", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id);
+
+static struct platform_driver s5m8767_pmic_driver = {
+	.driver = {
+		.name = "s5m8767-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = s5m8767_pmic_probe,
+	.remove = __devexit_p(s5m8767_pmic_remove),
+	.id_table = s5m8767_pmic_id,
+};
+
+static int __init s5m8767_pmic_init(void)
+{
+	return platform_driver_register(&s5m8767_pmic_driver);
+}
+subsys_initcall(s5m8767_pmic_init);
+
+static void __exit s5m8767_pmic_exit(void)
+{
+	platform_driver_unregister(&s5m8767_pmic_driver);
+}
+module_exit(s5m8767_pmic_exit);
+
+/* Module information */
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/tps6105x-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/tps6105x-regulator.c
new file mode 100644
index 0000000..d9278da
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/tps6105x-regulator.c
@@ -0,0 +1,198 @@
+/*
+ * Driver for TPS61050/61052 boost converters, typically used for white LEDs
+ * or audio amplifiers.
+ *
+ * Copyright (C) 2011 ST-Ericsson SA
+ * Written on behalf of Linaro for ST-Ericsson
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps6105x.h>
+
+static const int tps6105x_voltages[] = {
+	4500000,
+	5000000,
+	5250000,
+	5000000, /* There is an additional 5V */
+};
+
+static int tps6105x_regulator_enable(struct regulator_dev *rdev)
+{
+	struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+	int ret;
+
+	/* Activate voltage mode */
+	ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
+		TPS6105X_REG0_MODE_MASK,
+		TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int tps6105x_regulator_disable(struct regulator_dev *rdev)
+{
+	struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+	int ret;
+
+	/* Set into shutdown mode */
+	ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
+		TPS6105X_REG0_MODE_MASK,
+		TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+	u8 regval;
+	int ret;
+
+	ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
+	if (ret)
+		return ret;
+	regval &= TPS6105X_REG0_MODE_MASK;
+	regval >>= TPS6105X_REG0_MODE_SHIFT;
+
+	if (regval == TPS6105X_REG0_MODE_VOLTAGE)
+		return 1;
+
+	return 0;
+}
+
+static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+	u8 regval;
+	int ret;
+
+	ret = tps6105x_get(tps6105x, TPS6105X_REG_0, &regval);
+	if (ret)
+		return ret;
+
+	regval &= TPS6105X_REG0_VOLTAGE_MASK;
+	regval >>= TPS6105X_REG0_VOLTAGE_SHIFT;
+	return (int) regval;
+}
+
+static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
+					      unsigned selector)
+{
+	struct tps6105x *tps6105x = rdev_get_drvdata(rdev);
+	int ret;
+
+	ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0,
+				    TPS6105X_REG0_VOLTAGE_MASK,
+				    selector << TPS6105X_REG0_VOLTAGE_SHIFT);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int tps6105x_regulator_list_voltage(struct regulator_dev *rdev,
+					   unsigned selector)
+{
+	if (selector >= ARRAY_SIZE(tps6105x_voltages))
+		return -EINVAL;
+
+	return tps6105x_voltages[selector];
+}
+
+static struct regulator_ops tps6105x_regulator_ops = {
+	.enable		= tps6105x_regulator_enable,
+	.disable	= tps6105x_regulator_disable,
+	.is_enabled	= tps6105x_regulator_is_enabled,
+	.get_voltage_sel = tps6105x_regulator_get_voltage_sel,
+	.set_voltage_sel = tps6105x_regulator_set_voltage_sel,
+	.list_voltage	= tps6105x_regulator_list_voltage,
+};
+
+static struct regulator_desc tps6105x_regulator_desc = {
+	.name		= "tps6105x-boost",
+	.ops		= &tps6105x_regulator_ops,
+	.type		= REGULATOR_VOLTAGE,
+	.id		= 0,
+	.owner		= THIS_MODULE,
+	.n_voltages	= ARRAY_SIZE(tps6105x_voltages),
+};
+
+/*
+ * Registers the chip as a voltage regulator
+ */
+static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
+{
+	struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
+	struct tps6105x_platform_data *pdata = tps6105x->pdata;
+	int ret;
+
+	/* This instance is not set for regulator mode so bail out */
+	if (pdata->mode != TPS6105X_MODE_VOLTAGE) {
+		dev_info(&pdev->dev,
+			 "chip not in voltage mode mode, exit probe \n");
+		return 0;
+	}
+
+	/* Register regulator with framework */
+	tps6105x->regulator = regulator_register(&tps6105x_regulator_desc,
+					     &tps6105x->client->dev,
+					     pdata->regulator_data, tps6105x,
+					     NULL);
+	if (IS_ERR(tps6105x->regulator)) {
+		ret = PTR_ERR(tps6105x->regulator);
+		dev_err(&tps6105x->client->dev,
+			"failed to register regulator\n");
+		return ret;
+	}
+	platform_set_drvdata(pdev, tps6105x);
+
+	return 0;
+}
+
+static int __devexit tps6105x_regulator_remove(struct platform_device *pdev)
+{
+	struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
+	regulator_unregister(tps6105x->regulator);
+	return 0;
+}
+
+static struct platform_driver tps6105x_regulator_driver = {
+	.driver = {
+		.name  = "tps6105x-regulator",
+		.owner = THIS_MODULE,
+	},
+	.probe = tps6105x_regulator_probe,
+	.remove = __devexit_p(tps6105x_regulator_remove),
+};
+
+static __init int tps6105x_regulator_init(void)
+{
+	return platform_driver_register(&tps6105x_regulator_driver);
+}
+subsys_initcall(tps6105x_regulator_init);
+
+static __exit void tps6105x_regulator_exit(void)
+{
+	platform_driver_unregister(&tps6105x_regulator_driver);
+}
+module_exit(tps6105x_regulator_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("TPS6105x regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps6105x-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/tps62360-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/tps62360-regulator.c
new file mode 100644
index 0000000..e2ec730
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/tps62360-regulator.c
@@ -0,0 +1,472 @@
+/*
+ * tps62360.c -- TI tps62360
+ *
+ * Driver for processor core supply tps62360 and tps62361B
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/tps62360.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+/* Register definitions */
+#define REG_VSET0		0
+#define REG_VSET1		1
+#define REG_VSET2		2
+#define REG_VSET3		3
+#define REG_CONTROL		4
+#define REG_TEMP		5
+#define REG_RAMPCTRL		6
+#define REG_CHIPID		8
+
+enum chips {TPS62360, TPS62361};
+
+#define TPS62360_BASE_VOLTAGE	770
+#define TPS62360_N_VOLTAGES	64
+
+#define TPS62361_BASE_VOLTAGE	500
+#define TPS62361_N_VOLTAGES	128
+
+/* tps 62360 chip information */
+struct tps62360_chip {
+	const char *name;
+	struct device *dev;
+	struct regulator_desc desc;
+	struct i2c_client *client;
+	struct regulator_dev *rdev;
+	struct regmap *regmap;
+	int chip_id;
+	int vsel0_gpio;
+	int vsel1_gpio;
+	int voltage_base;
+	u8 voltage_reg_mask;
+	bool en_internal_pulldn;
+	bool en_force_pwm;
+	bool en_discharge;
+	bool valid_gpios;
+	int lru_index[4];
+	int curr_vset_vsel[4];
+	int curr_vset_id;
+};
+
+/*
+ * find_voltage_set_register: Find new voltage configuration register
+ * (VSET) id.
+ * The finding of the new VSET register will be based on the LRU mechanism.
+ * Each VSET register will have different voltage configured . This
+ * Function will look if any of the VSET register have requested voltage set
+ * or not.
+ *     - If it is already there then it will make that register as most
+ *       recently used and return as found so that caller need not to set
+ *       the VSET register but need to set the proper gpios to select this
+ *       VSET register.
+ *     - If requested voltage is not found then it will use the least
+ *       recently mechanism to get new VSET register for new configuration
+ *       and will return not_found so that caller need to set new VSET
+ *       register and then gpios (both).
+ */
+static bool find_voltage_set_register(struct tps62360_chip *tps,
+		int req_vsel, int *vset_reg_id)
+{
+	int i;
+	bool found = false;
+	int new_vset_reg = tps->lru_index[3];
+	int found_index = 3;
+	for (i = 0; i < 4; ++i) {
+		if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) {
+			new_vset_reg = tps->lru_index[i];
+			found_index = i;
+			found = true;
+			goto update_lru_index;
+		}
+	}
+
+update_lru_index:
+	for (i = found_index; i > 0; i--)
+		tps->lru_index[i] = tps->lru_index[i - 1];
+
+	tps->lru_index[0] = new_vset_reg;
+	*vset_reg_id = new_vset_reg;
+	return found;
+}
+
+static int tps62360_dcdc_get_voltage(struct regulator_dev *dev)
+{
+	struct tps62360_chip *tps = rdev_get_drvdata(dev);
+	int vsel;
+	unsigned int data;
+	int ret;
+
+	ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data);
+	if (ret < 0) {
+		dev_err(tps->dev, "%s: Error in reading register %d\n",
+			__func__, REG_VSET0 + tps->curr_vset_id);
+		return ret;
+	}
+	vsel = (int)data & tps->voltage_reg_mask;
+	return (tps->voltage_base + vsel * 10) * 1000;
+}
+
+static int tps62360_dcdc_set_voltage(struct regulator_dev *dev,
+	     int min_uV, int max_uV, unsigned *selector)
+{
+	struct tps62360_chip *tps = rdev_get_drvdata(dev);
+	int vsel;
+	int ret;
+	bool found = false;
+	int new_vset_id = tps->curr_vset_id;
+
+	if (max_uV < min_uV)
+		return -EINVAL;
+
+	if (min_uV >
+		((tps->voltage_base + (tps->desc.n_voltages - 1) * 10) * 1000))
+		return -EINVAL;
+
+	if (max_uV < tps->voltage_base * 1000)
+		return -EINVAL;
+
+	vsel = DIV_ROUND_UP(min_uV - (tps->voltage_base * 1000), 10000);
+	if (selector)
+		*selector = (vsel & tps->voltage_reg_mask);
+
+	/*
+	 * If gpios are available to select the VSET register then least
+	 * recently used register for new configuration.
+	 */
+	if (tps->valid_gpios)
+		found = find_voltage_set_register(tps, vsel, &new_vset_id);
+
+	if (!found) {
+		ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id,
+				tps->voltage_reg_mask, vsel);
+		if (ret < 0) {
+			dev_err(tps->dev, "%s: Error in updating register %d\n",
+				 __func__, REG_VSET0 + new_vset_id);
+			return ret;
+		}
+		tps->curr_vset_id = new_vset_id;
+		tps->curr_vset_vsel[new_vset_id] = vsel;
+	}
+
+	/* Select proper VSET register vio gpios */
+	if (tps->valid_gpios) {
+		gpio_set_value_cansleep(tps->vsel0_gpio,
+					new_vset_id & 0x1);
+		gpio_set_value_cansleep(tps->vsel1_gpio,
+					(new_vset_id >> 1) & 0x1);
+	}
+	return 0;
+}
+
+static int tps62360_dcdc_list_voltage(struct regulator_dev *dev,
+					unsigned selector)
+{
+	struct tps62360_chip *tps = rdev_get_drvdata(dev);
+
+	if (selector >= tps->desc.n_voltages)
+		return -EINVAL;
+	return (tps->voltage_base + selector * 10) * 1000;
+}
+
+static struct regulator_ops tps62360_dcdc_ops = {
+	.get_voltage = tps62360_dcdc_get_voltage,
+	.set_voltage = tps62360_dcdc_set_voltage,
+	.list_voltage = tps62360_dcdc_list_voltage,
+};
+
+static int tps62360_init_force_pwm(struct tps62360_chip *tps,
+	struct tps62360_regulator_platform_data *pdata,
+	int vset_id)
+{
+	unsigned int data;
+	int ret;
+	ret = regmap_read(tps->regmap, REG_VSET0 + vset_id, &data);
+	if (ret < 0) {
+		dev_err(tps->dev, "%s() fails in writing reg %d\n",
+			__func__, REG_VSET0 + vset_id);
+		return ret;
+	}
+	tps->curr_vset_vsel[vset_id] = data & tps->voltage_reg_mask;
+	if (pdata->en_force_pwm)
+		data |= BIT(7);
+	else
+		data &= ~BIT(7);
+	ret = regmap_write(tps->regmap, REG_VSET0 + vset_id, data);
+	if (ret < 0)
+		dev_err(tps->dev, "%s() fails in writing reg %d\n",
+				__func__, REG_VSET0 + vset_id);
+	return ret;
+}
+
+static int tps62360_init_dcdc(struct tps62360_chip *tps,
+		struct tps62360_regulator_platform_data *pdata)
+{
+	int ret;
+	int i;
+
+	/* Initailize internal pull up/down control */
+	if (tps->en_internal_pulldn)
+		ret = regmap_write(tps->regmap, REG_CONTROL, 0xE0);
+	else
+		ret = regmap_write(tps->regmap, REG_CONTROL, 0x0);
+	if (ret < 0) {
+		dev_err(tps->dev, "%s() fails in writing reg %d\n",
+			__func__, REG_CONTROL);
+		return ret;
+	}
+
+	/* Initailize force PWM mode */
+	if (tps->valid_gpios) {
+		for (i = 0; i < 4; ++i) {
+			ret = tps62360_init_force_pwm(tps, pdata, i);
+			if (ret < 0)
+				return ret;
+		}
+	} else {
+		ret = tps62360_init_force_pwm(tps, pdata, tps->curr_vset_id);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Reset output discharge path to reduce power consumption */
+	ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0);
+	if (ret < 0)
+		dev_err(tps->dev, "%s() fails in updating reg %d\n",
+			__func__, REG_RAMPCTRL);
+	return ret;
+}
+
+static const struct regmap_config tps62360_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int __devinit tps62360_probe(struct i2c_client *client,
+				     const struct i2c_device_id *id)
+{
+	struct tps62360_regulator_platform_data *pdata;
+	struct regulator_dev *rdev;
+	struct tps62360_chip *tps;
+	int ret;
+	int i;
+
+	pdata = client->dev.platform_data;
+	if (!pdata) {
+		dev_err(&client->dev, "%s() Err: Platform data not found\n",
+						__func__);
+		return -EIO;
+	}
+
+	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+	if (!tps) {
+		dev_err(&client->dev, "%s() Err: Memory allocation fails\n",
+						__func__);
+		return -ENOMEM;
+	}
+
+	tps->en_force_pwm = pdata->en_force_pwm;
+	tps->en_discharge = pdata->en_discharge;
+	tps->en_internal_pulldn = pdata->en_internal_pulldn;
+	tps->vsel0_gpio = pdata->vsel0_gpio;
+	tps->vsel1_gpio = pdata->vsel1_gpio;
+	tps->client = client;
+	tps->dev = &client->dev;
+	tps->name = id->name;
+	tps->voltage_base = (id->driver_data == TPS62360) ?
+				TPS62360_BASE_VOLTAGE : TPS62361_BASE_VOLTAGE;
+	tps->voltage_reg_mask = (id->driver_data == TPS62360) ? 0x3F : 0x7F;
+
+	tps->desc.name = id->name;
+	tps->desc.id = 0;
+	tps->desc.n_voltages = (id->driver_data == TPS62360) ?
+				TPS62360_N_VOLTAGES : TPS62361_N_VOLTAGES;
+	tps->desc.ops = &tps62360_dcdc_ops;
+	tps->desc.type = REGULATOR_VOLTAGE;
+	tps->desc.owner = THIS_MODULE;
+	tps->regmap = regmap_init_i2c(client, &tps62360_regmap_config);
+	if (IS_ERR(tps->regmap)) {
+		ret = PTR_ERR(tps->regmap);
+		dev_err(&client->dev, "%s() Err: Failed to allocate register"
+			"map: %d\n", __func__, ret);
+		return ret;
+	}
+	i2c_set_clientdata(client, tps);
+
+	tps->curr_vset_id = (pdata->vsel1_def_state & 1) * 2 +
+				(pdata->vsel0_def_state & 1);
+	tps->lru_index[0] = tps->curr_vset_id;
+	tps->valid_gpios = false;
+
+	if (gpio_is_valid(tps->vsel0_gpio) && gpio_is_valid(tps->vsel1_gpio)) {
+		ret = gpio_request(tps->vsel0_gpio, "tps62360-vsel0");
+		if (ret) {
+			dev_err(&client->dev,
+				"Err: Could not obtain vsel0 GPIO %d: %d\n",
+						tps->vsel0_gpio, ret);
+			goto err_gpio0;
+		}
+		ret = gpio_direction_output(tps->vsel0_gpio,
+					pdata->vsel0_def_state);
+		if (ret) {
+			dev_err(&client->dev, "Err: Could not set direction of"
+				"vsel0 GPIO %d: %d\n", tps->vsel0_gpio, ret);
+			gpio_free(tps->vsel0_gpio);
+			goto err_gpio0;
+		}
+
+		ret = gpio_request(tps->vsel1_gpio, "tps62360-vsel1");
+		if (ret) {
+			dev_err(&client->dev,
+				"Err: Could not obtain vsel1 GPIO %d: %d\n",
+						tps->vsel1_gpio, ret);
+			goto err_gpio1;
+		}
+		ret = gpio_direction_output(tps->vsel1_gpio,
+					pdata->vsel1_def_state);
+		if (ret) {
+			dev_err(&client->dev, "Err: Could not set direction of"
+				"vsel1 GPIO %d: %d\n", tps->vsel1_gpio, ret);
+			gpio_free(tps->vsel1_gpio);
+			goto err_gpio1;
+		}
+		tps->valid_gpios = true;
+
+		/*
+		 * Initialize the lru index with vset_reg id
+		 * The index 0 will be most recently used and
+		 * set with the tps->curr_vset_id */
+		for (i = 0; i < 4; ++i)
+			tps->lru_index[i] = i;
+		tps->lru_index[0] = tps->curr_vset_id;
+		tps->lru_index[tps->curr_vset_id] = 0;
+	}
+
+	ret = tps62360_init_dcdc(tps, pdata);
+	if (ret < 0) {
+		dev_err(tps->dev, "%s() Err: Init fails with = %d\n",
+				__func__, ret);
+		goto err_init;
+	}
+
+	/* Register the regulators */
+	rdev = regulator_register(&tps->desc, &client->dev,
+				&pdata->reg_init_data, tps, NULL);
+	if (IS_ERR(rdev)) {
+		dev_err(tps->dev, "%s() Err: Failed to register %s\n",
+				__func__, id->name);
+		ret = PTR_ERR(rdev);
+		goto err_init;
+	}
+
+	tps->rdev = rdev;
+	return 0;
+
+err_init:
+	if (gpio_is_valid(tps->vsel1_gpio))
+		gpio_free(tps->vsel1_gpio);
+err_gpio1:
+	if (gpio_is_valid(tps->vsel0_gpio))
+		gpio_free(tps->vsel0_gpio);
+err_gpio0:
+	regmap_exit(tps->regmap);
+	return ret;
+}
+
+/**
+ * tps62360_remove - tps62360 driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister TPS driver as an i2c client device driver
+ */
+static int __devexit tps62360_remove(struct i2c_client *client)
+{
+	struct tps62360_chip *tps = i2c_get_clientdata(client);
+
+	if (gpio_is_valid(tps->vsel1_gpio))
+		gpio_free(tps->vsel1_gpio);
+
+	if (gpio_is_valid(tps->vsel0_gpio))
+		gpio_free(tps->vsel0_gpio);
+
+	regulator_unregister(tps->rdev);
+	regmap_exit(tps->regmap);
+	return 0;
+}
+
+static void tps62360_shutdown(struct i2c_client *client)
+{
+	struct tps62360_chip *tps = i2c_get_clientdata(client);
+	int st;
+
+	if (!tps->en_discharge)
+		return;
+
+	/* Configure the output discharge path */
+	st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2));
+	if (st < 0)
+		dev_err(tps->dev, "%s() fails in updating reg %d\n",
+			__func__, REG_RAMPCTRL);
+}
+
+static const struct i2c_device_id tps62360_id[] = {
+	{.name = "tps62360", .driver_data = TPS62360},
+	{.name = "tps62361", .driver_data = TPS62361},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, tps62360_id);
+
+static struct i2c_driver tps62360_i2c_driver = {
+	.driver = {
+		.name = "tps62360",
+		.owner = THIS_MODULE,
+	},
+	.probe = tps62360_probe,
+	.remove = __devexit_p(tps62360_remove),
+	.shutdown = tps62360_shutdown,
+	.id_table = tps62360_id,
+};
+
+static int __init tps62360_init(void)
+{
+	return i2c_add_driver(&tps62360_i2c_driver);
+}
+subsys_initcall(tps62360_init);
+
+static void __exit tps62360_cleanup(void)
+{
+	i2c_del_driver(&tps62360_i2c_driver);
+}
+module_exit(tps62360_cleanup);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("TPS62360 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/tps65023-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/tps65023-regulator.c
new file mode 100644
index 0000000..43e4902
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/tps65023-regulator.c
@@ -0,0 +1,696 @@
+/*
+ * tps65023-regulator.c
+ *
+ * Supports TPS65023 Regulator
+ *
+ * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+/* Register definitions */
+#define	TPS65023_REG_VERSION		0
+#define	TPS65023_REG_PGOODZ		1
+#define	TPS65023_REG_MASK		2
+#define	TPS65023_REG_REG_CTRL		3
+#define	TPS65023_REG_CON_CTRL		4
+#define	TPS65023_REG_CON_CTRL2		5
+#define	TPS65023_REG_DEF_CORE		6
+#define	TPS65023_REG_DEFSLEW		7
+#define	TPS65023_REG_LDO_CTRL		8
+
+/* PGOODZ bitfields */
+#define	TPS65023_PGOODZ_PWRFAILZ	BIT(7)
+#define	TPS65023_PGOODZ_LOWBATTZ	BIT(6)
+#define	TPS65023_PGOODZ_VDCDC1		BIT(5)
+#define	TPS65023_PGOODZ_VDCDC2		BIT(4)
+#define	TPS65023_PGOODZ_VDCDC3		BIT(3)
+#define	TPS65023_PGOODZ_LDO2		BIT(2)
+#define	TPS65023_PGOODZ_LDO1		BIT(1)
+
+/* MASK bitfields */
+#define	TPS65023_MASK_PWRFAILZ		BIT(7)
+#define	TPS65023_MASK_LOWBATTZ		BIT(6)
+#define	TPS65023_MASK_VDCDC1		BIT(5)
+#define	TPS65023_MASK_VDCDC2		BIT(4)
+#define	TPS65023_MASK_VDCDC3		BIT(3)
+#define	TPS65023_MASK_LDO2		BIT(2)
+#define	TPS65023_MASK_LDO1		BIT(1)
+
+/* REG_CTRL bitfields */
+#define TPS65023_REG_CTRL_VDCDC1_EN	BIT(5)
+#define TPS65023_REG_CTRL_VDCDC2_EN	BIT(4)
+#define TPS65023_REG_CTRL_VDCDC3_EN	BIT(3)
+#define TPS65023_REG_CTRL_LDO2_EN	BIT(2)
+#define TPS65023_REG_CTRL_LDO1_EN	BIT(1)
+
+/* REG_CTRL2 bitfields */
+#define TPS65023_REG_CTRL2_GO		BIT(7)
+#define TPS65023_REG_CTRL2_CORE_ADJ	BIT(6)
+#define TPS65023_REG_CTRL2_DCDC2	BIT(2)
+#define TPS65023_REG_CTRL2_DCDC1	BIT(1)
+#define TPS65023_REG_CTRL2_DCDC3	BIT(0)
+
+/* LDO_CTRL bitfields */
+#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id)	((ldo_id)*4)
+#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id)	(0xF0 >> ((ldo_id)*4))
+
+/* Number of step-down converters available */
+#define TPS65023_NUM_DCDC		3
+/* Number of LDO voltage regulators  available */
+#define TPS65023_NUM_LDO		2
+/* Number of total regulators available */
+#define TPS65023_NUM_REGULATOR	(TPS65023_NUM_DCDC + TPS65023_NUM_LDO)
+
+/* DCDCs */
+#define TPS65023_DCDC_1			0
+#define TPS65023_DCDC_2			1
+#define TPS65023_DCDC_3			2
+/* LDOs */
+#define TPS65023_LDO_1			3
+#define TPS65023_LDO_2			4
+
+#define TPS65023_MAX_REG_ID		TPS65023_LDO_2
+
+/* Supported voltage values for regulators */
+static const u16 VCORE_VSEL_table[] = {
+	800, 825, 850, 875,
+	900, 925, 950, 975,
+	1000, 1025, 1050, 1075,
+	1100, 1125, 1150, 1175,
+	1200, 1225, 1250, 1275,
+	1300, 1325, 1350, 1375,
+	1400, 1425, 1450, 1475,
+	1500, 1525, 1550, 1600,
+};
+
+/* Supported voltage values for LDO regulators for tps65020 */
+static const u16 TPS65020_LDO1_VSEL_table[] = {
+	1000, 1050, 1100, 1300,
+	1800, 2500, 3000, 3300,
+};
+
+static const u16 TPS65020_LDO2_VSEL_table[] = {
+	1000, 1050, 1100, 1300,
+	1800, 2500, 3000, 3300,
+};
+
+/* Supported voltage values for LDO regulators
+ * for tps65021 and tps65023 */
+static const u16 TPS65023_LDO1_VSEL_table[] = {
+	1000, 1100, 1300, 1800,
+	2200, 2600, 2800, 3150,
+};
+
+static const u16 TPS65023_LDO2_VSEL_table[] = {
+	1050, 1200, 1300, 1800,
+	2500, 2800, 3000, 3300,
+};
+
+/* Regulator specific details */
+struct tps_info {
+	const char *name;
+	unsigned min_uV;
+	unsigned max_uV;
+	bool fixed;
+	u8 table_len;
+	const u16 *table;
+};
+
+/* PMIC details */
+struct tps_pmic {
+	struct regulator_desc desc[TPS65023_NUM_REGULATOR];
+	struct i2c_client *client;
+	struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
+	const struct tps_info *info[TPS65023_NUM_REGULATOR];
+	struct regmap *regmap;
+	u8 core_regulator;
+};
+
+/* Struct passed as driver data */
+struct tps_driver_data {
+	const struct tps_info *info;
+	u8 core_regulator;
+};
+
+static int tps65023_dcdc_is_enabled(struct regulator_dev *dev)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int data, dcdc = rdev_get_id(dev);
+	int ret;
+	u8 shift;
+
+	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
+		return -EINVAL;
+
+	shift = TPS65023_NUM_REGULATOR - dcdc;
+	ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
+
+	if (ret != 0)
+		return ret;
+	else
+		return (data & 1<<shift) ? 1 : 0;
+}
+
+static int tps65023_ldo_is_enabled(struct regulator_dev *dev)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int data, ldo = rdev_get_id(dev);
+	int ret;
+	u8 shift;
+
+	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
+		return -EINVAL;
+
+	shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
+	ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
+
+	if (ret != 0)
+		return ret;
+	else
+		return (data & 1<<shift) ? 1 : 0;
+}
+
+static int tps65023_dcdc_enable(struct regulator_dev *dev)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int dcdc = rdev_get_id(dev);
+	u8 shift;
+
+	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
+		return -EINVAL;
+
+	shift = TPS65023_NUM_REGULATOR - dcdc;
+	return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
+}
+
+static int tps65023_dcdc_disable(struct regulator_dev *dev)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int dcdc = rdev_get_id(dev);
+	u8 shift;
+
+	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
+		return -EINVAL;
+
+	shift = TPS65023_NUM_REGULATOR - dcdc;
+	return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
+}
+
+static int tps65023_ldo_enable(struct regulator_dev *dev)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev);
+	u8 shift;
+
+	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
+		return -EINVAL;
+
+	shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
+	return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
+}
+
+static int tps65023_ldo_disable(struct regulator_dev *dev)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev);
+	u8 shift;
+
+	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
+		return -EINVAL;
+
+	shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
+	return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
+}
+
+static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int ret;
+	int data, dcdc = rdev_get_id(dev);
+
+	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
+		return -EINVAL;
+
+	if (dcdc == tps->core_regulator) {
+		ret = regmap_read(tps->regmap, TPS65023_REG_DEF_CORE, &data);
+		if (ret != 0)
+			return ret;
+		data &= (tps->info[dcdc]->table_len - 1);
+		return tps->info[dcdc]->table[data] * 1000;
+	} else
+		return tps->info[dcdc]->min_uV;
+}
+
+static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
+				     int min_uV, int max_uV,
+				     unsigned *selector)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int dcdc = rdev_get_id(dev);
+	int vsel;
+	int ret;
+
+	if (dcdc != tps->core_regulator)
+		return -EINVAL;
+	if (min_uV < tps->info[dcdc]->min_uV
+			|| min_uV > tps->info[dcdc]->max_uV)
+		return -EINVAL;
+	if (max_uV < tps->info[dcdc]->min_uV
+			|| max_uV > tps->info[dcdc]->max_uV)
+		return -EINVAL;
+
+	for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
+		int mV = tps->info[dcdc]->table[vsel];
+		int uV = mV * 1000;
+
+		/* Break at the first in-range value */
+		if (min_uV <= uV && uV <= max_uV)
+			break;
+	}
+
+	*selector = vsel;
+
+	if (vsel == tps->info[dcdc]->table_len)
+		goto failed;
+
+	ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, vsel);
+
+	/* Tell the chip that we have changed the value in DEFCORE
+	 * and its time to update the core voltage
+	 */
+	regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
+			TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO);
+
+	return ret;
+
+failed:
+	return -EINVAL;
+}
+
+static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int data, ldo = rdev_get_id(dev);
+	int ret;
+
+	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
+		return -EINVAL;
+
+	ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
+	if (ret != 0)
+		return ret;
+
+	data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1));
+	data &= (tps->info[ldo]->table_len - 1);
+	return tps->info[ldo]->table[data] * 1000;
+}
+
+static int tps65023_ldo_set_voltage(struct regulator_dev *dev,
+				    int min_uV, int max_uV, unsigned *selector)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int data, vsel, ldo = rdev_get_id(dev);
+	int ret;
+
+	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
+		return -EINVAL;
+
+	if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
+		return -EINVAL;
+	if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
+		return -EINVAL;
+
+	for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
+		int mV = tps->info[ldo]->table[vsel];
+		int uV = mV * 1000;
+
+		/* Break at the first in-range value */
+		if (min_uV <= uV && uV <= max_uV)
+			break;
+	}
+
+	if (vsel == tps->info[ldo]->table_len)
+		return -EINVAL;
+
+	*selector = vsel;
+
+	ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
+	if (ret != 0)
+		return ret;
+
+	data &= TPS65023_LDO_CTRL_LDOx_MASK(ldo - TPS65023_LDO_1);
+	data |= (vsel << (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1)));
+	return regmap_write(tps->regmap, TPS65023_REG_LDO_CTRL, data);
+}
+
+static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
+					unsigned selector)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int dcdc = rdev_get_id(dev);
+
+	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
+		return -EINVAL;
+
+	if (dcdc == tps->core_regulator) {
+		if (selector >= tps->info[dcdc]->table_len)
+			return -EINVAL;
+		else
+			return tps->info[dcdc]->table[selector] * 1000;
+	} else
+		return tps->info[dcdc]->min_uV;
+}
+
+static int tps65023_ldo_list_voltage(struct regulator_dev *dev,
+					unsigned selector)
+{
+	struct tps_pmic *tps = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev);
+
+	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
+		return -EINVAL;
+
+	if (selector >= tps->info[ldo]->table_len)
+		return -EINVAL;
+	else
+		return tps->info[ldo]->table[selector] * 1000;
+}
+
+/* Operations permitted on VDCDCx */
+static struct regulator_ops tps65023_dcdc_ops = {
+	.is_enabled = tps65023_dcdc_is_enabled,
+	.enable = tps65023_dcdc_enable,
+	.disable = tps65023_dcdc_disable,
+	.get_voltage = tps65023_dcdc_get_voltage,
+	.set_voltage = tps65023_dcdc_set_voltage,
+	.list_voltage = tps65023_dcdc_list_voltage,
+};
+
+/* Operations permitted on LDOx */
+static struct regulator_ops tps65023_ldo_ops = {
+	.is_enabled = tps65023_ldo_is_enabled,
+	.enable = tps65023_ldo_enable,
+	.disable = tps65023_ldo_disable,
+	.get_voltage = tps65023_ldo_get_voltage,
+	.set_voltage = tps65023_ldo_set_voltage,
+	.list_voltage = tps65023_ldo_list_voltage,
+};
+
+static struct regmap_config tps65023_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int __devinit tps_65023_probe(struct i2c_client *client,
+				     const struct i2c_device_id *id)
+{
+	const struct tps_driver_data *drv_data = (void *)id->driver_data;
+	const struct tps_info *info = drv_data->info;
+	struct regulator_init_data *init_data;
+	struct regulator_dev *rdev;
+	struct tps_pmic *tps;
+	int i;
+	int error;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	/**
+	 * init_data points to array of regulator_init structures
+	 * coming from the board-evm file.
+	 */
+	init_data = client->dev.platform_data;
+	if (!init_data)
+		return -EIO;
+
+	tps = kzalloc(sizeof(*tps), GFP_KERNEL);
+	if (!tps)
+		return -ENOMEM;
+
+	tps->regmap = regmap_init_i2c(client, &tps65023_regmap_config);
+	if (IS_ERR(tps->regmap)) {
+		error = PTR_ERR(tps->regmap);
+		dev_err(&client->dev, "Failed to allocate register map: %d\n",
+			error);
+		goto fail_alloc;
+	}
+
+	/* common for all regulators */
+	tps->client = client;
+	tps->core_regulator = drv_data->core_regulator;
+
+	for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
+		/* Store regulator specific information */
+		tps->info[i] = info;
+
+		tps->desc[i].name = info->name;
+		tps->desc[i].id = i;
+		tps->desc[i].n_voltages = info->table_len;
+		tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
+					&tps65023_ldo_ops : &tps65023_dcdc_ops);
+		tps->desc[i].type = REGULATOR_VOLTAGE;
+		tps->desc[i].owner = THIS_MODULE;
+
+		/* Register the regulators */
+		rdev = regulator_register(&tps->desc[i], &client->dev,
+					  init_data, tps, NULL);
+		if (IS_ERR(rdev)) {
+			dev_err(&client->dev, "failed to register %s\n",
+				id->name);
+			error = PTR_ERR(rdev);
+			goto fail;
+		}
+
+		/* Save regulator for cleanup */
+		tps->rdev[i] = rdev;
+	}
+
+	i2c_set_clientdata(client, tps);
+
+	/* Enable setting output voltage by I2C */
+	regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
+			TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ);
+
+	return 0;
+
+ fail:
+	while (--i >= 0)
+		regulator_unregister(tps->rdev[i]);
+
+	regmap_exit(tps->regmap);
+ fail_alloc:
+	kfree(tps);
+	return error;
+}
+
+/**
+ * tps_65023_remove - TPS65023 driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister TPS driver as an i2c client device driver
+ */
+static int __devexit tps_65023_remove(struct i2c_client *client)
+{
+	struct tps_pmic *tps = i2c_get_clientdata(client);
+	int i;
+
+	for (i = 0; i < TPS65023_NUM_REGULATOR; i++)
+		regulator_unregister(tps->rdev[i]);
+
+	regmap_exit(tps->regmap);
+	kfree(tps);
+
+	return 0;
+}
+
+static const struct tps_info tps65020_regs[] = {
+	{
+		.name = "VDCDC1",
+		.min_uV = 3300000,
+		.max_uV = 3300000,
+		.fixed	= 1,
+	},
+	{
+		.name = "VDCDC2",
+		.min_uV =  1800000,
+		.max_uV = 1800000,
+		.fixed = 1,
+	},
+	{
+		.name = "VDCDC3",
+		.min_uV =  800000,
+		.max_uV = 1600000,
+		.table_len = ARRAY_SIZE(VCORE_VSEL_table),
+		.table = VCORE_VSEL_table,
+	},
+
+	{
+		.name = "LDO1",
+		.min_uV = 1000000,
+		.max_uV = 3150000,
+		.table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table),
+		.table = TPS65020_LDO1_VSEL_table,
+	},
+	{
+		.name = "LDO2",
+		.min_uV = 1050000,
+		.max_uV = 3300000,
+		.table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table),
+		.table = TPS65020_LDO2_VSEL_table,
+	},
+};
+
+static const struct tps_info tps65021_regs[] = {
+	{
+		.name = "VDCDC1",
+		.min_uV =  3300000,
+		.max_uV = 3300000,
+		.fixed = 1,
+	},
+	{
+		.name = "VDCDC2",
+		.min_uV =  1800000,
+		.max_uV = 1800000,
+		.fixed = 1,
+	},
+	{
+		.name = "VDCDC3",
+		.min_uV =  800000,
+		.max_uV = 1600000,
+		.table_len = ARRAY_SIZE(VCORE_VSEL_table),
+		.table = VCORE_VSEL_table,
+	},
+	{
+		.name = "LDO1",
+		.min_uV = 1000000,
+		.max_uV = 3150000,
+		.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
+		.table = TPS65023_LDO1_VSEL_table,
+	},
+	{
+		.name = "LDO2",
+		.min_uV = 1050000,
+		.max_uV = 3300000,
+		.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
+		.table = TPS65023_LDO2_VSEL_table,
+	},
+};
+
+static const struct tps_info tps65023_regs[] = {
+	{
+		.name = "VDCDC1",
+		.min_uV =  800000,
+		.max_uV = 1600000,
+		.table_len = ARRAY_SIZE(VCORE_VSEL_table),
+		.table = VCORE_VSEL_table,
+	},
+	{
+		.name = "VDCDC2",
+		.min_uV =  3300000,
+		.max_uV = 3300000,
+		.fixed = 1,
+	},
+	{
+		.name = "VDCDC3",
+		.min_uV =  1800000,
+		.max_uV = 1800000,
+		.fixed = 1,
+	},
+	{
+		.name = "LDO1",
+		.min_uV = 1000000,
+		.max_uV = 3150000,
+		.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
+		.table = TPS65023_LDO1_VSEL_table,
+	},
+	{
+		.name = "LDO2",
+		.min_uV = 1050000,
+		.max_uV = 3300000,
+		.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
+		.table = TPS65023_LDO2_VSEL_table,
+	},
+};
+
+static struct tps_driver_data tps65020_drv_data = {
+	.info = tps65020_regs,
+	.core_regulator = TPS65023_DCDC_3,
+};
+
+static struct tps_driver_data tps65021_drv_data = {
+		.info = tps65021_regs,
+		.core_regulator = TPS65023_DCDC_3,
+};
+
+static struct tps_driver_data tps65023_drv_data = {
+		.info = tps65023_regs,
+		.core_regulator = TPS65023_DCDC_1,
+};
+
+static const struct i2c_device_id tps_65023_id[] = {
+	{.name = "tps65023",
+	.driver_data = (unsigned long) &tps65023_drv_data},
+	{.name = "tps65021",
+	.driver_data = (unsigned long) &tps65021_drv_data,},
+	{.name = "tps65020",
+	.driver_data = (unsigned long) &tps65020_drv_data},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, tps_65023_id);
+
+static struct i2c_driver tps_65023_i2c_driver = {
+	.driver = {
+		.name = "tps65023",
+		.owner = THIS_MODULE,
+	},
+	.probe = tps_65023_probe,
+	.remove = __devexit_p(tps_65023_remove),
+	.id_table = tps_65023_id,
+};
+
+/**
+ * tps_65023_init
+ *
+ * Module init function
+ */
+static int __init tps_65023_init(void)
+{
+	return i2c_add_driver(&tps_65023_i2c_driver);
+}
+subsys_initcall(tps_65023_init);
+
+/**
+ * tps_65023_cleanup
+ *
+ * Module exit function
+ */
+static void __exit tps_65023_cleanup(void)
+{
+	i2c_del_driver(&tps_65023_i2c_driver);
+}
+module_exit(tps_65023_cleanup);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TPS65023 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/tps6507x-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/tps6507x-regulator.c
new file mode 100644
index 0000000..832833f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/tps6507x-regulator.c
@@ -0,0 +1,521 @@
+/*
+ * tps6507x-regulator.c
+ *
+ * Regulator driver for TPS65073 PMIC
+ *
+ * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/tps6507x.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mfd/tps6507x.h>
+
+/* DCDC's */
+#define TPS6507X_DCDC_1				0
+#define TPS6507X_DCDC_2				1
+#define TPS6507X_DCDC_3				2
+/* LDOs */
+#define TPS6507X_LDO_1				3
+#define TPS6507X_LDO_2				4
+
+#define TPS6507X_MAX_REG_ID			TPS6507X_LDO_2
+
+/* Number of step-down converters available */
+#define TPS6507X_NUM_DCDC			3
+/* Number of LDO voltage regulators  available */
+#define TPS6507X_NUM_LDO			2
+/* Number of total regulators available */
+#define TPS6507X_NUM_REGULATOR		(TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
+
+/* Supported voltage values for regulators (in milliVolts) */
+static const u16 VDCDCx_VSEL_table[] = {
+	725, 750, 775, 800,
+	825, 850, 875, 900,
+	925, 950, 975, 1000,
+	1025, 1050, 1075, 1100,
+	1125, 1150, 1175, 1200,
+	1225, 1250, 1275, 1300,
+	1325, 1350, 1375, 1400,
+	1425, 1450, 1475, 1500,
+	1550, 1600, 1650, 1700,
+	1750, 1800, 1850, 1900,
+	1950, 2000, 2050, 2100,
+	2150, 2200, 2250, 2300,
+	2350, 2400, 2450, 2500,
+	2550, 2600, 2650, 2700,
+	2750, 2800, 2850, 2900,
+	3000, 3100, 3200, 3300,
+};
+
+static const u16 LDO1_VSEL_table[] = {
+	1000, 1100, 1200, 1250,
+	1300, 1350, 1400, 1500,
+	1600, 1800, 2500, 2750,
+	2800, 3000, 3100, 3300,
+};
+
+static const u16 LDO2_VSEL_table[] = {
+	725, 750, 775, 800,
+	825, 850, 875, 900,
+	925, 950, 975, 1000,
+	1025, 1050, 1075, 1100,
+	1125, 1150, 1175, 1200,
+	1225, 1250, 1275, 1300,
+	1325, 1350, 1375, 1400,
+	1425, 1450, 1475, 1500,
+	1550, 1600, 1650, 1700,
+	1750, 1800, 1850, 1900,
+	1950, 2000, 2050, 2100,
+	2150, 2200, 2250, 2300,
+	2350, 2400, 2450, 2500,
+	2550, 2600, 2650, 2700,
+	2750, 2800, 2850, 2900,
+	3000, 3100, 3200, 3300,
+};
+
+struct tps_info {
+	const char *name;
+	unsigned min_uV;
+	unsigned max_uV;
+	u8 table_len;
+	const u16 *table;
+
+	/* Does DCDC high or the low register defines output voltage? */
+	bool defdcdc_default;
+};
+
+static struct tps_info tps6507x_pmic_regs[] = {
+	{
+		.name = "VDCDC1",
+		.min_uV = 725000,
+		.max_uV = 3300000,
+		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
+		.table = VDCDCx_VSEL_table,
+	},
+	{
+		.name = "VDCDC2",
+		.min_uV = 725000,
+		.max_uV = 3300000,
+		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
+		.table = VDCDCx_VSEL_table,
+	},
+	{
+		.name = "VDCDC3",
+		.min_uV = 725000,
+		.max_uV = 3300000,
+		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
+		.table = VDCDCx_VSEL_table,
+	},
+	{
+		.name = "LDO1",
+		.min_uV = 1000000,
+		.max_uV = 3300000,
+		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
+		.table = LDO1_VSEL_table,
+	},
+	{
+		.name = "LDO2",
+		.min_uV = 725000,
+		.max_uV = 3300000,
+		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
+		.table = LDO2_VSEL_table,
+	},
+};
+
+struct tps6507x_pmic {
+	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
+	struct tps6507x_dev *mfd;
+	struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
+	struct tps_info *info[TPS6507X_NUM_REGULATOR];
+	struct mutex io_lock;
+};
+static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
+{
+	u8 val;
+	int err;
+
+	err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
+
+	if (err)
+		return err;
+
+	return val;
+}
+
+static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
+{
+	return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
+}
+
+static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
+{
+	int err, data;
+
+	mutex_lock(&tps->io_lock);
+
+	data = tps6507x_pmic_read(tps, reg);
+	if (data < 0) {
+		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
+		err = data;
+		goto out;
+	}
+
+	data |= mask;
+	err = tps6507x_pmic_write(tps, reg, data);
+	if (err)
+		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
+
+out:
+	mutex_unlock(&tps->io_lock);
+	return err;
+}
+
+static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
+{
+	int err, data;
+
+	mutex_lock(&tps->io_lock);
+
+	data = tps6507x_pmic_read(tps, reg);
+	if (data < 0) {
+		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
+		err = data;
+		goto out;
+	}
+
+	data &= ~mask;
+	err = tps6507x_pmic_write(tps, reg, data);
+	if (err)
+		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
+
+out:
+	mutex_unlock(&tps->io_lock);
+	return err;
+}
+
+static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
+{
+	int data;
+
+	mutex_lock(&tps->io_lock);
+
+	data = tps6507x_pmic_read(tps, reg);
+	if (data < 0)
+		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
+
+	mutex_unlock(&tps->io_lock);
+	return data;
+}
+
+static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
+{
+	int err;
+
+	mutex_lock(&tps->io_lock);
+
+	err = tps6507x_pmic_write(tps, reg, val);
+	if (err < 0)
+		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
+
+	mutex_unlock(&tps->io_lock);
+	return err;
+}
+
+static int tps6507x_pmic_is_enabled(struct regulator_dev *dev)
+{
+	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
+	int data, rid = rdev_get_id(dev);
+	u8 shift;
+
+	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
+		return -EINVAL;
+
+	shift = TPS6507X_MAX_REG_ID - rid;
+	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
+
+	if (data < 0)
+		return data;
+	else
+		return (data & 1<<shift) ? 1 : 0;
+}
+
+static int tps6507x_pmic_enable(struct regulator_dev *dev)
+{
+	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
+	int rid = rdev_get_id(dev);
+	u8 shift;
+
+	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
+		return -EINVAL;
+
+	shift = TPS6507X_MAX_REG_ID - rid;
+	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
+}
+
+static int tps6507x_pmic_disable(struct regulator_dev *dev)
+{
+	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
+	int rid = rdev_get_id(dev);
+	u8 shift;
+
+	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
+		return -EINVAL;
+
+	shift = TPS6507X_MAX_REG_ID - rid;
+	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
+					1 << shift);
+}
+
+static int tps6507x_pmic_get_voltage(struct regulator_dev *dev)
+{
+	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
+	int data, rid = rdev_get_id(dev);
+	u8 reg, mask;
+
+	switch (rid) {
+	case TPS6507X_DCDC_1:
+		reg = TPS6507X_REG_DEFDCDC1;
+		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
+		break;
+	case TPS6507X_DCDC_2:
+		if (tps->info[rid]->defdcdc_default)
+			reg = TPS6507X_REG_DEFDCDC2_HIGH;
+		else
+			reg = TPS6507X_REG_DEFDCDC2_LOW;
+		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
+		break;
+	case TPS6507X_DCDC_3:
+		if (tps->info[rid]->defdcdc_default)
+			reg = TPS6507X_REG_DEFDCDC3_HIGH;
+		else
+			reg = TPS6507X_REG_DEFDCDC3_LOW;
+		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
+		break;
+	case TPS6507X_LDO_1:
+		reg = TPS6507X_REG_LDO_CTRL1;
+		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
+		break;
+	case TPS6507X_LDO_2:
+		reg = TPS6507X_REG_DEFLDO2;
+		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data = tps6507x_pmic_reg_read(tps, reg);
+	if (data < 0)
+		return data;
+
+	data &= mask;
+	return tps->info[rid]->table[data] * 1000;
+}
+
+static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
+					  unsigned selector)
+{
+	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
+	int data, rid = rdev_get_id(dev);
+	u8 reg, mask;
+
+	switch (rid) {
+	case TPS6507X_DCDC_1:
+		reg = TPS6507X_REG_DEFDCDC1;
+		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
+		break;
+	case TPS6507X_DCDC_2:
+		if (tps->info[rid]->defdcdc_default)
+			reg = TPS6507X_REG_DEFDCDC2_HIGH;
+		else
+			reg = TPS6507X_REG_DEFDCDC2_LOW;
+		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
+		break;
+	case TPS6507X_DCDC_3:
+		if (tps->info[rid]->defdcdc_default)
+			reg = TPS6507X_REG_DEFDCDC3_HIGH;
+		else
+			reg = TPS6507X_REG_DEFDCDC3_LOW;
+		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
+		break;
+	case TPS6507X_LDO_1:
+		reg = TPS6507X_REG_LDO_CTRL1;
+		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
+		break;
+	case TPS6507X_LDO_2:
+		reg = TPS6507X_REG_DEFLDO2;
+		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	data = tps6507x_pmic_reg_read(tps, reg);
+	if (data < 0)
+		return data;
+
+	data &= ~mask;
+	data |= selector;
+
+	return tps6507x_pmic_reg_write(tps, reg, data);
+}
+
+static int tps6507x_pmic_list_voltage(struct regulator_dev *dev,
+					unsigned selector)
+{
+	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
+	int rid = rdev_get_id(dev);
+
+	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
+		return -EINVAL;
+
+	if (selector >= tps->info[rid]->table_len)
+		return -EINVAL;
+	else
+		return tps->info[rid]->table[selector] * 1000;
+}
+
+static struct regulator_ops tps6507x_pmic_ops = {
+	.is_enabled = tps6507x_pmic_is_enabled,
+	.enable = tps6507x_pmic_enable,
+	.disable = tps6507x_pmic_disable,
+	.get_voltage = tps6507x_pmic_get_voltage,
+	.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
+	.list_voltage = tps6507x_pmic_list_voltage,
+};
+
+static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
+{
+	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
+	struct tps_info *info = &tps6507x_pmic_regs[0];
+	struct regulator_init_data *init_data;
+	struct regulator_dev *rdev;
+	struct tps6507x_pmic *tps;
+	struct tps6507x_board *tps_board;
+	int i;
+	int error;
+
+	/**
+	 * tps_board points to pmic related constants
+	 * coming from the board-evm file.
+	 */
+
+	tps_board = dev_get_platdata(tps6507x_dev->dev);
+	if (!tps_board)
+		return -EINVAL;
+
+	/**
+	 * init_data points to array of regulator_init structures
+	 * coming from the board-evm file.
+	 */
+	init_data = tps_board->tps6507x_pmic_init_data;
+	if (!init_data)
+		return -EINVAL;
+
+	tps = kzalloc(sizeof(*tps), GFP_KERNEL);
+	if (!tps)
+		return -ENOMEM;
+
+	mutex_init(&tps->io_lock);
+
+	/* common for all regulators */
+	tps->mfd = tps6507x_dev;
+
+	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
+		/* Register the regulators */
+		tps->info[i] = info;
+		if (init_data->driver_data) {
+			struct tps6507x_reg_platform_data *data =
+							init_data->driver_data;
+			tps->info[i]->defdcdc_default = data->defdcdc_default;
+		}
+
+		tps->desc[i].name = info->name;
+		tps->desc[i].id = i;
+		tps->desc[i].n_voltages = info->table_len;
+		tps->desc[i].ops = &tps6507x_pmic_ops;
+		tps->desc[i].type = REGULATOR_VOLTAGE;
+		tps->desc[i].owner = THIS_MODULE;
+
+		rdev = regulator_register(&tps->desc[i],
+					tps6507x_dev->dev, init_data, tps, NULL);
+		if (IS_ERR(rdev)) {
+			dev_err(tps6507x_dev->dev,
+				"failed to register %s regulator\n",
+				pdev->name);
+			error = PTR_ERR(rdev);
+			goto fail;
+		}
+
+		/* Save regulator for cleanup */
+		tps->rdev[i] = rdev;
+	}
+
+	tps6507x_dev->pmic = tps;
+	platform_set_drvdata(pdev, tps6507x_dev);
+
+	return 0;
+
+fail:
+	while (--i >= 0)
+		regulator_unregister(tps->rdev[i]);
+
+	kfree(tps);
+	return error;
+}
+
+static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
+{
+	struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
+	struct tps6507x_pmic *tps = tps6507x_dev->pmic;
+	int i;
+
+	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
+		regulator_unregister(tps->rdev[i]);
+
+	kfree(tps);
+
+	return 0;
+}
+
+static struct platform_driver tps6507x_pmic_driver = {
+	.driver = {
+		.name = "tps6507x-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = tps6507x_pmic_probe,
+	.remove = __devexit_p(tps6507x_pmic_remove),
+};
+
+static int __init tps6507x_pmic_init(void)
+{
+	return platform_driver_register(&tps6507x_pmic_driver);
+}
+subsys_initcall(tps6507x_pmic_init);
+
+static void __exit tps6507x_pmic_cleanup(void)
+{
+	platform_driver_unregister(&tps6507x_pmic_driver);
+}
+module_exit(tps6507x_pmic_cleanup);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps6507x-pmic");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/tps65217-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/tps65217-regulator.c
new file mode 100644
index 0000000..e39521b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/tps65217-regulator.c
@@ -0,0 +1,378 @@
+/*
+ * tps65217-regulator.c
+ *
+ * Regulator driver for TPS65217 PMIC
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/tps65217.h>
+
+#define TPS65217_REGULATOR(_name, _id, _ops, _n)	\
+	{						\
+		.name		= _name,		\
+		.id		= _id,			\
+		.ops		= &_ops,		\
+		.n_voltages	= _n,			\
+		.type		= REGULATOR_VOLTAGE,	\
+		.owner		= THIS_MODULE,		\
+	}						\
+
+#define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n, _em, _vr, _vm)	\
+	{						\
+		.name		= _nm,			\
+		.min_uV		= _min,			\
+		.max_uV		= _max,			\
+		.vsel_to_uv	= _f1,			\
+		.uv_to_vsel	= _f2,			\
+		.table		= _t,			\
+		.table_len	= _n,			\
+		.enable_mask	= _em,			\
+		.set_vout_reg	= _vr,			\
+		.set_vout_mask	= _vm,			\
+	}
+
+static const int LDO1_VSEL_table[] = {
+	1000000, 1100000, 1200000, 1250000,
+	1300000, 1350000, 1400000, 1500000,
+	1600000, 1800000, 2500000, 2750000,
+	2800000, 3000000, 3100000, 3300000,
+};
+
+static int tps65217_vsel_to_uv1(unsigned int vsel)
+{
+	int uV = 0;
+
+	if (vsel > 63)
+		return -EINVAL;
+
+	if (vsel <= 24)
+		uV = vsel * 25000 + 900000;
+	else if (vsel <= 52)
+		uV = (vsel - 24) * 50000 + 1500000;
+	else if (vsel < 56)
+		uV = (vsel - 52) * 100000 + 2900000;
+	else
+		uV = 3300000;
+
+	return uV;
+}
+
+static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel)
+{
+	if ((uV < 0) && (uV > 3300000))
+		return -EINVAL;
+
+	if (uV <= 1500000)
+		*vsel = DIV_ROUND_UP(uV - 900000, 25000);
+	else if (uV <= 2900000)
+		*vsel = 24 + DIV_ROUND_UP(uV - 1500000, 50000);
+	else if (uV < 3300000)
+		*vsel = 52 + DIV_ROUND_UP(uV - 2900000, 100000);
+	else
+		*vsel = 56;
+
+	return 0;
+}
+
+static int tps65217_vsel_to_uv2(unsigned int vsel)
+{
+	int uV = 0;
+
+	if (vsel > 31)
+		return -EINVAL;
+
+	if (vsel <= 8)
+		uV = vsel * 50000 + 1500000;
+	else if (vsel <= 13)
+		uV = (vsel - 8) * 100000 + 1900000;
+	else
+		uV = (vsel - 13) * 50000 + 2400000;
+
+	return uV;
+}
+
+static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel)
+{
+	if ((uV < 0) && (uV > 3300000))
+		return -EINVAL;
+
+	if (uV <= 1900000)
+		*vsel = DIV_ROUND_UP(uV - 1500000, 50000);
+	else if (uV <= 2400000)
+		*vsel = 8 + DIV_ROUND_UP(uV - 1900000, 100000);
+	else
+		*vsel = 13 + DIV_ROUND_UP(uV - 2400000, 50000);
+
+	return 0;
+}
+
+static struct tps_info tps65217_pmic_regs[] = {
+	TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1,
+			tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC1_EN,
+			TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK),
+	TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1,
+			tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC2_EN,
+			TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK),
+	TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1,
+			tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC3_EN,
+			TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK),
+	TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL, LDO1_VSEL_table,
+			16, TPS65217_ENABLE_LDO1_EN, TPS65217_REG_DEFLDO1,
+			TPS65217_DEFLDO1_LDO1_MASK),
+	TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1,
+			tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_LDO2_EN,
+			TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK),
+	TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2,
+			tps65217_uv_to_vsel2, NULL, 32,
+			TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
+			TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK),
+	TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2,
+			tps65217_uv_to_vsel2, NULL, 32,
+			TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
+			TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK),
+};
+
+static int tps65217_pmic_is_enabled(struct regulator_dev *dev)
+{
+	int ret;
+	struct tps65217 *tps = rdev_get_drvdata(dev);
+	unsigned int data, rid = rdev_get_id(dev);
+
+	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
+		return -EINVAL;
+
+	ret = tps65217_reg_read(tps, TPS65217_REG_ENABLE, &data);
+	if (ret)
+		return ret;
+
+	return (data & tps->info[rid]->enable_mask) ? 1 : 0;
+}
+
+static int tps65217_pmic_enable(struct regulator_dev *dev)
+{
+	struct tps65217 *tps = rdev_get_drvdata(dev);
+	unsigned int rid = rdev_get_id(dev);
+
+	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
+		return -EINVAL;
+
+	/* Enable the regulator and password protection is level 1 */
+	return tps65217_set_bits(tps, TPS65217_REG_ENABLE,
+				tps->info[rid]->enable_mask,
+				tps->info[rid]->enable_mask,
+				TPS65217_PROTECT_L1);
+}
+
+static int tps65217_pmic_disable(struct regulator_dev *dev)
+{
+	struct tps65217 *tps = rdev_get_drvdata(dev);
+	unsigned int rid = rdev_get_id(dev);
+
+	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
+		return -EINVAL;
+
+	/* Disable the regulator and password protection is level 1 */
+	return tps65217_clear_bits(tps, TPS65217_REG_ENABLE,
+			tps->info[rid]->enable_mask, TPS65217_PROTECT_L1);
+}
+
+static int tps65217_pmic_get_voltage_sel(struct regulator_dev *dev)
+{
+	int ret;
+	struct tps65217 *tps = rdev_get_drvdata(dev);
+	unsigned int selector, rid = rdev_get_id(dev);
+
+	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
+		return -EINVAL;
+
+	ret = tps65217_reg_read(tps, tps->info[rid]->set_vout_reg, &selector);
+	if (ret)
+		return ret;
+
+	selector &= tps->info[rid]->set_vout_mask;
+
+	return selector;
+}
+
+static int tps65217_pmic_ldo1_set_voltage_sel(struct regulator_dev *dev,
+						unsigned selector)
+{
+	struct tps65217 *tps = rdev_get_drvdata(dev);
+	int ldo = rdev_get_id(dev);
+
+	if (ldo != TPS65217_LDO_1)
+		return -EINVAL;
+
+	if (selector >= tps->info[ldo]->table_len)
+		return -EINVAL;
+
+	/* Set the voltage based on vsel value and write protect level is 2 */
+	return tps65217_set_bits(tps, tps->info[ldo]->set_vout_reg,
+					tps->info[ldo]->set_vout_mask,
+					selector, TPS65217_PROTECT_L2);
+}
+
+static int tps65217_pmic_set_voltage(struct regulator_dev *dev,
+				  int min_uV, int max_uV, unsigned *selector)
+{
+	int ret;
+	struct tps65217 *tps = rdev_get_drvdata(dev);
+	unsigned int rid = rdev_get_id(dev);
+
+	/* LDO1 implements set_voltage_sel callback */
+	if (rid == TPS65217_LDO_1)
+		return -EINVAL;
+
+	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
+		return -EINVAL;
+
+	if (min_uV < tps->info[rid]->min_uV
+		|| min_uV > tps->info[rid]->max_uV)
+		return -EINVAL;
+
+	if (max_uV < tps->info[rid]->min_uV
+		|| max_uV > tps->info[rid]->max_uV)
+		return -EINVAL;
+
+	ret = tps->info[rid]->uv_to_vsel(min_uV, selector);
+	if (ret)
+		return ret;
+
+	/* Set the voltage based on vsel value and write protect level is 2 */
+	ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg,
+				tps->info[rid]->set_vout_mask,
+				*selector, TPS65217_PROTECT_L2);
+
+	/* Set GO bit for DCDCx to initiate voltage transistion */
+	switch (rid) {
+	case TPS65217_DCDC_1 ... TPS65217_DCDC_3:
+		ret = tps65217_set_bits(tps, TPS65217_REG_DEFSLEW,
+				       TPS65217_DEFSLEW_GO, TPS65217_DEFSLEW_GO,
+				       TPS65217_PROTECT_L2);
+		break;
+	}
+
+	return ret;
+}
+
+static int tps65217_pmic_list_voltage(struct regulator_dev *dev,
+					unsigned selector)
+{
+	struct tps65217 *tps = rdev_get_drvdata(dev);
+	unsigned int rid = rdev_get_id(dev);
+
+	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
+		return -EINVAL;
+
+	if (selector >= tps->info[rid]->table_len)
+		return -EINVAL;
+
+	if (tps->info[rid]->table)
+		return tps->info[rid]->table[selector];
+
+	return tps->info[rid]->vsel_to_uv(selector);
+}
+
+/* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */
+static struct regulator_ops tps65217_pmic_ops = {
+	.is_enabled		= tps65217_pmic_is_enabled,
+	.enable			= tps65217_pmic_enable,
+	.disable		= tps65217_pmic_disable,
+	.get_voltage_sel	= tps65217_pmic_get_voltage_sel,
+	.set_voltage		= tps65217_pmic_set_voltage,
+	.list_voltage		= tps65217_pmic_list_voltage,
+};
+
+/* Operations permitted on LDO1 */
+static struct regulator_ops tps65217_pmic_ldo1_ops = {
+	.is_enabled		= tps65217_pmic_is_enabled,
+	.enable			= tps65217_pmic_enable,
+	.disable		= tps65217_pmic_disable,
+	.get_voltage_sel	= tps65217_pmic_get_voltage_sel,
+	.set_voltage_sel	= tps65217_pmic_ldo1_set_voltage_sel,
+	.list_voltage		= tps65217_pmic_list_voltage,
+};
+
+static struct regulator_desc regulators[] = {
+	TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64),
+	TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64),
+	TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64),
+	TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16),
+	TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64),
+	TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32),
+	TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32),
+};
+
+static int __devinit tps65217_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev;
+	struct tps65217 *tps;
+	struct tps_info *info = &tps65217_pmic_regs[pdev->id];
+
+	/* Already set by core driver */
+	tps = dev_to_tps65217(pdev->dev.parent);
+	tps->info[pdev->id] = info;
+
+	rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
+				  pdev->dev.platform_data, tps, NULL);
+	if (IS_ERR(rdev))
+		return PTR_ERR(rdev);
+
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+}
+
+static int __devexit tps65217_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	regulator_unregister(rdev);
+
+	return 0;
+}
+
+static struct platform_driver tps65217_regulator_driver = {
+	.driver = {
+		.name = "tps65217-pmic",
+	},
+	.probe = tps65217_regulator_probe,
+	.remove = __devexit_p(tps65217_regulator_remove),
+};
+
+static int __init tps65217_regulator_init(void)
+{
+	return platform_driver_register(&tps65217_regulator_driver);
+}
+subsys_initcall(tps65217_regulator_init);
+
+static void __exit tps65217_regulator_exit(void)
+{
+	platform_driver_unregister(&tps65217_regulator_driver);
+}
+module_exit(tps65217_regulator_exit);
+
+MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>");
+MODULE_DESCRIPTION("TPS65217 voltage regulator driver");
+MODULE_ALIAS("platform:tps65217-pmic");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/tps6524x-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/tps6524x-regulator.c
new file mode 100644
index 0000000..4a421be
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/tps6524x-regulator.c
@@ -0,0 +1,691 @@
+/*
+ * Regulator driver for TPS6524x PMIC
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define REG_LDO_SET		0x0
+#define LDO_ILIM_MASK		1	/* 0 = 400-800, 1 = 900-1500 */
+#define LDO_VSEL_MASK		0x0f
+#define LDO2_ILIM_SHIFT		12
+#define LDO2_VSEL_SHIFT		4
+#define LDO1_ILIM_SHIFT		8
+#define LDO1_VSEL_SHIFT		0
+
+#define REG_BLOCK_EN		0x1
+#define BLOCK_MASK		1
+#define BLOCK_LDO1_SHIFT	0
+#define BLOCK_LDO2_SHIFT	1
+#define BLOCK_LCD_SHIFT		2
+#define BLOCK_USB_SHIFT		3
+
+#define REG_DCDC_SET		0x2
+#define DCDC_VDCDC_MASK		0x1f
+#define DCDC_VDCDC1_SHIFT	0
+#define DCDC_VDCDC2_SHIFT	5
+#define DCDC_VDCDC3_SHIFT	10
+
+#define REG_DCDC_EN		0x3
+#define DCDCDCDC_EN_MASK	0x1
+#define DCDCDCDC1_EN_SHIFT	0
+#define DCDCDCDC1_PG_MSK	BIT(1)
+#define DCDCDCDC2_EN_SHIFT	2
+#define DCDCDCDC2_PG_MSK	BIT(3)
+#define DCDCDCDC3_EN_SHIFT	4
+#define DCDCDCDC3_PG_MSK	BIT(5)
+
+#define REG_USB			0x4
+#define USB_ILIM_SHIFT		0
+#define USB_ILIM_MASK		0x3
+#define USB_TSD_SHIFT		2
+#define USB_TSD_MASK		0x3
+#define USB_TWARN_SHIFT		4
+#define USB_TWARN_MASK		0x3
+#define USB_IWARN_SD		BIT(6)
+#define USB_FAST_LOOP		BIT(7)
+
+#define REG_ALARM		0x5
+#define ALARM_LDO1		BIT(0)
+#define ALARM_DCDC1		BIT(1)
+#define ALARM_DCDC2		BIT(2)
+#define ALARM_DCDC3		BIT(3)
+#define ALARM_LDO2		BIT(4)
+#define ALARM_USB_WARN		BIT(5)
+#define ALARM_USB_ALARM		BIT(6)
+#define ALARM_LCD		BIT(9)
+#define ALARM_TEMP_WARM		BIT(10)
+#define ALARM_TEMP_HOT		BIT(11)
+#define ALARM_NRST		BIT(14)
+#define ALARM_POWERUP		BIT(15)
+
+#define REG_INT_ENABLE		0x6
+#define INT_LDO1		BIT(0)
+#define INT_DCDC1		BIT(1)
+#define INT_DCDC2		BIT(2)
+#define INT_DCDC3		BIT(3)
+#define INT_LDO2		BIT(4)
+#define INT_USB_WARN		BIT(5)
+#define INT_USB_ALARM		BIT(6)
+#define INT_LCD			BIT(9)
+#define INT_TEMP_WARM		BIT(10)
+#define INT_TEMP_HOT		BIT(11)
+#define INT_GLOBAL_EN		BIT(15)
+
+#define REG_INT_STATUS		0x7
+#define STATUS_LDO1		BIT(0)
+#define STATUS_DCDC1		BIT(1)
+#define STATUS_DCDC2		BIT(2)
+#define STATUS_DCDC3		BIT(3)
+#define STATUS_LDO2		BIT(4)
+#define STATUS_USB_WARN		BIT(5)
+#define STATUS_USB_ALARM	BIT(6)
+#define STATUS_LCD		BIT(9)
+#define STATUS_TEMP_WARM	BIT(10)
+#define STATUS_TEMP_HOT		BIT(11)
+
+#define REG_SOFTWARE_RESET	0xb
+#define REG_WRITE_ENABLE	0xd
+#define REG_REV_ID		0xf
+
+#define N_DCDC			3
+#define N_LDO			2
+#define N_SWITCH		2
+#define N_REGULATORS		(N_DCDC + N_LDO + N_SWITCH)
+
+#define FIXED_ILIMSEL		BIT(0)
+#define FIXED_VOLTAGE		BIT(1)
+
+#define CMD_READ(reg)		((reg) << 6)
+#define CMD_WRITE(reg)		(BIT(5) | (reg) << 6)
+#define STAT_CLK		BIT(3)
+#define STAT_WRITE		BIT(2)
+#define STAT_INVALID		BIT(1)
+#define STAT_WP			BIT(0)
+
+struct field {
+	int		reg;
+	int		shift;
+	int		mask;
+};
+
+struct supply_info {
+	const char	*name;
+	int		n_voltages;
+	const int	*voltages;
+	int		fixed_voltage;
+	int		n_ilimsels;
+	const int	*ilimsels;
+	int		fixed_ilimsel;
+	int		flags;
+	struct field	enable, voltage, ilimsel;
+};
+
+struct tps6524x {
+	struct device		*dev;
+	struct spi_device	*spi;
+	struct mutex		lock;
+	struct regulator_desc	desc[N_REGULATORS];
+	struct regulator_dev	*rdev[N_REGULATORS];
+};
+
+static int __read_reg(struct tps6524x *hw, int reg)
+{
+	int error = 0;
+	u16 cmd = CMD_READ(reg), in;
+	u8 status;
+	struct spi_message m;
+	struct spi_transfer t[3];
+
+	spi_message_init(&m);
+	memset(t, 0, sizeof(t));
+
+	t[0].tx_buf = &cmd;
+	t[0].len = 2;
+	t[0].bits_per_word = 12;
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].rx_buf = &in;
+	t[1].len = 2;
+	t[1].bits_per_word = 16;
+	spi_message_add_tail(&t[1], &m);
+
+	t[2].rx_buf = &status;
+	t[2].len = 1;
+	t[2].bits_per_word = 4;
+	spi_message_add_tail(&t[2], &m);
+
+	error = spi_sync(hw->spi, &m);
+	if (error < 0)
+		return error;
+
+	dev_dbg(hw->dev, "read reg %d, data %x, status %x\n",
+		reg, in, status);
+
+	if (!(status & STAT_CLK) || (status & STAT_WRITE))
+		return -EIO;
+
+	if (status & STAT_INVALID)
+		return -EINVAL;
+
+	return in;
+}
+
+static int read_reg(struct tps6524x *hw, int reg)
+{
+	int ret;
+
+	mutex_lock(&hw->lock);
+	ret = __read_reg(hw, reg);
+	mutex_unlock(&hw->lock);
+
+	return ret;
+}
+
+static int __write_reg(struct tps6524x *hw, int reg, int val)
+{
+	int error = 0;
+	u16 cmd = CMD_WRITE(reg), out = val;
+	u8 status;
+	struct spi_message m;
+	struct spi_transfer t[3];
+
+	spi_message_init(&m);
+	memset(t, 0, sizeof(t));
+
+	t[0].tx_buf = &cmd;
+	t[0].len = 2;
+	t[0].bits_per_word = 12;
+	spi_message_add_tail(&t[0], &m);
+
+	t[1].tx_buf = &out;
+	t[1].len = 2;
+	t[1].bits_per_word = 16;
+	spi_message_add_tail(&t[1], &m);
+
+	t[2].rx_buf = &status;
+	t[2].len = 1;
+	t[2].bits_per_word = 4;
+	spi_message_add_tail(&t[2], &m);
+
+	error = spi_sync(hw->spi, &m);
+	if (error < 0)
+		return error;
+
+	dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n",
+		reg, out, status);
+
+	if (!(status & STAT_CLK) || !(status & STAT_WRITE))
+		return -EIO;
+
+	if (status & (STAT_INVALID | STAT_WP))
+		return -EINVAL;
+
+	return error;
+}
+
+static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val)
+{
+	int ret;
+
+	ret = __read_reg(hw, reg);
+	if (ret < 0)
+		return ret;
+
+	ret &= ~mask;
+	ret |= val;
+
+	ret = __write_reg(hw, reg, ret);
+
+	return (ret < 0) ? ret : 0;
+}
+
+static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val)
+{
+	int ret;
+
+	mutex_lock(&hw->lock);
+
+	ret = __write_reg(hw, REG_WRITE_ENABLE, 1);
+	if (ret) {
+		dev_err(hw->dev, "failed to set write enable\n");
+		goto error;
+	}
+
+	ret = __rmw_reg(hw, reg, mask, val);
+	if (ret)
+		dev_err(hw->dev, "failed to rmw register %d\n", reg);
+
+	ret = __write_reg(hw, REG_WRITE_ENABLE, 0);
+	if (ret) {
+		dev_err(hw->dev, "failed to clear write enable\n");
+		goto error;
+	}
+
+error:
+	mutex_unlock(&hw->lock);
+
+	return ret;
+}
+
+static int read_field(struct tps6524x *hw, const struct field *field)
+{
+	int tmp;
+
+	tmp = read_reg(hw, field->reg);
+	if (tmp < 0)
+		return tmp;
+
+	return (tmp >> field->shift) & field->mask;
+}
+
+static int write_field(struct tps6524x *hw, const struct field *field,
+		       int val)
+{
+	if (val & ~field->mask)
+		return -EOVERFLOW;
+
+	return rmw_protect(hw, field->reg,
+				    field->mask << field->shift,
+				    val << field->shift);
+}
+
+static const int dcdc1_voltages[] = {
+	 800000,  825000,  850000,  875000,
+	 900000,  925000,  950000,  975000,
+	1000000, 1025000, 1050000, 1075000,
+	1100000, 1125000, 1150000, 1175000,
+	1200000, 1225000, 1250000, 1275000,
+	1300000, 1325000, 1350000, 1375000,
+	1400000, 1425000, 1450000, 1475000,
+	1500000, 1525000, 1550000, 1575000,
+};
+
+static const int dcdc2_voltages[] = {
+	1400000, 1450000, 1500000, 1550000,
+	1600000, 1650000, 1700000, 1750000,
+	1800000, 1850000, 1900000, 1950000,
+	2000000, 2050000, 2100000, 2150000,
+	2200000, 2250000, 2300000, 2350000,
+	2400000, 2450000, 2500000, 2550000,
+	2600000, 2650000, 2700000, 2750000,
+	2800000, 2850000, 2900000, 2950000,
+};
+
+static const int dcdc3_voltages[] = {
+	2400000, 2450000, 2500000, 2550000, 2600000,
+	2650000, 2700000, 2750000, 2800000, 2850000,
+	2900000, 2950000, 3000000, 3050000, 3100000,
+	3150000, 3200000, 3250000, 3300000, 3350000,
+	3400000, 3450000, 3500000, 3550000, 3600000,
+};
+
+static const int ldo1_voltages[] = {
+	4300000, 4350000, 4400000, 4450000,
+	4500000, 4550000, 4600000, 4650000,
+	4700000, 4750000, 4800000, 4850000,
+	4900000, 4950000, 5000000, 5050000,
+};
+
+static const int ldo2_voltages[] = {
+	1100000, 1150000, 1200000, 1250000,
+	1300000, 1700000, 1750000, 1800000,
+	1850000, 1900000, 3150000, 3200000,
+	3250000, 3300000, 3350000, 3400000,
+};
+
+static const int ldo_ilimsel[] = {
+	400000, 1500000
+};
+
+static const int usb_ilimsel[] = {
+	200000, 400000, 800000, 1000000
+};
+
+#define __MK_FIELD(_reg, _mask, _shift) \
+	{ .reg = (_reg), .mask = (_mask), .shift = (_shift), }
+
+static const struct supply_info supply_info[N_REGULATORS] = {
+	{
+		.name		= "DCDC1",
+		.flags		= FIXED_ILIMSEL,
+		.n_voltages	= ARRAY_SIZE(dcdc1_voltages),
+		.voltages	= dcdc1_voltages,
+		.fixed_ilimsel	= 2400000,
+		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
+					     DCDCDCDC1_EN_SHIFT),
+		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
+					     DCDC_VDCDC1_SHIFT),
+	},
+	{
+		.name		= "DCDC2",
+		.flags		= FIXED_ILIMSEL,
+		.n_voltages	= ARRAY_SIZE(dcdc2_voltages),
+		.voltages	= dcdc2_voltages,
+		.fixed_ilimsel	= 1200000,
+		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
+					     DCDCDCDC2_EN_SHIFT),
+		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
+					     DCDC_VDCDC2_SHIFT),
+	},
+	{
+		.name		= "DCDC3",
+		.flags		= FIXED_ILIMSEL,
+		.n_voltages	= ARRAY_SIZE(dcdc3_voltages),
+		.voltages	= dcdc3_voltages,
+		.fixed_ilimsel	= 1200000,
+		.enable		= __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
+					DCDCDCDC3_EN_SHIFT),
+		.voltage	= __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
+					     DCDC_VDCDC3_SHIFT),
+	},
+	{
+		.name		= "LDO1",
+		.n_voltages	= ARRAY_SIZE(ldo1_voltages),
+		.voltages	= ldo1_voltages,
+		.n_ilimsels	= ARRAY_SIZE(ldo_ilimsel),
+		.ilimsels	= ldo_ilimsel,
+		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+					     BLOCK_LDO1_SHIFT),
+		.voltage	= __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
+					     LDO1_VSEL_SHIFT),
+		.ilimsel	= __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
+					     LDO1_ILIM_SHIFT),
+	},
+	{
+		.name		= "LDO2",
+		.n_voltages	= ARRAY_SIZE(ldo2_voltages),
+		.voltages	= ldo2_voltages,
+		.n_ilimsels	= ARRAY_SIZE(ldo_ilimsel),
+		.ilimsels	= ldo_ilimsel,
+		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+					     BLOCK_LDO2_SHIFT),
+		.voltage	= __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK,
+					     LDO2_VSEL_SHIFT),
+		.ilimsel	= __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK,
+					     LDO2_ILIM_SHIFT),
+	},
+	{
+		.name		= "USB",
+		.flags		= FIXED_VOLTAGE,
+		.fixed_voltage	= 5000000,
+		.n_ilimsels	= ARRAY_SIZE(usb_ilimsel),
+		.ilimsels	= usb_ilimsel,
+		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+					     BLOCK_USB_SHIFT),
+		.ilimsel	= __MK_FIELD(REG_USB, USB_ILIM_MASK,
+					     USB_ILIM_SHIFT),
+	},
+	{
+		.name		= "LCD",
+		.flags		= FIXED_VOLTAGE | FIXED_ILIMSEL,
+		.fixed_voltage	= 5000000,
+		.fixed_ilimsel	=  400000,
+		.enable		= __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
+					     BLOCK_LCD_SHIFT),
+	},
+};
+
+static int list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_VOLTAGE)
+		return selector ? -EINVAL : info->fixed_voltage;
+
+	return ((selector < info->n_voltages) ?
+		info->voltages[selector] : -EINVAL);
+}
+
+static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+		       unsigned *selector)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+	unsigned i;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_VOLTAGE)
+		return -EINVAL;
+
+	for (i = 0; i < info->n_voltages; i++)
+		if (min_uV <= info->voltages[i] &&
+		    max_uV >= info->voltages[i])
+			break;
+
+	if (i >= info->n_voltages)
+		i = info->n_voltages - 1;
+
+	*selector = i;
+
+	return write_field(hw, &info->voltage, i);
+}
+
+static int get_voltage(struct regulator_dev *rdev)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+	int ret;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_VOLTAGE)
+		return info->fixed_voltage;
+
+	ret = read_field(hw, &info->voltage);
+	if (ret < 0)
+		return ret;
+	if (WARN_ON(ret >= info->n_voltages))
+		return -EIO;
+
+	return info->voltages[ret];
+}
+
+static int set_current_limit(struct regulator_dev *rdev, int min_uA,
+			     int max_uA)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+	int i;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_ILIMSEL)
+		return -EINVAL;
+
+	for (i = 0; i < info->n_ilimsels; i++)
+		if (min_uA <= info->ilimsels[i] &&
+		    max_uA >= info->ilimsels[i])
+			break;
+
+	if (i >= info->n_ilimsels)
+		return -EINVAL;
+
+	return write_field(hw, &info->ilimsel, i);
+}
+
+static int get_current_limit(struct regulator_dev *rdev)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+	int ret;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	if (info->flags & FIXED_ILIMSEL)
+		return info->fixed_ilimsel;
+
+	ret = read_field(hw, &info->ilimsel);
+	if (ret < 0)
+		return ret;
+	if (WARN_ON(ret >= info->n_ilimsels))
+		return -EIO;
+
+	return info->ilimsels[ret];
+}
+
+static int enable_supply(struct regulator_dev *rdev)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	return write_field(hw, &info->enable, 1);
+}
+
+static int disable_supply(struct regulator_dev *rdev)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	return write_field(hw, &info->enable, 0);
+}
+
+static int is_supply_enabled(struct regulator_dev *rdev)
+{
+	const struct supply_info *info;
+	struct tps6524x *hw;
+
+	hw	= rdev_get_drvdata(rdev);
+	info	= &supply_info[rdev_get_id(rdev)];
+
+	return read_field(hw, &info->enable);
+}
+
+static struct regulator_ops regulator_ops = {
+	.is_enabled		= is_supply_enabled,
+	.enable			= enable_supply,
+	.disable		= disable_supply,
+	.get_voltage		= get_voltage,
+	.set_voltage		= set_voltage,
+	.list_voltage		= list_voltage,
+	.set_current_limit	= set_current_limit,
+	.get_current_limit	= get_current_limit,
+};
+
+static int pmic_remove(struct spi_device *spi)
+{
+	struct tps6524x *hw = spi_get_drvdata(spi);
+	int i;
+
+	if (!hw)
+		return 0;
+	for (i = 0; i < N_REGULATORS; i++) {
+		if (hw->rdev[i])
+			regulator_unregister(hw->rdev[i]);
+		hw->rdev[i] = NULL;
+	}
+	spi_set_drvdata(spi, NULL);
+	kfree(hw);
+	return 0;
+}
+
+static int __devinit pmic_probe(struct spi_device *spi)
+{
+	struct tps6524x *hw;
+	struct device *dev = &spi->dev;
+	const struct supply_info *info = supply_info;
+	struct regulator_init_data *init_data;
+	int ret = 0, i;
+
+	init_data = dev->platform_data;
+	if (!init_data) {
+		dev_err(dev, "could not find regulator platform data\n");
+		return -EINVAL;
+	}
+
+	hw = kzalloc(sizeof(struct tps6524x), GFP_KERNEL);
+	if (!hw) {
+		dev_err(dev, "cannot allocate regulator private data\n");
+		return -ENOMEM;
+	}
+	spi_set_drvdata(spi, hw);
+
+	memset(hw, 0, sizeof(struct tps6524x));
+	hw->dev = dev;
+	hw->spi = spi_dev_get(spi);
+	mutex_init(&hw->lock);
+
+	for (i = 0; i < N_REGULATORS; i++, info++, init_data++) {
+		hw->desc[i].name	= info->name;
+		hw->desc[i].id		= i;
+		hw->desc[i].n_voltages	= info->n_voltages;
+		hw->desc[i].ops		= &regulator_ops;
+		hw->desc[i].type	= REGULATOR_VOLTAGE;
+		hw->desc[i].owner	= THIS_MODULE;
+
+		if (info->flags & FIXED_VOLTAGE)
+			hw->desc[i].n_voltages = 1;
+
+		hw->rdev[i] = regulator_register(&hw->desc[i], dev,
+						 init_data, hw, NULL);
+		if (IS_ERR(hw->rdev[i])) {
+			ret = PTR_ERR(hw->rdev[i]);
+			hw->rdev[i] = NULL;
+			goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	pmic_remove(spi);
+	return ret;
+}
+
+static struct spi_driver pmic_driver = {
+	.probe		= pmic_probe,
+	.remove		= __devexit_p(pmic_remove),
+	.driver		= {
+		.name	= "tps6524x",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pmic_driver_init(void)
+{
+	return spi_register_driver(&pmic_driver);
+}
+module_init(pmic_driver_init);
+
+static void __exit pmic_driver_exit(void)
+{
+	spi_unregister_driver(&pmic_driver);
+}
+module_exit(pmic_driver_exit);
+
+MODULE_DESCRIPTION("TPS6524X PMIC Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:tps6524x");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/tps6586x-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/tps6586x-regulator.c
new file mode 100644
index 0000000..cfc1f16
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/tps6586x-regulator.c
@@ -0,0 +1,448 @@
+/*
+ * Regulator driver for TI TPS6586x
+ *
+ * Copyright (C) 2010 Compulab Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on da903x
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Copyright (C) 2008 Compulab Ltd.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/tps6586x.h>
+
+/* supply control and voltage setting  */
+#define TPS6586X_SUPPLYENA	0x10
+#define TPS6586X_SUPPLYENB	0x11
+#define TPS6586X_SUPPLYENC	0x12
+#define TPS6586X_SUPPLYEND	0x13
+#define TPS6586X_SUPPLYENE	0x14
+#define TPS6586X_VCC1		0x20
+#define TPS6586X_VCC2		0x21
+#define TPS6586X_SM1V1		0x23
+#define TPS6586X_SM1V2		0x24
+#define TPS6586X_SM1SL		0x25
+#define TPS6586X_SM0V1		0x26
+#define TPS6586X_SM0V2		0x27
+#define TPS6586X_SM0SL		0x28
+#define TPS6586X_LDO2AV1	0x29
+#define TPS6586X_LDO2AV2	0x2A
+#define TPS6586X_LDO2BV1	0x2F
+#define TPS6586X_LDO2BV2	0x30
+#define TPS6586X_LDO4V1		0x32
+#define TPS6586X_LDO4V2		0x33
+
+/* converter settings  */
+#define TPS6586X_SUPPLYV1	0x41
+#define TPS6586X_SUPPLYV2	0x42
+#define TPS6586X_SUPPLYV3	0x43
+#define TPS6586X_SUPPLYV4	0x44
+#define TPS6586X_SUPPLYV5	0x45
+#define TPS6586X_SUPPLYV6	0x46
+#define TPS6586X_SMODE1		0x47
+#define TPS6586X_SMODE2		0x48
+
+struct tps6586x_regulator {
+	struct regulator_desc desc;
+
+	int volt_reg;
+	int volt_shift;
+	int volt_nbits;
+	int enable_bit[2];
+	int enable_reg[2];
+
+	int *voltages;
+
+	/* for DVM regulators */
+	int go_reg;
+	int go_bit;
+};
+
+static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
+{
+	return rdev_get_dev(rdev)->parent->parent;
+}
+
+static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev,
+				     unsigned selector)
+{
+	struct tps6586x_regulator *info = rdev_get_drvdata(rdev);
+	int rid = rdev_get_id(rdev);
+
+	/* LDO0 has minimal voltage 1.2V rather than 1.25V */
+	if ((rid == TPS6586X_ID_LDO_0) && (selector == 0))
+		return (info->voltages[0] - 50) * 1000;
+
+	return info->voltages[selector] * 1000;
+}
+
+
+static int __tps6586x_ldo_set_voltage(struct device *parent,
+				      struct tps6586x_regulator *ri,
+				      int min_uV, int max_uV,
+				      unsigned *selector)
+{
+	int val, uV;
+	uint8_t mask;
+
+	for (val = 0; val < ri->desc.n_voltages; val++) {
+		uV = ri->voltages[val] * 1000;
+
+		/* LDO0 has minimal voltage 1.2 rather than 1.25 */
+		if (ri->desc.id == TPS6586X_ID_LDO_0 && val == 0)
+			uV -= 50 * 1000;
+
+		/* use the first in-range value */
+		if (min_uV <= uV && uV <= max_uV) {
+
+			*selector = val;
+
+			val <<= ri->volt_shift;
+			mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
+
+			return tps6586x_update(parent, ri->volt_reg, val, mask);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int tps6586x_ldo_set_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV, unsigned *selector)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+
+	return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV,
+					  selector);
+}
+
+static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+	uint8_t val, mask;
+	int ret;
+
+	ret = tps6586x_read(parent, ri->volt_reg, &val);
+	if (ret)
+		return ret;
+
+	mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
+	val = (val & mask) >> ri->volt_shift;
+
+	if (val >= ri->desc.n_voltages)
+		BUG();
+
+	return ri->voltages[val] * 1000;
+}
+
+static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV, unsigned *selector)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+	int ret;
+
+	ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV,
+					 selector);
+	if (ret)
+		return ret;
+
+	return tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit);
+}
+
+static int tps6586x_regulator_enable(struct regulator_dev *rdev)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+
+	return tps6586x_set_bits(parent, ri->enable_reg[0],
+				 1 << ri->enable_bit[0]);
+}
+
+static int tps6586x_regulator_disable(struct regulator_dev *rdev)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+
+	return tps6586x_clr_bits(parent, ri->enable_reg[0],
+				 1 << ri->enable_bit[0]);
+}
+
+static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+	uint8_t reg_val;
+	int ret;
+
+	ret = tps6586x_read(parent, ri->enable_reg[0], &reg_val);
+	if (ret)
+		return ret;
+
+	return !!(reg_val & (1 << ri->enable_bit[0]));
+}
+
+static struct regulator_ops tps6586x_regulator_ldo_ops = {
+	.list_voltage = tps6586x_ldo_list_voltage,
+	.get_voltage = tps6586x_ldo_get_voltage,
+	.set_voltage = tps6586x_ldo_set_voltage,
+
+	.is_enabled = tps6586x_regulator_is_enabled,
+	.enable = tps6586x_regulator_enable,
+	.disable = tps6586x_regulator_disable,
+};
+
+static struct regulator_ops tps6586x_regulator_dvm_ops = {
+	.list_voltage = tps6586x_ldo_list_voltage,
+	.get_voltage = tps6586x_ldo_get_voltage,
+	.set_voltage = tps6586x_dvm_set_voltage,
+
+	.is_enabled = tps6586x_regulator_is_enabled,
+	.enable = tps6586x_regulator_enable,
+	.disable = tps6586x_regulator_disable,
+};
+
+static int tps6586x_ldo_voltages[] = {
+	1250, 1500, 1800, 2500, 2700, 2850, 3100, 3300,
+};
+
+static int tps6586x_ldo4_voltages[] = {
+	1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
+	1900, 1925, 1950, 1975, 2000, 2025, 2050, 2075,
+	2100, 2125, 2150, 2175, 2200, 2225, 2250, 2275,
+	2300, 2325, 2350, 2375, 2400, 2425, 2450, 2475,
+};
+
+static int tps6586x_sm2_voltages[] = {
+	3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350,
+	3400, 3450, 3500, 3550, 3600, 3650, 3700, 3750,
+	3800, 3850, 3900, 3950, 4000, 4050, 4100, 4150,
+	4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550,
+};
+
+static int tps6586x_dvm_voltages[] = {
+	 725,  750,  775,  800,  825,  850,  875,  900,
+	 925,  950,  975, 1000, 1025, 1050, 1075, 1100,
+	1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
+	1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+};
+
+#define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits,	\
+			   ereg0, ebit0, ereg1, ebit1)			\
+	.desc	= {							\
+		.name	= "REG-" #_id,					\
+		.ops	= &tps6586x_regulator_##_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= TPS6586X_ID_##_id,				\
+		.n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages),	\
+		.owner	= THIS_MODULE,					\
+	},								\
+	.volt_reg	= TPS6586X_##vreg,				\
+	.volt_shift	= (shift),					\
+	.volt_nbits	= (nbits),					\
+	.enable_reg[0]	= TPS6586X_SUPPLY##ereg0,			\
+	.enable_bit[0]	= (ebit0),					\
+	.enable_reg[1]	= TPS6586X_SUPPLY##ereg1,			\
+	.enable_bit[1]	= (ebit1),					\
+	.voltages	= tps6586x_##vdata##_voltages,
+
+#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)			\
+	.go_reg = TPS6586X_##goreg,					\
+	.go_bit = (gobit),
+
+#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits,			\
+		     ereg0, ebit0, ereg1, ebit1)			\
+{									\
+	TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits,	\
+			   ereg0, ebit0, ereg1, ebit1)			\
+}
+
+#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits,			\
+		     ereg0, ebit0, ereg1, ebit1, goreg, gobit)		\
+{									\
+	TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits,	\
+			   ereg0, ebit0, ereg1, ebit1)			\
+	TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)			\
+}
+
+static struct tps6586x_regulator tps6586x_regulator[] = {
+	TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0),
+	TPS6586X_LDO(LDO_3, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
+	TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
+	TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
+	TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
+	TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6),
+	TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
+	TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
+	TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
+	TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
+
+	TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6),
+	TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6),
+	TPS6586X_DVM(SM_0, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2),
+	TPS6586X_DVM(SM_1, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0),
+};
+
+/*
+ * TPS6586X has 2 enable bits that are OR'ed to determine the actual
+ * regulator state. Clearing one of this bits allows switching
+ * regulator on and of with single register write.
+ */
+static inline int tps6586x_regulator_preinit(struct device *parent,
+					     struct tps6586x_regulator *ri)
+{
+	uint8_t val1, val2;
+	int ret;
+
+	if (ri->enable_reg[0] == ri->enable_reg[1] &&
+	    ri->enable_bit[0] == ri->enable_bit[1])
+			return 0;
+
+	ret = tps6586x_read(parent, ri->enable_reg[0], &val1);
+	if (ret)
+		return ret;
+
+	ret = tps6586x_read(parent, ri->enable_reg[1], &val2);
+	if (ret)
+		return ret;
+
+	if (!(val2 & (1 << ri->enable_bit[1])))
+		return 0;
+
+	/*
+	 * The regulator is on, but it's enabled with the bit we don't
+	 * want to use, so we switch the enable bits
+	 */
+	if (!(val1 & (1 << ri->enable_bit[0]))) {
+		ret = tps6586x_set_bits(parent, ri->enable_reg[0],
+					1 << ri->enable_bit[0]);
+		if (ret)
+			return ret;
+	}
+
+	return tps6586x_clr_bits(parent, ri->enable_reg[1],
+				 1 << ri->enable_bit[1]);
+}
+
+static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev)
+{
+	struct device *parent = pdev->dev.parent;
+	struct regulator_init_data *p = pdev->dev.platform_data;
+	struct tps6586x_settings *setting = p->driver_data;
+	uint8_t reg;
+
+	if (setting == NULL)
+		return 0;
+
+	if (!(setting->slew_rate & TPS6586X_SLEW_RATE_SET))
+		return 0;
+
+	/* only SM0 and SM1 can have the slew rate settings */
+	switch (pdev->id) {
+	case TPS6586X_ID_SM_0:
+		reg = TPS6586X_SM0SL;
+		break;
+	case TPS6586X_ID_SM_1:
+		reg = TPS6586X_SM1SL;
+		break;
+	default:
+		dev_warn(&pdev->dev, "Only SM0/SM1 can set slew rate\n");
+		return -EINVAL;
+	}
+
+	return tps6586x_write(parent, reg,
+			setting->slew_rate & TPS6586X_SLEW_RATE_MASK);
+}
+
+static inline struct tps6586x_regulator *find_regulator_info(int id)
+{
+	struct tps6586x_regulator *ri;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tps6586x_regulator); i++) {
+		ri = &tps6586x_regulator[i];
+		if (ri->desc.id == id)
+			return ri;
+	}
+	return NULL;
+}
+
+static int __devinit tps6586x_regulator_probe(struct platform_device *pdev)
+{
+	struct tps6586x_regulator *ri = NULL;
+	struct regulator_dev *rdev;
+	int id = pdev->id;
+	int err;
+
+	dev_dbg(&pdev->dev, "Probing regulator %d\n", id);
+
+	ri = find_regulator_info(id);
+	if (ri == NULL) {
+		dev_err(&pdev->dev, "invalid regulator ID specified\n");
+		return -EINVAL;
+	}
+
+	err = tps6586x_regulator_preinit(pdev->dev.parent, ri);
+	if (err)
+		return err;
+
+	rdev = regulator_register(&ri->desc, &pdev->dev,
+				  pdev->dev.platform_data, ri, NULL);
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "failed to register regulator %s\n",
+				ri->desc.name);
+		return PTR_ERR(rdev);
+	}
+
+	platform_set_drvdata(pdev, rdev);
+
+	return tps6586x_regulator_set_slew_rate(pdev);
+}
+
+static int __devexit tps6586x_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	regulator_unregister(rdev);
+	return 0;
+}
+
+static struct platform_driver tps6586x_regulator_driver = {
+	.driver	= {
+		.name	= "tps6586x-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= tps6586x_regulator_probe,
+	.remove		= __devexit_p(tps6586x_regulator_remove),
+};
+
+static int __init tps6586x_regulator_init(void)
+{
+	return platform_driver_register(&tps6586x_regulator_driver);
+}
+subsys_initcall(tps6586x_regulator_init);
+
+static void __exit tps6586x_regulator_exit(void)
+{
+	platform_driver_unregister(&tps6586x_regulator_driver);
+}
+module_exit(tps6586x_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Regulator Driver for TI TPS6586X PMIC");
+MODULE_ALIAS("platform:tps6586x-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/tps65910-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/tps65910-regulator.c
new file mode 100644
index 0000000..4a37c2b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/tps65910-regulator.c
@@ -0,0 +1,1307 @@
+/*
+ * tps65910.c  --  TI tps65910
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65910.h>
+
+#define TPS65910_SUPPLY_STATE_ENABLED	0x1
+#define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 |	\
+			TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 |		\
+			TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 |		\
+			TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
+
+/* supported VIO voltages in milivolts */
+static const u16 VIO_VSEL_table[] = {
+	1500, 1800, 2500, 3300,
+};
+
+/* VSEL tables for TPS65910 specific LDOs and dcdc's */
+
+/* supported VDD3 voltages in milivolts */
+static const u16 VDD3_VSEL_table[] = {
+	5000,
+};
+
+/* supported VDIG1 voltages in milivolts */
+static const u16 VDIG1_VSEL_table[] = {
+	1200, 1500, 1800, 2700,
+};
+
+/* supported VDIG2 voltages in milivolts */
+static const u16 VDIG2_VSEL_table[] = {
+	1000, 1100, 1200, 1800,
+};
+
+/* supported VPLL voltages in milivolts */
+static const u16 VPLL_VSEL_table[] = {
+	1000, 1100, 1800, 2500,
+};
+
+/* supported VDAC voltages in milivolts */
+static const u16 VDAC_VSEL_table[] = {
+	1800, 2600, 2800, 2850,
+};
+
+/* supported VAUX1 voltages in milivolts */
+static const u16 VAUX1_VSEL_table[] = {
+	1800, 2500, 2800, 2850,
+};
+
+/* supported VAUX2 voltages in milivolts */
+static const u16 VAUX2_VSEL_table[] = {
+	1800, 2800, 2900, 3300,
+};
+
+/* supported VAUX33 voltages in milivolts */
+static const u16 VAUX33_VSEL_table[] = {
+	1800, 2000, 2800, 3300,
+};
+
+/* supported VMMC voltages in milivolts */
+static const u16 VMMC_VSEL_table[] = {
+	1800, 2800, 3000, 3300,
+};
+
+struct tps_info {
+	const char *name;
+	unsigned min_uV;
+	unsigned max_uV;
+	u8 n_voltages;
+	const u16 *voltage_table;
+	int enable_time_us;
+};
+
+static struct tps_info tps65910_regs[] = {
+	{
+		.name = "VRTC",
+		.enable_time_us = 2200,
+	},
+	{
+		.name = "VIO",
+		.min_uV = 1500000,
+		.max_uV = 3300000,
+		.n_voltages = ARRAY_SIZE(VIO_VSEL_table),
+		.voltage_table = VIO_VSEL_table,
+		.enable_time_us = 350,
+	},
+	{
+		.name = "VDD1",
+		.min_uV = 600000,
+		.max_uV = 4500000,
+		.enable_time_us = 350,
+	},
+	{
+		.name = "VDD2",
+		.min_uV = 600000,
+		.max_uV = 4500000,
+		.enable_time_us = 350,
+	},
+	{
+		.name = "VDD3",
+		.min_uV = 5000000,
+		.max_uV = 5000000,
+		.n_voltages = ARRAY_SIZE(VDD3_VSEL_table),
+		.voltage_table = VDD3_VSEL_table,
+		.enable_time_us = 200,
+	},
+	{
+		.name = "VDIG1",
+		.min_uV = 1200000,
+		.max_uV = 2700000,
+		.n_voltages = ARRAY_SIZE(VDIG1_VSEL_table),
+		.voltage_table = VDIG1_VSEL_table,
+		.enable_time_us = 100,
+	},
+	{
+		.name = "VDIG2",
+		.min_uV = 1000000,
+		.max_uV = 1800000,
+		.n_voltages = ARRAY_SIZE(VDIG2_VSEL_table),
+		.voltage_table = VDIG2_VSEL_table,
+		.enable_time_us = 100,
+	},
+	{
+		.name = "VPLL",
+		.min_uV = 1000000,
+		.max_uV = 2500000,
+		.n_voltages = ARRAY_SIZE(VPLL_VSEL_table),
+		.voltage_table = VPLL_VSEL_table,
+		.enable_time_us = 100,
+	},
+	{
+		.name = "VDAC",
+		.min_uV = 1800000,
+		.max_uV = 2850000,
+		.n_voltages = ARRAY_SIZE(VDAC_VSEL_table),
+		.voltage_table = VDAC_VSEL_table,
+		.enable_time_us = 100,
+	},
+	{
+		.name = "VAUX1",
+		.min_uV = 1800000,
+		.max_uV = 2850000,
+		.n_voltages = ARRAY_SIZE(VAUX1_VSEL_table),
+		.voltage_table = VAUX1_VSEL_table,
+		.enable_time_us = 100,
+	},
+	{
+		.name = "VAUX2",
+		.min_uV = 1800000,
+		.max_uV = 3300000,
+		.n_voltages = ARRAY_SIZE(VAUX2_VSEL_table),
+		.voltage_table = VAUX2_VSEL_table,
+		.enable_time_us = 100,
+	},
+	{
+		.name = "VAUX33",
+		.min_uV = 1800000,
+		.max_uV = 3300000,
+		.n_voltages = ARRAY_SIZE(VAUX33_VSEL_table),
+		.voltage_table = VAUX33_VSEL_table,
+		.enable_time_us = 100,
+	},
+	{
+		.name = "VMMC",
+		.min_uV = 1800000,
+		.max_uV = 3300000,
+		.n_voltages = ARRAY_SIZE(VMMC_VSEL_table),
+		.voltage_table = VMMC_VSEL_table,
+		.enable_time_us = 100,
+	},
+};
+
+static struct tps_info tps65911_regs[] = {
+	{
+		.name = "VRTC",
+		.enable_time_us = 2200,
+	},
+	{
+		.name = "VIO",
+		.min_uV = 1500000,
+		.max_uV = 3300000,
+		.n_voltages = ARRAY_SIZE(VIO_VSEL_table),
+		.voltage_table = VIO_VSEL_table,
+		.enable_time_us = 350,
+	},
+	{
+		.name = "VDD1",
+		.min_uV = 600000,
+		.max_uV = 4500000,
+		.n_voltages = 73,
+		.enable_time_us = 350,
+	},
+	{
+		.name = "VDD2",
+		.min_uV = 600000,
+		.max_uV = 4500000,
+		.n_voltages = 73,
+		.enable_time_us = 350,
+	},
+	{
+		.name = "VDDCTRL",
+		.min_uV = 600000,
+		.max_uV = 1400000,
+		.n_voltages = 65,
+		.enable_time_us = 900,
+	},
+	{
+		.name = "LDO1",
+		.min_uV = 1000000,
+		.max_uV = 3300000,
+		.n_voltages = 47,
+		.enable_time_us = 420,
+	},
+	{
+		.name = "LDO2",
+		.min_uV = 1000000,
+		.max_uV = 3300000,
+		.n_voltages = 47,
+		.enable_time_us = 420,
+	},
+	{
+		.name = "LDO3",
+		.min_uV = 1000000,
+		.max_uV = 3300000,
+		.n_voltages = 24,
+		.enable_time_us = 230,
+	},
+	{
+		.name = "LDO4",
+		.min_uV = 1000000,
+		.max_uV = 3300000,
+		.n_voltages = 47,
+		.enable_time_us = 230,
+	},
+	{
+		.name = "LDO5",
+		.min_uV = 1000000,
+		.max_uV = 3300000,
+		.n_voltages = 24,
+		.enable_time_us = 230,
+	},
+	{
+		.name = "LDO6",
+		.min_uV = 1000000,
+		.max_uV = 3300000,
+		.n_voltages = 24,
+		.enable_time_us = 230,
+	},
+	{
+		.name = "LDO7",
+		.min_uV = 1000000,
+		.max_uV = 3300000,
+		.n_voltages = 24,
+		.enable_time_us = 230,
+	},
+	{
+		.name = "LDO8",
+		.min_uV = 1000000,
+		.max_uV = 3300000,
+		.n_voltages = 24,
+		.enable_time_us = 230,
+	},
+};
+
+#define EXT_CONTROL_REG_BITS(id, regs_offs, bits) (((regs_offs) << 8) | (bits))
+static unsigned int tps65910_ext_sleep_control[] = {
+	0,
+	EXT_CONTROL_REG_BITS(VIO,    1, 0),
+	EXT_CONTROL_REG_BITS(VDD1,   1, 1),
+	EXT_CONTROL_REG_BITS(VDD2,   1, 2),
+	EXT_CONTROL_REG_BITS(VDD3,   1, 3),
+	EXT_CONTROL_REG_BITS(VDIG1,  0, 1),
+	EXT_CONTROL_REG_BITS(VDIG2,  0, 2),
+	EXT_CONTROL_REG_BITS(VPLL,   0, 6),
+	EXT_CONTROL_REG_BITS(VDAC,   0, 7),
+	EXT_CONTROL_REG_BITS(VAUX1,  0, 3),
+	EXT_CONTROL_REG_BITS(VAUX2,  0, 4),
+	EXT_CONTROL_REG_BITS(VAUX33, 0, 5),
+	EXT_CONTROL_REG_BITS(VMMC,   0, 0),
+};
+
+static unsigned int tps65911_ext_sleep_control[] = {
+	0,
+	EXT_CONTROL_REG_BITS(VIO,     1, 0),
+	EXT_CONTROL_REG_BITS(VDD1,    1, 1),
+	EXT_CONTROL_REG_BITS(VDD2,    1, 2),
+	EXT_CONTROL_REG_BITS(VDDCTRL, 1, 3),
+	EXT_CONTROL_REG_BITS(LDO1,    0, 1),
+	EXT_CONTROL_REG_BITS(LDO2,    0, 2),
+	EXT_CONTROL_REG_BITS(LDO3,    0, 7),
+	EXT_CONTROL_REG_BITS(LDO4,    0, 6),
+	EXT_CONTROL_REG_BITS(LDO5,    0, 3),
+	EXT_CONTROL_REG_BITS(LDO6,    0, 0),
+	EXT_CONTROL_REG_BITS(LDO7,    0, 5),
+	EXT_CONTROL_REG_BITS(LDO8,    0, 4),
+};
+
+struct tps65910_reg {
+	struct regulator_desc *desc;
+	struct tps65910 *mfd;
+	struct regulator_dev **rdev;
+	struct tps_info **info;
+	struct mutex mutex;
+	int num_regulators;
+	int mode;
+	int  (*get_ctrl_reg)(int);
+	unsigned int *ext_sleep_control;
+	unsigned int board_ext_control[TPS65910_NUM_REGS];
+};
+
+static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg)
+{
+	u8 val;
+	int err;
+
+	err = pmic->mfd->read(pmic->mfd, reg, 1, &val);
+	if (err)
+		return err;
+
+	return val;
+}
+
+static inline int tps65910_write(struct tps65910_reg *pmic, u8 reg, u8 val)
+{
+	return pmic->mfd->write(pmic->mfd, reg, 1, &val);
+}
+
+static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg,
+					u8 set_mask, u8 clear_mask)
+{
+	int err, data;
+
+	mutex_lock(&pmic->mutex);
+
+	data = tps65910_read(pmic, reg);
+	if (data < 0) {
+		dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
+		err = data;
+		goto out;
+	}
+
+	data &= ~clear_mask;
+	data |= set_mask;
+	err = tps65910_write(pmic, reg, data);
+	if (err)
+		dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
+
+out:
+	mutex_unlock(&pmic->mutex);
+	return err;
+}
+
+static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg)
+{
+	int data;
+
+	mutex_lock(&pmic->mutex);
+
+	data = tps65910_read(pmic, reg);
+	if (data < 0)
+		dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
+
+	mutex_unlock(&pmic->mutex);
+	return data;
+}
+
+static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val)
+{
+	int err;
+
+	mutex_lock(&pmic->mutex);
+
+	err = tps65910_write(pmic, reg, val);
+	if (err < 0)
+		dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
+
+	mutex_unlock(&pmic->mutex);
+	return err;
+}
+
+static int tps65910_get_ctrl_register(int id)
+{
+	switch (id) {
+	case TPS65910_REG_VRTC:
+		return TPS65910_VRTC;
+	case TPS65910_REG_VIO:
+		return TPS65910_VIO;
+	case TPS65910_REG_VDD1:
+		return TPS65910_VDD1;
+	case TPS65910_REG_VDD2:
+		return TPS65910_VDD2;
+	case TPS65910_REG_VDD3:
+		return TPS65910_VDD3;
+	case TPS65910_REG_VDIG1:
+		return TPS65910_VDIG1;
+	case TPS65910_REG_VDIG2:
+		return TPS65910_VDIG2;
+	case TPS65910_REG_VPLL:
+		return TPS65910_VPLL;
+	case TPS65910_REG_VDAC:
+		return TPS65910_VDAC;
+	case TPS65910_REG_VAUX1:
+		return TPS65910_VAUX1;
+	case TPS65910_REG_VAUX2:
+		return TPS65910_VAUX2;
+	case TPS65910_REG_VAUX33:
+		return TPS65910_VAUX33;
+	case TPS65910_REG_VMMC:
+		return TPS65910_VMMC;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int tps65911_get_ctrl_register(int id)
+{
+	switch (id) {
+	case TPS65910_REG_VRTC:
+		return TPS65910_VRTC;
+	case TPS65910_REG_VIO:
+		return TPS65910_VIO;
+	case TPS65910_REG_VDD1:
+		return TPS65910_VDD1;
+	case TPS65910_REG_VDD2:
+		return TPS65910_VDD2;
+	case TPS65911_REG_VDDCTRL:
+		return TPS65911_VDDCTRL;
+	case TPS65911_REG_LDO1:
+		return TPS65911_LDO1;
+	case TPS65911_REG_LDO2:
+		return TPS65911_LDO2;
+	case TPS65911_REG_LDO3:
+		return TPS65911_LDO3;
+	case TPS65911_REG_LDO4:
+		return TPS65911_LDO4;
+	case TPS65911_REG_LDO5:
+		return TPS65911_LDO5;
+	case TPS65911_REG_LDO6:
+		return TPS65911_LDO6;
+	case TPS65911_REG_LDO7:
+		return TPS65911_LDO7;
+	case TPS65911_REG_LDO8:
+		return TPS65911_LDO8;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int tps65910_is_enabled(struct regulator_dev *dev)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int reg, value, id = rdev_get_id(dev);
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	value = tps65910_reg_read(pmic, reg);
+	if (value < 0)
+		return value;
+
+	return value & TPS65910_SUPPLY_STATE_ENABLED;
+}
+
+static int tps65910_enable(struct regulator_dev *dev)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65910 *mfd = pmic->mfd;
+	int reg, id = rdev_get_id(dev);
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
+}
+
+static int tps65910_disable(struct regulator_dev *dev)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65910 *mfd = pmic->mfd;
+	int reg, id = rdev_get_id(dev);
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
+}
+
+static int tps65910_enable_time(struct regulator_dev *dev)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+	return pmic->info[id]->enable_time_us;
+}
+
+static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65910 *mfd = pmic->mfd;
+	int reg, value, id = rdev_get_id(dev);
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		return tps65910_modify_bits(pmic, reg, LDO_ST_ON_BIT,
+							LDO_ST_MODE_BIT);
+	case REGULATOR_MODE_IDLE:
+		value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT;
+		return tps65910_set_bits(mfd, reg, value);
+	case REGULATOR_MODE_STANDBY:
+		return tps65910_clear_bits(mfd, reg, LDO_ST_ON_BIT);
+	}
+
+	return -EINVAL;
+}
+
+static unsigned int tps65910_get_mode(struct regulator_dev *dev)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int reg, value, id = rdev_get_id(dev);
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	value = tps65910_reg_read(pmic, reg);
+	if (value < 0)
+		return value;
+
+	if (!(value & LDO_ST_ON_BIT))
+		return REGULATOR_MODE_STANDBY;
+	else if (value & LDO_ST_MODE_BIT)
+		return REGULATOR_MODE_IDLE;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+	int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0;
+
+	switch (id) {
+	case TPS65910_REG_VDD1:
+		opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP);
+		mult = tps65910_reg_read(pmic, TPS65910_VDD1);
+		mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT;
+		srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR);
+		sr = opvsel & VDD1_OP_CMD_MASK;
+		opvsel &= VDD1_OP_SEL_MASK;
+		srvsel &= VDD1_SR_SEL_MASK;
+		vselmax = 75;
+		break;
+	case TPS65910_REG_VDD2:
+		opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP);
+		mult = tps65910_reg_read(pmic, TPS65910_VDD2);
+		mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT;
+		srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR);
+		sr = opvsel & VDD2_OP_CMD_MASK;
+		opvsel &= VDD2_OP_SEL_MASK;
+		srvsel &= VDD2_SR_SEL_MASK;
+		vselmax = 75;
+		break;
+	case TPS65911_REG_VDDCTRL:
+		opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP);
+		srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR);
+		sr = opvsel & VDDCTRL_OP_CMD_MASK;
+		opvsel &= VDDCTRL_OP_SEL_MASK;
+		srvsel &= VDDCTRL_SR_SEL_MASK;
+		vselmax = 64;
+		break;
+	}
+
+	/* multiplier 0 == 1 but 2,3 normal */
+	if (!mult)
+		mult=1;
+
+	if (sr) {
+		/* normalise to valid range */
+		if (srvsel < 3)
+			srvsel = 3;
+		if (srvsel > vselmax)
+			srvsel = vselmax;
+		return srvsel - 3;
+	} else {
+
+		/* normalise to valid range*/
+		if (opvsel < 3)
+			opvsel = 3;
+		if (opvsel > vselmax)
+			opvsel = vselmax;
+		return opvsel - 3;
+	}
+	return -EINVAL;
+}
+
+static int tps65910_get_voltage(struct regulator_dev *dev)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int reg, value, id = rdev_get_id(dev), voltage = 0;
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	value = tps65910_reg_read(pmic, reg);
+	if (value < 0)
+		return value;
+
+	switch (id) {
+	case TPS65910_REG_VIO:
+	case TPS65910_REG_VDIG1:
+	case TPS65910_REG_VDIG2:
+	case TPS65910_REG_VPLL:
+	case TPS65910_REG_VDAC:
+	case TPS65910_REG_VAUX1:
+	case TPS65910_REG_VAUX2:
+	case TPS65910_REG_VAUX33:
+	case TPS65910_REG_VMMC:
+		value &= LDO_SEL_MASK;
+		value >>= LDO_SEL_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	voltage = pmic->info[id]->voltage_table[value] * 1000;
+
+	return voltage;
+}
+
+static int tps65910_get_voltage_vdd3(struct regulator_dev *dev)
+{
+	return 5 * 1000 * 1000;
+}
+
+static int tps65911_get_voltage(struct regulator_dev *dev)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int step_mv, id = rdev_get_id(dev);
+	u8 value, reg;
+
+	reg = pmic->get_ctrl_reg(id);
+
+	value = tps65910_reg_read(pmic, reg);
+
+	switch (id) {
+	case TPS65911_REG_LDO1:
+	case TPS65911_REG_LDO2:
+	case TPS65911_REG_LDO4:
+		value &= LDO1_SEL_MASK;
+		value >>= LDO_SEL_SHIFT;
+		/* The first 5 values of the selector correspond to 1V */
+		if (value < 5)
+			value = 0;
+		else
+			value -= 4;
+
+		step_mv = 50;
+		break;
+	case TPS65911_REG_LDO3:
+	case TPS65911_REG_LDO5:
+	case TPS65911_REG_LDO6:
+	case TPS65911_REG_LDO7:
+	case TPS65911_REG_LDO8:
+		value &= LDO3_SEL_MASK;
+		value >>= LDO_SEL_SHIFT;
+		/* The first 3 values of the selector correspond to 1V */
+		if (value < 3)
+			value = 0;
+		else
+			value -= 2;
+
+		step_mv = 100;
+		break;
+	case TPS65910_REG_VIO:
+		value &= LDO_SEL_MASK;
+		value >>= LDO_SEL_SHIFT;
+		return pmic->info[id]->voltage_table[value] * 1000;
+	default:
+		return -EINVAL;
+	}
+
+	return (LDO_MIN_VOLT + value * step_mv) * 1000;
+}
+
+static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev,
+					 unsigned selector)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev), vsel;
+	int dcdc_mult = 0;
+
+	switch (id) {
+	case TPS65910_REG_VDD1:
+		dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
+		if (dcdc_mult == 1)
+			dcdc_mult--;
+		vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3;
+
+		tps65910_modify_bits(pmic, TPS65910_VDD1,
+				(dcdc_mult << VDD1_VGAIN_SEL_SHIFT),
+						VDD1_VGAIN_SEL_MASK);
+		tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel);
+		break;
+	case TPS65910_REG_VDD2:
+		dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
+		if (dcdc_mult == 1)
+			dcdc_mult--;
+		vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3;
+
+		tps65910_modify_bits(pmic, TPS65910_VDD2,
+				(dcdc_mult << VDD2_VGAIN_SEL_SHIFT),
+						VDD1_VGAIN_SEL_MASK);
+		tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel);
+		break;
+	case TPS65911_REG_VDDCTRL:
+		vsel = selector + 3;
+		tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel);
+	}
+
+	return 0;
+}
+
+static int tps65910_set_voltage_sel(struct regulator_dev *dev,
+				    unsigned selector)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int reg, id = rdev_get_id(dev);
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	switch (id) {
+	case TPS65910_REG_VIO:
+	case TPS65910_REG_VDIG1:
+	case TPS65910_REG_VDIG2:
+	case TPS65910_REG_VPLL:
+	case TPS65910_REG_VDAC:
+	case TPS65910_REG_VAUX1:
+	case TPS65910_REG_VAUX2:
+	case TPS65910_REG_VAUX33:
+	case TPS65910_REG_VMMC:
+		return tps65910_modify_bits(pmic, reg,
+				(selector << LDO_SEL_SHIFT), LDO_SEL_MASK);
+	}
+
+	return -EINVAL;
+}
+
+static int tps65911_set_voltage_sel(struct regulator_dev *dev,
+				    unsigned selector)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int reg, id = rdev_get_id(dev);
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	switch (id) {
+	case TPS65911_REG_LDO1:
+	case TPS65911_REG_LDO2:
+	case TPS65911_REG_LDO4:
+		return tps65910_modify_bits(pmic, reg,
+				(selector << LDO_SEL_SHIFT), LDO1_SEL_MASK);
+	case TPS65911_REG_LDO3:
+	case TPS65911_REG_LDO5:
+	case TPS65911_REG_LDO6:
+	case TPS65911_REG_LDO7:
+	case TPS65911_REG_LDO8:
+		return tps65910_modify_bits(pmic, reg,
+				(selector << LDO_SEL_SHIFT), LDO3_SEL_MASK);
+	case TPS65910_REG_VIO:
+		return tps65910_modify_bits(pmic, reg,
+				(selector << LDO_SEL_SHIFT), LDO_SEL_MASK);
+	}
+
+	return -EINVAL;
+}
+
+
+static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
+					unsigned selector)
+{
+	int volt, mult = 1, id = rdev_get_id(dev);
+
+	switch (id) {
+	case TPS65910_REG_VDD1:
+	case TPS65910_REG_VDD2:
+		mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
+		volt = VDD1_2_MIN_VOLT +
+				(selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET;
+		break;
+	case TPS65911_REG_VDDCTRL:
+		volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	return  volt * 100 * mult;
+}
+
+static int tps65910_list_voltage(struct regulator_dev *dev,
+					unsigned selector)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev), voltage;
+
+	if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC)
+		return -EINVAL;
+
+	if (selector >= pmic->info[id]->n_voltages)
+		return -EINVAL;
+	else
+		voltage = pmic->info[id]->voltage_table[selector] * 1000;
+
+	return voltage;
+}
+
+static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
+{
+	struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+	int step_mv = 0, id = rdev_get_id(dev);
+
+	switch(id) {
+	case TPS65911_REG_LDO1:
+	case TPS65911_REG_LDO2:
+	case TPS65911_REG_LDO4:
+		/* The first 5 values of the selector correspond to 1V */
+		if (selector < 5)
+			selector = 0;
+		else
+			selector -= 4;
+
+		step_mv = 50;
+		break;
+	case TPS65911_REG_LDO3:
+	case TPS65911_REG_LDO5:
+	case TPS65911_REG_LDO6:
+	case TPS65911_REG_LDO7:
+	case TPS65911_REG_LDO8:
+		/* The first 3 values of the selector correspond to 1V */
+		if (selector < 3)
+			selector = 0;
+		else
+			selector -= 2;
+
+		step_mv = 100;
+		break;
+	case TPS65910_REG_VIO:
+		return pmic->info[id]->voltage_table[selector] * 1000;
+	default:
+		return -EINVAL;
+	}
+
+	return (LDO_MIN_VOLT + selector * step_mv) * 1000;
+}
+
+static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev,
+		unsigned int old_selector, unsigned int new_selector)
+{
+	int id = rdev_get_id(dev);
+	int old_volt, new_volt;
+
+	old_volt = tps65910_list_voltage_dcdc(dev, old_selector);
+	if (old_volt < 0)
+		return old_volt;
+
+	new_volt = tps65910_list_voltage_dcdc(dev, new_selector);
+	if (new_volt < 0)
+		return new_volt;
+
+	/* VDD1 and VDD2 are 12.5mV/us, VDDCTRL is 100mV/20us */
+	switch (id) {
+	case TPS65910_REG_VDD1:
+	case TPS65910_REG_VDD2:
+		return DIV_ROUND_UP(abs(old_volt - new_volt), 12500);
+	case TPS65911_REG_VDDCTRL:
+		return DIV_ROUND_UP(abs(old_volt - new_volt), 5000);
+	}
+	return -EINVAL;
+}
+
+/* Regulator ops (except VRTC) */
+static struct regulator_ops tps65910_ops_dcdc = {
+	.is_enabled		= tps65910_is_enabled,
+	.enable			= tps65910_enable,
+	.disable		= tps65910_disable,
+	.enable_time		= tps65910_enable_time,
+	.set_mode		= tps65910_set_mode,
+	.get_mode		= tps65910_get_mode,
+	.get_voltage_sel	= tps65910_get_voltage_dcdc_sel,
+	.set_voltage_sel	= tps65910_set_voltage_dcdc_sel,
+	.set_voltage_time_sel	= tps65910_set_voltage_dcdc_time_sel,
+	.list_voltage		= tps65910_list_voltage_dcdc,
+};
+
+static struct regulator_ops tps65910_ops_vdd3 = {
+	.is_enabled		= tps65910_is_enabled,
+	.enable			= tps65910_enable,
+	.disable		= tps65910_disable,
+	.enable_time		= tps65910_enable_time,
+	.set_mode		= tps65910_set_mode,
+	.get_mode		= tps65910_get_mode,
+	.get_voltage		= tps65910_get_voltage_vdd3,
+	.list_voltage		= tps65910_list_voltage,
+};
+
+static struct regulator_ops tps65910_ops = {
+	.is_enabled		= tps65910_is_enabled,
+	.enable			= tps65910_enable,
+	.disable		= tps65910_disable,
+	.enable_time		= tps65910_enable_time,
+	.set_mode		= tps65910_set_mode,
+	.get_mode		= tps65910_get_mode,
+	.get_voltage		= tps65910_get_voltage,
+	.set_voltage_sel	= tps65910_set_voltage_sel,
+	.list_voltage		= tps65910_list_voltage,
+};
+
+static struct regulator_ops tps65911_ops = {
+	.is_enabled		= tps65910_is_enabled,
+	.enable			= tps65910_enable,
+	.disable		= tps65910_disable,
+	.enable_time		= tps65910_enable_time,
+	.set_mode		= tps65910_set_mode,
+	.get_mode		= tps65910_get_mode,
+	.get_voltage		= tps65911_get_voltage,
+	.set_voltage_sel	= tps65911_set_voltage_sel,
+	.list_voltage		= tps65911_list_voltage,
+};
+
+static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
+		int id, int ext_sleep_config)
+{
+	struct tps65910 *mfd = pmic->mfd;
+	u8 regoffs = (pmic->ext_sleep_control[id] >> 8) & 0xFF;
+	u8 bit_pos = (1 << pmic->ext_sleep_control[id] & 0xFF);
+	int ret;
+
+	/*
+	 * Regulator can not be control from multiple external input EN1, EN2
+	 * and EN3 together.
+	 */
+	if (ext_sleep_config & EXT_SLEEP_CONTROL) {
+		int en_count;
+		en_count = ((ext_sleep_config &
+				TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) != 0);
+		en_count += ((ext_sleep_config &
+				TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) != 0);
+		en_count += ((ext_sleep_config &
+				TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) != 0);
+		en_count += ((ext_sleep_config &
+				TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) != 0);
+		if (en_count > 1) {
+			dev_err(mfd->dev,
+				"External sleep control flag is not proper\n");
+			return -EINVAL;
+		}
+	}
+
+	pmic->board_ext_control[id] = ext_sleep_config;
+
+	/* External EN1 control */
+	if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1)
+		ret = tps65910_set_bits(mfd,
+				TPS65910_EN1_LDO_ASS + regoffs, bit_pos);
+	else
+		ret = tps65910_clear_bits(mfd,
+				TPS65910_EN1_LDO_ASS + regoffs, bit_pos);
+	if (ret < 0) {
+		dev_err(mfd->dev,
+			"Error in configuring external control EN1\n");
+		return ret;
+	}
+
+	/* External EN2 control */
+	if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2)
+		ret = tps65910_set_bits(mfd,
+				TPS65910_EN2_LDO_ASS + regoffs, bit_pos);
+	else
+		ret = tps65910_clear_bits(mfd,
+				TPS65910_EN2_LDO_ASS + regoffs, bit_pos);
+	if (ret < 0) {
+		dev_err(mfd->dev,
+			"Error in configuring external control EN2\n");
+		return ret;
+	}
+
+	/* External EN3 control for TPS65910 LDO only */
+	if ((tps65910_chip_id(mfd) == TPS65910) &&
+			(id >= TPS65910_REG_VDIG1)) {
+		if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3)
+			ret = tps65910_set_bits(mfd,
+				TPS65910_EN3_LDO_ASS + regoffs, bit_pos);
+		else
+			ret = tps65910_clear_bits(mfd,
+				TPS65910_EN3_LDO_ASS + regoffs, bit_pos);
+		if (ret < 0) {
+			dev_err(mfd->dev,
+				"Error in configuring external control EN3\n");
+			return ret;
+		}
+	}
+
+	/* Return if no external control is selected */
+	if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) {
+		/* Clear all sleep controls */
+		ret = tps65910_clear_bits(mfd,
+			TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos);
+		if (!ret)
+			ret = tps65910_clear_bits(mfd,
+				TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
+		if (ret < 0)
+			dev_err(mfd->dev,
+				"Error in configuring SLEEP register\n");
+		return ret;
+	}
+
+	/*
+	 * For regulator that has separate operational and sleep register make
+	 * sure that operational is used and clear sleep register to turn
+	 * regulator off when external control is inactive
+	 */
+	if ((id == TPS65910_REG_VDD1) ||
+		(id == TPS65910_REG_VDD2) ||
+			((id == TPS65911_REG_VDDCTRL) &&
+				(tps65910_chip_id(mfd) == TPS65911))) {
+		int op_reg_add = pmic->get_ctrl_reg(id) + 1;
+		int sr_reg_add = pmic->get_ctrl_reg(id) + 2;
+		int opvsel = tps65910_reg_read(pmic, op_reg_add);
+		int srvsel = tps65910_reg_read(pmic, sr_reg_add);
+		if (opvsel & VDD1_OP_CMD_MASK) {
+			u8 reg_val = srvsel & VDD1_OP_SEL_MASK;
+			ret = tps65910_reg_write(pmic, op_reg_add, reg_val);
+			if (ret < 0) {
+				dev_err(mfd->dev,
+					"Error in configuring op register\n");
+				return ret;
+			}
+		}
+		ret = tps65910_reg_write(pmic, sr_reg_add, 0);
+		if (ret < 0) {
+			dev_err(mfd->dev, "Error in settting sr register\n");
+			return ret;
+		}
+	}
+
+	ret = tps65910_clear_bits(mfd,
+			TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos);
+	if (!ret) {
+		if (ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
+			ret = tps65910_set_bits(mfd,
+				TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
+		else
+			ret = tps65910_clear_bits(mfd,
+				TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
+	}
+	if (ret < 0)
+		dev_err(mfd->dev,
+			"Error in configuring SLEEP register\n");
+
+	return ret;
+}
+
+static __devinit int tps65910_probe(struct platform_device *pdev)
+{
+	struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
+	struct tps_info *info;
+	struct regulator_init_data *reg_data;
+	struct regulator_dev *rdev;
+	struct tps65910_reg *pmic;
+	struct tps65910_board *pmic_plat_data;
+	int i, err;
+
+	pmic_plat_data = dev_get_platdata(tps65910->dev);
+	if (!pmic_plat_data)
+		return -EINVAL;
+
+	pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	mutex_init(&pmic->mutex);
+	pmic->mfd = tps65910;
+	platform_set_drvdata(pdev, pmic);
+
+	/* Give control of all register to control port */
+	tps65910_set_bits(pmic->mfd, TPS65910_DEVCTRL,
+				DEVCTRL_SR_CTL_I2C_SEL_MASK);
+
+	switch(tps65910_chip_id(tps65910)) {
+	case TPS65910:
+		pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
+		pmic->num_regulators = ARRAY_SIZE(tps65910_regs);
+		pmic->ext_sleep_control = tps65910_ext_sleep_control;
+		info = tps65910_regs;
+		break;
+	case TPS65911:
+		pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
+		pmic->num_regulators = ARRAY_SIZE(tps65911_regs);
+		pmic->ext_sleep_control = tps65911_ext_sleep_control;
+		info = tps65911_regs;
+		break;
+	default:
+		pr_err("Invalid tps chip version\n");
+		kfree(pmic);
+		return -ENODEV;
+	}
+
+	pmic->desc = kcalloc(pmic->num_regulators,
+			sizeof(struct regulator_desc), GFP_KERNEL);
+	if (!pmic->desc) {
+		err = -ENOMEM;
+		goto err_free_pmic;
+	}
+
+	pmic->info = kcalloc(pmic->num_regulators,
+			sizeof(struct tps_info *), GFP_KERNEL);
+	if (!pmic->info) {
+		err = -ENOMEM;
+		goto err_free_desc;
+	}
+
+	pmic->rdev = kcalloc(pmic->num_regulators,
+			sizeof(struct regulator_dev *), GFP_KERNEL);
+	if (!pmic->rdev) {
+		err = -ENOMEM;
+		goto err_free_info;
+	}
+
+	for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS;
+			i++, info++) {
+
+		reg_data = pmic_plat_data->tps65910_pmic_init_data[i];
+
+		/* Regulator API handles empty constraints but not NULL
+		 * constraints */
+		if (!reg_data)
+			continue;
+
+		/* Register the regulators */
+		pmic->info[i] = info;
+
+		pmic->desc[i].name = info->name;
+		pmic->desc[i].id = i;
+		pmic->desc[i].n_voltages = info->n_voltages;
+
+		if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) {
+			pmic->desc[i].ops = &tps65910_ops_dcdc;
+			pmic->desc[i].n_voltages = VDD1_2_NUM_VOLT_FINE *
+							VDD1_2_NUM_VOLT_COARSE;
+		} else if (i == TPS65910_REG_VDD3) {
+			if (tps65910_chip_id(tps65910) == TPS65910)
+				pmic->desc[i].ops = &tps65910_ops_vdd3;
+			else
+				pmic->desc[i].ops = &tps65910_ops_dcdc;
+		} else {
+			if (tps65910_chip_id(tps65910) == TPS65910)
+				pmic->desc[i].ops = &tps65910_ops;
+			else
+				pmic->desc[i].ops = &tps65911_ops;
+		}
+
+		err = tps65910_set_ext_sleep_config(pmic, i,
+				pmic_plat_data->regulator_ext_sleep_control[i]);
+		/*
+		 * Failing on regulator for configuring externally control
+		 * is not a serious issue, just throw warning.
+		 */
+		if (err < 0)
+			dev_warn(tps65910->dev,
+				"Failed to initialise ext control config\n");
+
+		pmic->desc[i].type = REGULATOR_VOLTAGE;
+		pmic->desc[i].owner = THIS_MODULE;
+
+		rdev = regulator_register(&pmic->desc[i],
+				tps65910->dev, reg_data, pmic, NULL);
+		if (IS_ERR(rdev)) {
+			dev_err(tps65910->dev,
+				"failed to register %s regulator\n",
+				pdev->name);
+			err = PTR_ERR(rdev);
+			goto err_unregister_regulator;
+		}
+
+		/* Save regulator for cleanup */
+		pmic->rdev[i] = rdev;
+	}
+	return 0;
+
+err_unregister_regulator:
+	while (--i >= 0)
+		regulator_unregister(pmic->rdev[i]);
+	kfree(pmic->rdev);
+err_free_info:
+	kfree(pmic->info);
+err_free_desc:
+	kfree(pmic->desc);
+err_free_pmic:
+	kfree(pmic);
+	return err;
+}
+
+static int __devexit tps65910_remove(struct platform_device *pdev)
+{
+	struct tps65910_reg *pmic = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < pmic->num_regulators; i++)
+		regulator_unregister(pmic->rdev[i]);
+
+	kfree(pmic->rdev);
+	kfree(pmic->info);
+	kfree(pmic->desc);
+	kfree(pmic);
+	return 0;
+}
+
+static void tps65910_shutdown(struct platform_device *pdev)
+{
+	struct tps65910_reg *pmic = platform_get_drvdata(pdev);
+	int i;
+
+	/*
+	 * Before bootloader jumps to kernel, it makes sure that required
+	 * external control signals are in desired state so that given rails
+	 * can be configure accordingly.
+	 * If rails are configured to be controlled from external control
+	 * then before shutting down/rebooting the system, the external
+	 * control configuration need to be remove from the rails so that
+	 * its output will be available as per register programming even
+	 * if external controls are removed. This is require when the POR
+	 * value of the control signals are not in active state and before
+	 * bootloader initializes it, the system requires the rail output
+	 * to be active for booting.
+	 */
+	for (i = 0; i < pmic->num_regulators; i++) {
+		int err;
+		if (!pmic->rdev[i])
+			continue;
+
+		err = tps65910_set_ext_sleep_config(pmic, i, 0);
+		if (err < 0)
+			dev_err(&pdev->dev,
+				"Error in clearing external control\n");
+	}
+}
+
+static struct platform_driver tps65910_driver = {
+	.driver = {
+		.name = "tps65910-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = tps65910_probe,
+	.remove = __devexit_p(tps65910_remove),
+	.shutdown = tps65910_shutdown,
+};
+
+static int __init tps65910_init(void)
+{
+	return platform_driver_register(&tps65910_driver);
+}
+subsys_initcall(tps65910_init);
+
+static void __exit tps65910_cleanup(void)
+{
+	platform_driver_unregister(&tps65910_driver);
+}
+module_exit(tps65910_cleanup);
+
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS65910/TPS65911 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65910-pmic");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/tps65912-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/tps65912-regulator.c
new file mode 100644
index 0000000..b36799b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/tps65912-regulator.c
@@ -0,0 +1,586 @@
+/*
+ * tps65912.c  --  TI tps65912
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk>
+ *
+ *  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 driver is based on wm8350 implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65912.h>
+
+/* DCDC's */
+#define TPS65912_REG_DCDC1	0
+#define TPS65912_REG_DCDC2	1
+#define TPS65912_REG_DCDC3	2
+#define TPS65912_REG_DCDC4	3
+
+/* LDOs */
+#define TPS65912_REG_LDO1	4
+#define TPS65912_REG_LDO2	5
+#define TPS65912_REG_LDO3	6
+#define TPS65912_REG_LDO4	7
+#define TPS65912_REG_LDO5	8
+#define TPS65912_REG_LDO6	9
+#define TPS65912_REG_LDO7	10
+#define TPS65912_REG_LDO8	11
+#define TPS65912_REG_LDO9	12
+#define TPS65912_REG_LDO10	13
+
+/* Number of step-down converters available */
+#define TPS65912_NUM_DCDC	4
+
+/* Number of LDO voltage regulators  available */
+#define TPS65912_NUM_LDO	10
+
+/* Number of total regulators available */
+#define TPS65912_NUM_REGULATOR		(TPS65912_NUM_DCDC + TPS65912_NUM_LDO)
+
+#define TPS65912_REG_ENABLED	0x80
+#define OP_SELREG_MASK		0x40
+#define OP_SELREG_SHIFT		6
+
+struct tps_info {
+	const char *name;
+};
+
+static struct tps_info tps65912_regs[] = {
+	{
+		.name = "DCDC1",
+	},
+	{
+		.name = "DCDC2",
+	},
+	{
+		.name = "DCDC3",
+	},
+	{
+		.name = "DCDC4",
+	},
+	{
+		.name = "LDO1",
+	},
+	{
+		.name = "LDO2",
+	},
+	{
+		.name = "LDO3",
+	},
+	{
+		.name = "LDO4",
+	},
+	{
+		.name = "LDO5",
+	},
+	{
+		.name = "LDO6",
+	},
+	{
+		.name = "LDO7",
+	},
+	{
+		.name = "LDO8",
+	},
+	{
+		.name = "LDO9",
+	},
+	{
+		.name = "LDO10",
+	},
+};
+
+struct tps65912_reg {
+	struct regulator_desc desc[TPS65912_NUM_REGULATOR];
+	struct tps65912 *mfd;
+	struct regulator_dev *rdev[TPS65912_NUM_REGULATOR];
+	struct tps_info *info[TPS65912_NUM_REGULATOR];
+	/* for read/write access */
+	struct mutex io_lock;
+	int mode;
+	int (*get_ctrl_reg)(int);
+	int dcdc_range[TPS65912_NUM_DCDC];
+	int pwm_mode_reg;
+	int eco_reg;
+};
+
+static int tps65912_get_range(struct tps65912_reg *pmic, int id)
+{
+	struct tps65912 *mfd = pmic->mfd;
+	int range;
+
+	switch (id) {
+	case TPS65912_REG_DCDC1:
+		range = tps65912_reg_read(mfd, TPS65912_DCDC1_LIMIT);
+		break;
+	case TPS65912_REG_DCDC2:
+		range = tps65912_reg_read(mfd, TPS65912_DCDC2_LIMIT);
+		break;
+	case TPS65912_REG_DCDC3:
+		range = tps65912_reg_read(mfd, TPS65912_DCDC3_LIMIT);
+		break;
+	case TPS65912_REG_DCDC4:
+		range = tps65912_reg_read(mfd, TPS65912_DCDC4_LIMIT);
+		break;
+	default:
+		return 0;
+	}
+
+	if (range >= 0)
+		range = (range & DCDC_LIMIT_RANGE_MASK)
+			>> DCDC_LIMIT_RANGE_SHIFT;
+
+	pmic->dcdc_range[id] = range;
+	return range;
+}
+
+static unsigned long tps65912_vsel_to_uv_range0(u8 vsel)
+{
+	unsigned long uv;
+
+	uv = ((vsel * 12500) + 500000);
+	return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_range1(u8 vsel)
+{
+	unsigned long uv;
+
+	 uv = ((vsel * 12500) + 700000);
+	return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_range2(u8 vsel)
+{
+	unsigned long uv;
+
+	uv = ((vsel * 25000) + 500000);
+	return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_range3(u8 vsel)
+{
+	unsigned long uv;
+
+	if (vsel == 0x3f)
+		uv = 3800000;
+	else
+		uv = ((vsel * 50000) + 500000);
+
+	return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_ldo(u8 vsel)
+{
+	unsigned long uv = 0;
+
+	if (vsel <= 32)
+		uv = ((vsel * 25000) + 800000);
+	else if (vsel > 32 && vsel <= 60)
+		uv = (((vsel - 32) * 50000) + 1600000);
+	else if (vsel > 60)
+		uv = (((vsel - 60) * 100000) + 3000000);
+
+	return uv;
+}
+
+static int tps65912_get_ctrl_register(int id)
+{
+	if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4)
+		return id * 3 + TPS65912_DCDC1_AVS;
+	else if (id >= TPS65912_REG_LDO5 && id <= TPS65912_REG_LDO10)
+		return id - TPS65912_REG_LDO5 + TPS65912_LDO5;
+	else
+		return -EINVAL;
+}
+
+static int tps65912_get_sel_register(struct tps65912_reg *pmic, int id)
+{
+	struct tps65912 *mfd = pmic->mfd;
+	int opvsel;
+	u8 reg = 0;
+
+	if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4) {
+		opvsel = tps65912_reg_read(mfd, id * 3 + TPS65912_DCDC1_OP);
+		if (opvsel & OP_SELREG_MASK)
+			reg = id * 3 + TPS65912_DCDC1_AVS;
+		else
+			reg = id * 3 + TPS65912_DCDC1_OP;
+	} else if (id >= TPS65912_REG_LDO5 && id <= TPS65912_REG_LDO10) {
+		reg = id - TPS65912_REG_LDO5 + TPS65912_LDO5;
+	} else {
+		return -EINVAL;
+	}
+
+	return reg;
+}
+
+static int tps65912_get_mode_regiters(struct tps65912_reg *pmic, int id)
+{
+	switch (id) {
+	case TPS65912_REG_DCDC1:
+		pmic->pwm_mode_reg = TPS65912_DCDC1_CTRL;
+		pmic->eco_reg = TPS65912_DCDC1_AVS;
+		break;
+	case TPS65912_REG_DCDC2:
+		pmic->pwm_mode_reg = TPS65912_DCDC2_CTRL;
+		pmic->eco_reg = TPS65912_DCDC2_AVS;
+		break;
+	case TPS65912_REG_DCDC3:
+		pmic->pwm_mode_reg = TPS65912_DCDC3_CTRL;
+		pmic->eco_reg = TPS65912_DCDC3_AVS;
+		break;
+	case TPS65912_REG_DCDC4:
+		pmic->pwm_mode_reg = TPS65912_DCDC4_CTRL;
+		pmic->eco_reg = TPS65912_DCDC4_AVS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tps65912_reg_is_enabled(struct regulator_dev *dev)
+{
+	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65912 *mfd = pmic->mfd;
+	int reg, value, id = rdev_get_id(dev);
+
+	if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_LDO10)
+		return -EINVAL;
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	value = tps65912_reg_read(mfd, reg);
+	if (value < 0)
+		return value;
+
+	return value & TPS65912_REG_ENABLED;
+}
+
+static int tps65912_reg_enable(struct regulator_dev *dev)
+{
+	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65912 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev);
+	int reg;
+
+	if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_LDO10)
+		return -EINVAL;
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	return tps65912_set_bits(mfd, reg, TPS65912_REG_ENABLED);
+}
+
+static int tps65912_reg_disable(struct regulator_dev *dev)
+{
+	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65912 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev), reg;
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	return tps65912_clear_bits(mfd, reg, TPS65912_REG_ENABLED);
+}
+
+static int tps65912_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65912 *mfd = pmic->mfd;
+	int pwm_mode, eco, id = rdev_get_id(dev);
+
+	tps65912_get_mode_regiters(pmic, id);
+
+	pwm_mode = tps65912_reg_read(mfd, pmic->pwm_mode_reg);
+	eco = tps65912_reg_read(mfd, pmic->eco_reg);
+
+	pwm_mode &= DCDCCTRL_DCDC_MODE_MASK;
+	eco &= DCDC_AVS_ECO_MASK;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		/* Verify if mode alredy set */
+		if (pwm_mode && !eco)
+			break;
+		tps65912_set_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK);
+		tps65912_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+		break;
+	case REGULATOR_MODE_NORMAL:
+	case REGULATOR_MODE_IDLE:
+		if (!pwm_mode && !eco)
+			break;
+		tps65912_clear_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK);
+		tps65912_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+		break;
+	case REGULATOR_MODE_STANDBY:
+		if (!pwm_mode && eco)
+			break;
+		tps65912_clear_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK);
+		tps65912_set_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned int tps65912_get_mode(struct regulator_dev *dev)
+{
+	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65912 *mfd = pmic->mfd;
+	int pwm_mode, eco, mode = 0, id = rdev_get_id(dev);
+
+	tps65912_get_mode_regiters(pmic, id);
+
+	pwm_mode = tps65912_reg_read(mfd, pmic->pwm_mode_reg);
+	eco = tps65912_reg_read(mfd, pmic->eco_reg);
+
+	pwm_mode &= DCDCCTRL_DCDC_MODE_MASK;
+	eco &= DCDC_AVS_ECO_MASK;
+
+	if (pwm_mode && !eco)
+		mode = REGULATOR_MODE_FAST;
+	else if (!pwm_mode && !eco)
+		mode = REGULATOR_MODE_NORMAL;
+	else if (!pwm_mode && eco)
+		mode = REGULATOR_MODE_STANDBY;
+
+	return mode;
+}
+
+static int tps65912_list_voltage_dcdc(struct regulator_dev *dev,
+					unsigned selector)
+{
+	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+	int range, voltage = 0, id = rdev_get_id(dev);
+
+	if (id > TPS65912_REG_DCDC4)
+		return -EINVAL;
+
+	range = pmic->dcdc_range[id];
+
+	switch (range) {
+	case 0:
+		/* 0.5 - 1.2875V in 12.5mV steps */
+		voltage = tps65912_vsel_to_uv_range0(selector);
+		break;
+	case 1:
+		/* 0.7 - 1.4875V in 12.5mV steps */
+		voltage = tps65912_vsel_to_uv_range1(selector);
+		break;
+	case 2:
+		/* 0.5 - 2.075V in 25mV steps */
+		voltage = tps65912_vsel_to_uv_range2(selector);
+		break;
+	case 3:
+		/* 0.5 - 3.8V in 50mV steps */
+		voltage = tps65912_vsel_to_uv_range3(selector);
+		break;
+	}
+	return voltage;
+}
+
+static int tps65912_get_voltage_dcdc(struct regulator_dev *dev)
+{
+	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65912 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev);
+	int reg, vsel;
+
+	reg = tps65912_get_sel_register(pmic, id);
+	if (reg < 0)
+		return reg;
+
+	vsel = tps65912_reg_read(mfd, reg);
+	vsel &= 0x3F;
+
+	return tps65912_list_voltage_dcdc(dev, vsel);
+}
+
+static int tps65912_set_voltage_sel(struct regulator_dev *dev,
+					 unsigned selector)
+{
+	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65912 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev);
+	int value;
+	u8 reg;
+
+	reg = tps65912_get_sel_register(pmic, id);
+	value = tps65912_reg_read(mfd, reg);
+	value &= 0xC0;
+	return tps65912_reg_write(mfd, reg, selector | value);
+}
+
+static int tps65912_get_voltage_ldo(struct regulator_dev *dev)
+{
+	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+	struct tps65912 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev);
+	int vsel = 0;
+	u8 reg;
+
+	reg = tps65912_get_sel_register(pmic, id);
+	vsel = tps65912_reg_read(mfd, reg);
+	vsel &= 0x3F;
+
+	return tps65912_vsel_to_uv_ldo(vsel);
+}
+
+static int tps65912_list_voltage_ldo(struct regulator_dev *dev,
+					unsigned selector)
+{
+	int ldo = rdev_get_id(dev);
+
+	if (ldo < TPS65912_REG_LDO1 || ldo > TPS65912_REG_LDO10)
+		return -EINVAL;
+
+	return tps65912_vsel_to_uv_ldo(selector);
+}
+
+/* Operations permitted on DCDCx */
+static struct regulator_ops tps65912_ops_dcdc = {
+	.is_enabled = tps65912_reg_is_enabled,
+	.enable = tps65912_reg_enable,
+	.disable = tps65912_reg_disable,
+	.set_mode = tps65912_set_mode,
+	.get_mode = tps65912_get_mode,
+	.get_voltage = tps65912_get_voltage_dcdc,
+	.set_voltage_sel = tps65912_set_voltage_sel,
+	.list_voltage = tps65912_list_voltage_dcdc,
+};
+
+/* Operations permitted on LDOx */
+static struct regulator_ops tps65912_ops_ldo = {
+	.is_enabled = tps65912_reg_is_enabled,
+	.enable = tps65912_reg_enable,
+	.disable = tps65912_reg_disable,
+	.get_voltage = tps65912_get_voltage_ldo,
+	.set_voltage_sel = tps65912_set_voltage_sel,
+	.list_voltage = tps65912_list_voltage_ldo,
+};
+
+static __devinit int tps65912_probe(struct platform_device *pdev)
+{
+	struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent);
+	struct tps_info *info;
+	struct regulator_init_data *reg_data;
+	struct regulator_dev *rdev;
+	struct tps65912_reg *pmic;
+	struct tps65912_board *pmic_plat_data;
+	int i, err;
+
+	pmic_plat_data = dev_get_platdata(tps65912->dev);
+	if (!pmic_plat_data)
+		return -EINVAL;
+
+	reg_data = pmic_plat_data->tps65912_pmic_init_data;
+
+	pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	mutex_init(&pmic->io_lock);
+	pmic->mfd = tps65912;
+	platform_set_drvdata(pdev, pmic);
+
+	pmic->get_ctrl_reg = &tps65912_get_ctrl_register;
+	info = tps65912_regs;
+
+	for (i = 0; i < TPS65912_NUM_REGULATOR; i++, info++, reg_data++) {
+		int range = 0;
+		/* Register the regulators */
+		pmic->info[i] = info;
+
+		pmic->desc[i].name = info->name;
+		pmic->desc[i].id = i;
+		pmic->desc[i].n_voltages = 64;
+		pmic->desc[i].ops = (i > TPS65912_REG_DCDC4 ?
+			&tps65912_ops_ldo : &tps65912_ops_dcdc);
+		pmic->desc[i].type = REGULATOR_VOLTAGE;
+		pmic->desc[i].owner = THIS_MODULE;
+		range = tps65912_get_range(pmic, i);
+		rdev = regulator_register(&pmic->desc[i],
+					tps65912->dev, reg_data, pmic, NULL);
+		if (IS_ERR(rdev)) {
+			dev_err(tps65912->dev,
+				"failed to register %s regulator\n",
+				pdev->name);
+			err = PTR_ERR(rdev);
+			goto err;
+		}
+
+		/* Save regulator for cleanup */
+		pmic->rdev[i] = rdev;
+	}
+	return 0;
+
+err:
+	while (--i >= 0)
+		regulator_unregister(pmic->rdev[i]);
+
+	kfree(pmic);
+	return err;
+}
+
+static int __devexit tps65912_remove(struct platform_device *pdev)
+{
+	struct tps65912_reg *tps65912_reg = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < TPS65912_NUM_REGULATOR; i++)
+		regulator_unregister(tps65912_reg->rdev[i]);
+
+	kfree(tps65912_reg);
+	return 0;
+}
+
+static struct platform_driver tps65912_driver = {
+	.driver = {
+		.name = "tps65912-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = tps65912_probe,
+	.remove = __devexit_p(tps65912_remove),
+};
+
+static int __init tps65912_init(void)
+{
+	return platform_driver_register(&tps65912_driver);
+}
+subsys_initcall(tps65912_init);
+
+static void __exit tps65912_cleanup(void)
+{
+	platform_driver_unregister(&tps65912_driver);
+}
+module_exit(tps65912_cleanup);
+
+MODULE_AUTHOR("Margarita Olaya Cabrera <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS65912 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65912-pmic");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/twl-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/twl-regulator.c
new file mode 100644
index 0000000..1eb7a15
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/twl-regulator.c
@@ -0,0 +1,1334 @@
+/*
+ * twl-regulator.c -- support regulators in twl4030/twl6030 family chips
+ *
+ * Copyright (C) 2008 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/i2c/twl.h>
+
+
+/*
+ * The TWL4030/TW5030/TPS659x0/TWL6030 family chips include power management, a
+ * USB OTG transceiver, an RTC, ADC, PWM, and lots more.  Some versions
+ * include an audio codec, battery charger, and more voltage regulators.
+ * These chips are often used in OMAP-based systems.
+ *
+ * This driver implements software-based resource control for various
+ * voltage regulators.  This is usually augmented with state machine
+ * based control.
+ */
+
+struct twlreg_info {
+	/* start of regulator's PM_RECEIVER control register bank */
+	u8			base;
+
+	/* twl resource ID, for resource control state machine */
+	u8			id;
+
+	/* voltage in mV = table[VSEL]; table_len must be a power-of-two */
+	u8			table_len;
+	const u16		*table;
+
+	/* regulator specific turn-on delay */
+	u16			delay;
+
+	/* State REMAP default configuration */
+	u8			remap;
+
+	/* chip constraints on regulator behavior */
+	u16			min_mV;
+	u16			max_mV;
+
+	u8			flags;
+
+	/* used by regulator core */
+	struct regulator_desc	desc;
+
+	/* chip specific features */
+	unsigned long 		features;
+
+	/*
+	 * optional override functions for voltage set/get
+	 * these are currently only used for SMPS regulators
+	 */
+	int			(*get_voltage)(void *data);
+	int			(*set_voltage)(void *data, int target_uV);
+
+	/* data passed from board for external get/set voltage */
+	void			*data;
+};
+
+
+/* LDO control registers ... offset is from the base of its register bank.
+ * The first three registers of all power resource banks help hardware to
+ * manage the various resource groups.
+ */
+/* Common offset in TWL4030/6030 */
+#define VREG_GRP		0
+/* TWL4030 register offsets */
+#define VREG_TYPE		1
+#define VREG_REMAP		2
+#define VREG_DEDICATED		3	/* LDO control */
+#define VREG_VOLTAGE_SMPS_4030	9
+/* TWL6030 register offsets */
+#define VREG_TRANS		1
+#define VREG_STATE		2
+#define VREG_VOLTAGE		3
+#define VREG_VOLTAGE_SMPS	4
+/* TWL6030 Misc register offsets */
+#define VREG_BC_ALL		1
+#define VREG_BC_REF		2
+#define VREG_BC_PROC		3
+#define VREG_BC_CLK_RST		4
+
+/* TWL6030 LDO register values for CFG_STATE */
+#define TWL6030_CFG_STATE_OFF	0x00
+#define TWL6030_CFG_STATE_ON	0x01
+#define TWL6030_CFG_STATE_OFF2	0x02
+#define TWL6030_CFG_STATE_SLEEP	0x03
+#define TWL6030_CFG_STATE_GRP_SHIFT	5
+#define TWL6030_CFG_STATE_APP_SHIFT	2
+#define TWL6030_CFG_STATE_APP_MASK	(0x03 << TWL6030_CFG_STATE_APP_SHIFT)
+#define TWL6030_CFG_STATE_APP(v)	(((v) & TWL6030_CFG_STATE_APP_MASK) >>\
+						TWL6030_CFG_STATE_APP_SHIFT)
+
+/* Flags for SMPS Voltage reading */
+#define SMPS_OFFSET_EN		BIT(0)
+#define SMPS_EXTENDED_EN	BIT(1)
+
+/* twl6025 SMPS EPROM values */
+#define TWL6030_SMPS_OFFSET		0xB0
+#define TWL6030_SMPS_MULT		0xB3
+#define SMPS_MULTOFFSET_SMPS4	BIT(0)
+#define SMPS_MULTOFFSET_VIO	BIT(1)
+#define SMPS_MULTOFFSET_SMPS3	BIT(6)
+
+static inline int
+twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset)
+{
+	u8 value;
+	int status;
+
+	status = twl_i2c_read_u8(slave_subgp,
+			&value, info->base + offset);
+	return (status < 0) ? status : value;
+}
+
+static inline int
+twlreg_write(struct twlreg_info *info, unsigned slave_subgp, unsigned offset,
+						 u8 value)
+{
+	return twl_i2c_write_u8(slave_subgp,
+			value, info->base + offset);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* generic power resource operations, which work on all regulators */
+
+static int twlreg_grp(struct regulator_dev *rdev)
+{
+	return twlreg_read(rdev_get_drvdata(rdev), TWL_MODULE_PM_RECEIVER,
+								 VREG_GRP);
+}
+
+/*
+ * Enable/disable regulators by joining/leaving the P1 (processor) group.
+ * We assume nobody else is updating the DEV_GRP registers.
+ */
+/* definition for 4030 family */
+#define P3_GRP_4030	BIT(7)		/* "peripherals" */
+#define P2_GRP_4030	BIT(6)		/* secondary processor, modem, etc */
+#define P1_GRP_4030	BIT(5)		/* CPU/Linux */
+/* definition for 6030 family */
+#define P3_GRP_6030	BIT(2)		/* secondary processor, modem, etc */
+#define P2_GRP_6030	BIT(1)		/* "peripherals" */
+#define P1_GRP_6030	BIT(0)		/* CPU/Linux */
+
+static int twl4030reg_is_enabled(struct regulator_dev *rdev)
+{
+	int	state = twlreg_grp(rdev);
+
+	if (state < 0)
+		return state;
+
+	return state & P1_GRP_4030;
+}
+
+static int twl6030reg_is_enabled(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			grp = 0, val;
+
+	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+		grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+	if (grp < 0)
+		return grp;
+
+	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+		grp &= P1_GRP_6030;
+	else
+		grp = 1;
+
+	val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+	val = TWL6030_CFG_STATE_APP(val);
+
+	return grp && (val == TWL6030_CFG_STATE_ON);
+}
+
+static int twl4030reg_enable(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			grp;
+	int			ret;
+
+	grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+	if (grp < 0)
+		return grp;
+
+	grp |= P1_GRP_4030;
+
+	ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+
+	udelay(info->delay);
+
+	return ret;
+}
+
+static int twl6030reg_enable(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			grp = 0;
+	int			ret;
+
+	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+		grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+	if (grp < 0)
+		return grp;
+
+	ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+			grp << TWL6030_CFG_STATE_GRP_SHIFT |
+			TWL6030_CFG_STATE_ON);
+
+	udelay(info->delay);
+
+	return ret;
+}
+
+static int twl4030reg_disable(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			grp;
+	int			ret;
+
+	grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+	if (grp < 0)
+		return grp;
+
+	grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
+
+	ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+
+	return ret;
+}
+
+static int twl6030reg_disable(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			grp = 0;
+	int			ret;
+
+	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+		grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030;
+
+	/* For 6030, set the off state for all grps enabled */
+	ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+			(grp) << TWL6030_CFG_STATE_GRP_SHIFT |
+			TWL6030_CFG_STATE_OFF);
+
+	return ret;
+}
+
+static int twl4030reg_get_status(struct regulator_dev *rdev)
+{
+	int	state = twlreg_grp(rdev);
+
+	if (state < 0)
+		return state;
+	state &= 0x0f;
+
+	/* assume state != WARM_RESET; we'd not be running...  */
+	if (!state)
+		return REGULATOR_STATUS_OFF;
+	return (state & BIT(3))
+		? REGULATOR_STATUS_NORMAL
+		: REGULATOR_STATUS_STANDBY;
+}
+
+static int twl6030reg_get_status(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			val;
+
+	val = twlreg_grp(rdev);
+	if (val < 0)
+		return val;
+
+	val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+
+	switch (TWL6030_CFG_STATE_APP(val)) {
+	case TWL6030_CFG_STATE_ON:
+		return REGULATOR_STATUS_NORMAL;
+
+	case TWL6030_CFG_STATE_SLEEP:
+		return REGULATOR_STATUS_STANDBY;
+
+	case TWL6030_CFG_STATE_OFF:
+	case TWL6030_CFG_STATE_OFF2:
+	default:
+		break;
+	}
+
+	return REGULATOR_STATUS_OFF;
+}
+
+static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	unsigned		message;
+	int			status;
+
+	/* We can only set the mode through state machine commands... */
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_ACTIVE);
+		break;
+	case REGULATOR_MODE_STANDBY:
+		message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_SLEEP);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Ensure the resource is associated with some group */
+	status = twlreg_grp(rdev);
+	if (status < 0)
+		return status;
+	if (!(status & (P3_GRP_4030 | P2_GRP_4030 | P1_GRP_4030)))
+		return -EACCES;
+
+	status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
+			message >> 8, TWL4030_PM_MASTER_PB_WORD_MSB);
+	if (status < 0)
+		return status;
+
+	return twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
+			message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB);
+}
+
+static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int grp = 0;
+	int val;
+
+	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+		grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+
+	if (grp < 0)
+		return grp;
+
+	/* Compose the state register settings */
+	val = grp << TWL6030_CFG_STATE_GRP_SHIFT;
+	/* We can only set the mode through state machine commands... */
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		val |= TWL6030_CFG_STATE_ON;
+		break;
+	case REGULATOR_MODE_STANDBY:
+		val |= TWL6030_CFG_STATE_SLEEP;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, val);
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Support for adjustable-voltage LDOs uses a four bit (or less) voltage
+ * select field in its control register.   We use tables indexed by VSEL
+ * to record voltages in milliVolts.  (Accuracy is about three percent.)
+ *
+ * Note that VSEL values for VAUX2 changed in twl5030 and newer silicon;
+ * currently handled by listing two slightly different VAUX2 regulators,
+ * only one of which will be configured.
+ *
+ * VSEL values documented as "TI cannot support these values" are flagged
+ * in these tables as UNSUP() values; we normally won't assign them.
+ *
+ * VAUX3 at 3V is incorrectly listed in some TI manuals as unsupported.
+ * TI are revising the twl5030/tps659x0 specs to support that 3.0V setting.
+ */
+#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED
+#define UNSUP_MASK	0x0000
+#else
+#define UNSUP_MASK	0x8000
+#endif
+
+#define UNSUP(x)	(UNSUP_MASK | (x))
+#define IS_UNSUP(x)	(UNSUP_MASK & (x))
+#define LDO_MV(x)	(~UNSUP_MASK & (x))
+
+
+static const u16 VAUX1_VSEL_table[] = {
+	UNSUP(1500), UNSUP(1800), 2500, 2800,
+	3000, 3000, 3000, 3000,
+};
+static const u16 VAUX2_4030_VSEL_table[] = {
+	UNSUP(1000), UNSUP(1000), UNSUP(1200), 1300,
+	1500, 1800, UNSUP(1850), 2500,
+	UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
+	UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VAUX2_VSEL_table[] = {
+	1700, 1700, 1900, 1300,
+	1500, 1800, 2000, 2500,
+	2100, 2800, 2200, 2300,
+	2400, 2400, 2400, 2400,
+};
+static const u16 VAUX3_VSEL_table[] = {
+	1500, 1800, 2500, 2800,
+	3000, 3000, 3000, 3000,
+};
+static const u16 VAUX4_VSEL_table[] = {
+	700, 1000, 1200, UNSUP(1300),
+	1500, 1800, UNSUP(1850), 2500,
+	UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
+	UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VMMC1_VSEL_table[] = {
+	1850, 2850, 3000, 3150,
+};
+static const u16 VMMC2_VSEL_table[] = {
+	UNSUP(1000), UNSUP(1000), UNSUP(1200), UNSUP(1300),
+	UNSUP(1500), UNSUP(1800), 1850, UNSUP(2500),
+	2600, 2800, 2850, 3000,
+	3150, 3150, 3150, 3150,
+};
+static const u16 VPLL1_VSEL_table[] = {
+	1000, 1200, 1300, 1800,
+	UNSUP(2800), UNSUP(3000), UNSUP(3000), UNSUP(3000),
+};
+static const u16 VPLL2_VSEL_table[] = {
+	700, 1000, 1200, 1300,
+	UNSUP(1500), 1800, UNSUP(1850), UNSUP(2500),
+	UNSUP(2600), UNSUP(2800), UNSUP(2850), UNSUP(3000),
+	UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VSIM_VSEL_table[] = {
+	UNSUP(1000), UNSUP(1200), UNSUP(1300), 1800,
+	2800, 3000, 3000, 3000,
+};
+static const u16 VDAC_VSEL_table[] = {
+	1200, 1300, 1800, 1800,
+};
+static const u16 VDD1_VSEL_table[] = {
+	800, 1450,
+};
+static const u16 VDD2_VSEL_table[] = {
+	800, 1450, 1500,
+};
+static const u16 VIO_VSEL_table[] = {
+	1800, 1850,
+};
+static const u16 VINTANA2_VSEL_table[] = {
+	2500, 2750,
+};
+
+static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			mV = info->table[index];
+
+	return IS_UNSUP(mV) ? 0 : (LDO_MV(mV) * 1000);
+}
+
+static int
+twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+		       unsigned *selector)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			vsel;
+
+	for (vsel = 0; vsel < info->table_len; vsel++) {
+		int mV = info->table[vsel];
+		int uV;
+
+		if (IS_UNSUP(mV))
+			continue;
+		uV = LDO_MV(mV) * 1000;
+
+		/* REVISIT for VAUX2, first match may not be best/lowest */
+
+		/* use the first in-range value */
+		if (min_uV <= uV && uV <= max_uV) {
+			*selector = vsel;
+			return twlreg_write(info, TWL_MODULE_PM_RECEIVER,
+							VREG_VOLTAGE, vsel);
+		}
+	}
+
+	return -EDOM;
+}
+
+static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int		vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
+								VREG_VOLTAGE);
+
+	if (vsel < 0)
+		return vsel;
+
+	vsel &= info->table_len - 1;
+	return LDO_MV(info->table[vsel]) * 1000;
+}
+
+static struct regulator_ops twl4030ldo_ops = {
+	.list_voltage	= twl4030ldo_list_voltage,
+
+	.set_voltage	= twl4030ldo_set_voltage,
+	.get_voltage	= twl4030ldo_get_voltage,
+
+	.enable		= twl4030reg_enable,
+	.disable	= twl4030reg_disable,
+	.is_enabled	= twl4030reg_is_enabled,
+
+	.set_mode	= twl4030reg_set_mode,
+
+	.get_status	= twl4030reg_get_status,
+};
+
+static int
+twl4030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+			unsigned *selector)
+{
+	struct twlreg_info *info = rdev_get_drvdata(rdev);
+	int vsel = DIV_ROUND_UP(min_uV - 600000, 12500);
+
+	if (info->set_voltage) {
+		return info->set_voltage(info->data, min_uV);
+	} else {
+		twlreg_write(info, TWL_MODULE_PM_RECEIVER,
+			VREG_VOLTAGE_SMPS_4030, vsel);
+	}
+
+	return 0;
+}
+
+static int twl4030smps_get_voltage(struct regulator_dev *rdev)
+{
+	struct twlreg_info *info = rdev_get_drvdata(rdev);
+	int vsel;
+
+	if (info->get_voltage)
+		return info->get_voltage(info->data);
+
+	vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
+		VREG_VOLTAGE_SMPS_4030);
+
+	return vsel * 12500 + 600000;
+}
+
+static struct regulator_ops twl4030smps_ops = {
+	.set_voltage	= twl4030smps_set_voltage,
+	.get_voltage	= twl4030smps_get_voltage,
+};
+
+static int twl6030coresmps_set_voltage(struct regulator_dev *rdev, int min_uV,
+	int max_uV, unsigned *selector)
+{
+	struct twlreg_info *info = rdev_get_drvdata(rdev);
+
+	if (info->set_voltage)
+		return info->set_voltage(info->data, min_uV);
+
+	return -ENODEV;
+}
+
+static int twl6030coresmps_get_voltage(struct regulator_dev *rdev)
+{
+	struct twlreg_info *info = rdev_get_drvdata(rdev);
+
+	if (info->get_voltage)
+		return info->get_voltage(info->data);
+
+	return -ENODEV;
+}
+
+static struct regulator_ops twl6030coresmps_ops = {
+	.set_voltage	= twl6030coresmps_set_voltage,
+	.get_voltage	= twl6030coresmps_get_voltage,
+};
+
+static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+
+	return ((info->min_mV + (index * 100)) * 1000);
+}
+
+static int
+twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+		       unsigned *selector)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			vsel;
+
+	if ((min_uV/1000 < info->min_mV) || (max_uV/1000 > info->max_mV))
+		return -EDOM;
+
+	/*
+	 * Use the below formula to calculate vsel
+	 * mV = 1000mv + 100mv * (vsel - 1)
+	 */
+	vsel = (min_uV/1000 - 1000)/100 + 1;
+	*selector = vsel;
+	return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel);
+
+}
+
+static int twl6030ldo_get_voltage(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int		vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
+								VREG_VOLTAGE);
+
+	if (vsel < 0)
+		return vsel;
+
+	/*
+	 * Use the below formula to calculate vsel
+	 * mV = 1000mv + 100mv * (vsel - 1)
+	 */
+	return (1000 + (100 * (vsel - 1))) * 1000;
+}
+
+static struct regulator_ops twl6030ldo_ops = {
+	.list_voltage	= twl6030ldo_list_voltage,
+
+	.set_voltage	= twl6030ldo_set_voltage,
+	.get_voltage	= twl6030ldo_get_voltage,
+
+	.enable		= twl6030reg_enable,
+	.disable	= twl6030reg_disable,
+	.is_enabled	= twl6030reg_is_enabled,
+
+	.set_mode	= twl6030reg_set_mode,
+
+	.get_status	= twl6030reg_get_status,
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Fixed voltage LDOs don't have a VSEL field to update.
+ */
+static int twlfixed_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+
+	return info->min_mV * 1000;
+}
+
+static int twlfixed_get_voltage(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+
+	return info->min_mV * 1000;
+}
+
+static struct regulator_ops twl4030fixed_ops = {
+	.list_voltage	= twlfixed_list_voltage,
+
+	.get_voltage	= twlfixed_get_voltage,
+
+	.enable		= twl4030reg_enable,
+	.disable	= twl4030reg_disable,
+	.is_enabled	= twl4030reg_is_enabled,
+
+	.set_mode	= twl4030reg_set_mode,
+
+	.get_status	= twl4030reg_get_status,
+};
+
+static struct regulator_ops twl6030fixed_ops = {
+	.list_voltage	= twlfixed_list_voltage,
+
+	.get_voltage	= twlfixed_get_voltage,
+
+	.enable		= twl6030reg_enable,
+	.disable	= twl6030reg_disable,
+	.is_enabled	= twl6030reg_is_enabled,
+
+	.set_mode	= twl6030reg_set_mode,
+
+	.get_status	= twl6030reg_get_status,
+};
+
+static struct regulator_ops twl6030_fixed_resource = {
+	.enable		= twl6030reg_enable,
+	.disable	= twl6030reg_disable,
+	.is_enabled	= twl6030reg_is_enabled,
+	.get_status	= twl6030reg_get_status,
+};
+
+/*
+ * SMPS status and control
+ */
+
+static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+
+	int voltage = 0;
+
+	switch (info->flags) {
+	case SMPS_OFFSET_EN:
+		voltage = 100000;
+		/* fall through */
+	case 0:
+		switch (index) {
+		case 0:
+			voltage = 0;
+			break;
+		case 58:
+			voltage = 1350 * 1000;
+			break;
+		case 59:
+			voltage = 1500 * 1000;
+			break;
+		case 60:
+			voltage = 1800 * 1000;
+			break;
+		case 61:
+			voltage = 1900 * 1000;
+			break;
+		case 62:
+			voltage = 2100 * 1000;
+			break;
+		default:
+			voltage += (600000 + (12500 * (index - 1)));
+		}
+		break;
+	case SMPS_EXTENDED_EN:
+		switch (index) {
+		case 0:
+			voltage = 0;
+			break;
+		case 58:
+			voltage = 2084 * 1000;
+			break;
+		case 59:
+			voltage = 2315 * 1000;
+			break;
+		case 60:
+			voltage = 2778 * 1000;
+			break;
+		case 61:
+			voltage = 2932 * 1000;
+			break;
+		case 62:
+			voltage = 3241 * 1000;
+			break;
+		default:
+			voltage = (1852000 + (38600 * (index - 1)));
+		}
+		break;
+	case SMPS_OFFSET_EN | SMPS_EXTENDED_EN:
+		switch (index) {
+		case 0:
+			voltage = 0;
+			break;
+		case 58:
+			voltage = 4167 * 1000;
+			break;
+		case 59:
+			voltage = 2315 * 1000;
+			break;
+		case 60:
+			voltage = 2778 * 1000;
+			break;
+		case 61:
+			voltage = 2932 * 1000;
+			break;
+		case 62:
+			voltage = 3241 * 1000;
+			break;
+		default:
+			voltage = (2161000 + (38600 * (index - 1)));
+		}
+		break;
+	}
+
+	return voltage;
+}
+
+static int
+twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+			unsigned int *selector)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int	vsel = 0;
+
+	switch (info->flags) {
+	case 0:
+		if (min_uV == 0)
+			vsel = 0;
+		else if ((min_uV >= 600000) && (min_uV <= 1300000)) {
+			int calc_uV;
+			vsel = (min_uV - 600000) / 125;
+			if (vsel % 100)
+				vsel += 100;
+			vsel /= 100;
+			vsel++;
+			calc_uV = twl6030smps_list_voltage(rdev, vsel);
+			if (calc_uV > max_uV)
+				return -EINVAL;
+		}
+		/* Values 1..57 for vsel are linear and can be calculated
+		 * values 58..62 are non linear.
+		 */
+		else if ((min_uV > 1900000) && (max_uV >= 2100000))
+			vsel = 62;
+		else if ((min_uV > 1800000) && (max_uV >= 1900000))
+			vsel = 61;
+		else if ((min_uV > 1500000) && (max_uV >= 1800000))
+			vsel = 60;
+		else if ((min_uV > 1350000) && (max_uV >= 1500000))
+			vsel = 59;
+		else if ((min_uV > 1300000) && (max_uV >= 1350000))
+			vsel = 58;
+		else
+			return -EINVAL;
+		break;
+	case SMPS_OFFSET_EN:
+		if (min_uV == 0)
+			vsel = 0;
+		else if ((min_uV >= 700000) && (min_uV <= 1420000)) {
+			int calc_uV;
+			vsel = (min_uV - 700000) / 125;
+			if (vsel % 100)
+				vsel += 100;
+			vsel /= 100;
+			vsel++;
+			calc_uV = twl6030smps_list_voltage(rdev, vsel);
+			if (calc_uV > max_uV)
+				return -EINVAL;
+		}
+		/* Values 1..57 for vsel are linear and can be calculated
+		 * values 58..62 are non linear.
+		 */
+		else if ((min_uV > 1900000) && (max_uV >= 2100000))
+			vsel = 62;
+		else if ((min_uV > 1800000) && (max_uV >= 1900000))
+			vsel = 61;
+		else if ((min_uV > 1350000) && (max_uV >= 1800000))
+			vsel = 60;
+		else if ((min_uV > 1350000) && (max_uV >= 1500000))
+			vsel = 59;
+		else if ((min_uV > 1300000) && (max_uV >= 1350000))
+			vsel = 58;
+		else
+			return -EINVAL;
+		break;
+	case SMPS_EXTENDED_EN:
+		if (min_uV == 0)
+			vsel = 0;
+		else if ((min_uV >= 1852000) && (max_uV <= 4013600)) {
+			vsel = (min_uV - 1852000) / 386;
+			if (vsel % 100)
+				vsel += 100;
+			vsel /= 100;
+			vsel++;
+		}
+		break;
+	case SMPS_OFFSET_EN|SMPS_EXTENDED_EN:
+		if (min_uV == 0)
+			vsel = 0;
+		else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
+			vsel = (min_uV - 2161000) / 386;
+			if (vsel % 100)
+				vsel += 100;
+			vsel /= 100;
+			vsel++;
+		}
+		break;
+	}
+
+	*selector = vsel;
+
+	return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS,
+							vsel);
+}
+
+static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+
+	return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS);
+}
+
+static struct regulator_ops twlsmps_ops = {
+	.list_voltage		= twl6030smps_list_voltage,
+
+	.set_voltage		= twl6030smps_set_voltage,
+	.get_voltage_sel	= twl6030smps_get_voltage_sel,
+
+	.enable			= twl6030reg_enable,
+	.disable		= twl6030reg_disable,
+	.is_enabled		= twl6030reg_is_enabled,
+
+	.set_mode		= twl6030reg_set_mode,
+
+	.get_status		= twl6030reg_get_status,
+};
+
+/*----------------------------------------------------------------------*/
+
+#define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+			remap_conf) \
+		TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+			remap_conf, TWL4030, twl4030fixed_ops)
+#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \
+		TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \
+			0x0, TWL6030, twl6030fixed_ops)
+
+#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
+static struct twlreg_info TWL4030_INFO_##label = { \
+	.base = offset, \
+	.id = num, \
+	.table_len = ARRAY_SIZE(label##_VSEL_table), \
+	.table = label##_VSEL_table, \
+	.delay = turnon_delay, \
+	.remap = remap_conf, \
+	.desc = { \
+		.name = #label, \
+		.id = TWL4030_REG_##label, \
+		.n_voltages = ARRAY_SIZE(label##_VSEL_table), \
+		.ops = &twl4030ldo_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+#define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \
+static struct twlreg_info TWL4030_INFO_##label = { \
+	.base = offset, \
+	.id = num, \
+	.delay = turnon_delay, \
+	.remap = remap_conf, \
+	.desc = { \
+		.name = #label, \
+		.id = TWL4030_REG_##label, \
+		.ops = &twl4030smps_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+#define TWL6030_ADJUSTABLE_SMPS(label) \
+static struct twlreg_info TWL6030_INFO_##label = { \
+	.desc = { \
+		.name = #label, \
+		.id = TWL6030_REG_##label, \
+		.ops = &twl6030coresmps_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
+static struct twlreg_info TWL6030_INFO_##label = { \
+	.base = offset, \
+	.min_mV = min_mVolts, \
+	.max_mV = max_mVolts, \
+	.desc = { \
+		.name = #label, \
+		.id = TWL6030_REG_##label, \
+		.n_voltages = (max_mVolts - min_mVolts)/100 + 1, \
+		.ops = &twl6030ldo_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
+static struct twlreg_info TWL6025_INFO_##label = { \
+	.base = offset, \
+	.min_mV = min_mVolts, \
+	.max_mV = max_mVolts, \
+	.desc = { \
+		.name = #label, \
+		.id = TWL6025_REG_##label, \
+		.n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \
+		.ops = &twl6030ldo_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+#define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
+		family, operations) \
+static struct twlreg_info TWLFIXED_INFO_##label = { \
+	.base = offset, \
+	.id = num, \
+	.min_mV = mVolts, \
+	.delay = turnon_delay, \
+	.remap = remap_conf, \
+	.desc = { \
+		.name = #label, \
+		.id = family##_REG_##label, \
+		.n_voltages = 1, \
+		.ops = &operations, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) \
+static struct twlreg_info TWLRES_INFO_##label = { \
+	.base = offset, \
+	.delay = turnon_delay, \
+	.desc = { \
+		.name = #label, \
+		.id = TWL6030_REG_##label, \
+		.ops = &twl6030_fixed_resource, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+#define TWL6025_ADJUSTABLE_SMPS(label, offset) \
+static struct twlreg_info TWLSMPS_INFO_##label = { \
+	.base = offset, \
+	.min_mV = 600, \
+	.max_mV = 2100, \
+	.desc = { \
+		.name = #label, \
+		.id = TWL6025_REG_##label, \
+		.n_voltages = 63, \
+		.ops = &twlsmps_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+/*
+ * We list regulators here if systems need some level of
+ * software control over them after boot.
+ */
+TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7, 100, 0x00);
+TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9, 100, 0x00);
+TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08);
+TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08);
+TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08);
+TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08);
+/* VUSBCP is managed *only* by the USB subchip */
+/* 6030 REG with base as PMC Slave Misc : 0x0030 */
+/* Turnon-delay and remap configuration values for 6030 are not
+   verified since the specification is not public */
+TWL6030_ADJUSTABLE_SMPS(VDD1);
+TWL6030_ADJUSTABLE_SMPS(VDD2);
+TWL6030_ADJUSTABLE_SMPS(VDD3);
+TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300);
+TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300);
+TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300);
+TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300);
+TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300);
+TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300);
+/* 6025 are renamed compared to 6030 versions */
+TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300);
+TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300);
+TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300);
+TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300);
+TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300);
+TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300);
+TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300);
+TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300);
+TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300);
+TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08);
+TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08);
+TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08);
+TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08);
+TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08);
+TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0);
+TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0);
+TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0);
+TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0);
+TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0);
+TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0);
+TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0);
+TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34);
+TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10);
+TWL6025_ADJUSTABLE_SMPS(VIO, 0x16);
+
+static u8 twl_get_smps_offset(void)
+{
+	u8 value;
+
+	twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+			TWL6030_SMPS_OFFSET);
+	return value;
+}
+
+static u8 twl_get_smps_mult(void)
+{
+	u8 value;
+
+	twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+			TWL6030_SMPS_MULT);
+	return value;
+}
+
+#define TWL_OF_MATCH(comp, family, label) \
+	{ \
+		.compatible = comp, \
+		.data = &family##_INFO_##label, \
+	}
+
+#define TWL4030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL4030, label)
+#define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label)
+#define TWL6025_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6025, label)
+#define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label)
+#define TWLRES_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLRES, label)
+#define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label)
+
+static const struct of_device_id twl_of_match[] __devinitconst = {
+	TWL4030_OF_MATCH("ti,twl4030-vaux1", VAUX1),
+	TWL4030_OF_MATCH("ti,twl4030-vaux2", VAUX2_4030),
+	TWL4030_OF_MATCH("ti,twl5030-vaux2", VAUX2),
+	TWL4030_OF_MATCH("ti,twl4030-vaux3", VAUX3),
+	TWL4030_OF_MATCH("ti,twl4030-vaux4", VAUX4),
+	TWL4030_OF_MATCH("ti,twl4030-vmmc1", VMMC1),
+	TWL4030_OF_MATCH("ti,twl4030-vmmc2", VMMC2),
+	TWL4030_OF_MATCH("ti,twl4030-vpll1", VPLL1),
+	TWL4030_OF_MATCH("ti,twl4030-vpll2", VPLL2),
+	TWL4030_OF_MATCH("ti,twl4030-vsim", VSIM),
+	TWL4030_OF_MATCH("ti,twl4030-vdac", VDAC),
+	TWL4030_OF_MATCH("ti,twl4030-vintana2", VINTANA2),
+	TWL4030_OF_MATCH("ti,twl4030-vio", VIO),
+	TWL4030_OF_MATCH("ti,twl4030-vdd1", VDD1),
+	TWL4030_OF_MATCH("ti,twl4030-vdd2", VDD2),
+	TWL6030_OF_MATCH("ti,twl6030-vdd1", VDD1),
+	TWL6030_OF_MATCH("ti,twl6030-vdd2", VDD2),
+	TWL6030_OF_MATCH("ti,twl6030-vdd3", VDD3),
+	TWL6030_OF_MATCH("ti,twl6030-vaux1", VAUX1_6030),
+	TWL6030_OF_MATCH("ti,twl6030-vaux2", VAUX2_6030),
+	TWL6030_OF_MATCH("ti,twl6030-vaux3", VAUX3_6030),
+	TWL6030_OF_MATCH("ti,twl6030-vmmc", VMMC),
+	TWL6030_OF_MATCH("ti,twl6030-vpp", VPP),
+	TWL6030_OF_MATCH("ti,twl6030-vusim", VUSIM),
+	TWL6025_OF_MATCH("ti,twl6025-ldo2", LDO2),
+	TWL6025_OF_MATCH("ti,twl6025-ldo4", LDO4),
+	TWL6025_OF_MATCH("ti,twl6025-ldo3", LDO3),
+	TWL6025_OF_MATCH("ti,twl6025-ldo5", LDO5),
+	TWL6025_OF_MATCH("ti,twl6025-ldo1", LDO1),
+	TWL6025_OF_MATCH("ti,twl6025-ldo7", LDO7),
+	TWL6025_OF_MATCH("ti,twl6025-ldo6", LDO6),
+	TWL6025_OF_MATCH("ti,twl6025-ldoln", LDOLN),
+	TWL6025_OF_MATCH("ti,twl6025-ldousb", LDOUSB),
+	TWLFIXED_OF_MATCH("ti,twl4030-vintana1", VINTANA1),
+	TWLFIXED_OF_MATCH("ti,twl4030-vintdig", VINTDIG),
+	TWLFIXED_OF_MATCH("ti,twl4030-vusb1v5", VUSB1V5),
+	TWLFIXED_OF_MATCH("ti,twl4030-vusb1v8", VUSB1V8),
+	TWLFIXED_OF_MATCH("ti,twl4030-vusb3v1", VUSB3V1),
+	TWLFIXED_OF_MATCH("ti,twl6030-vana", VANA),
+	TWLFIXED_OF_MATCH("ti,twl6030-vcxio", VCXIO),
+	TWLFIXED_OF_MATCH("ti,twl6030-vdac", VDAC),
+	TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB),
+	TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8),
+	TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1),
+	TWLRES_OF_MATCH("ti,twl6030-clk32kg", CLK32KG),
+	TWLSMPS_OF_MATCH("ti,twl6025-smps3", SMPS3),
+	TWLSMPS_OF_MATCH("ti,twl6025-smps4", SMPS4),
+	TWLSMPS_OF_MATCH("ti,twl6025-vio", VIO),
+	{},
+};
+MODULE_DEVICE_TABLE(of, twl_of_match);
+
+static int __devinit twlreg_probe(struct platform_device *pdev)
+{
+	int				i, id;
+	struct twlreg_info		*info;
+	struct regulator_init_data	*initdata;
+	struct regulation_constraints	*c;
+	struct regulator_dev		*rdev;
+	struct twl_regulator_driver_data	*drvdata;
+	const struct of_device_id	*match;
+
+	match = of_match_device(twl_of_match, &pdev->dev);
+	if (match) {
+		info = match->data;
+		id = info->desc.id;
+		initdata = of_get_regulator_init_data(&pdev->dev,
+						      pdev->dev.of_node);
+		drvdata = NULL;
+	} else {
+		id = pdev->id;
+		initdata = pdev->dev.platform_data;
+		for (i = 0, info = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
+			info = twl_of_match[i].data;
+			if (!info || info->desc.id != id)
+				continue;
+			break;
+		}
+		drvdata = initdata->driver_data;
+		if (!drvdata)
+			return -EINVAL;
+	}
+
+	if (!info)
+		return -ENODEV;
+
+	if (!initdata)
+		return -EINVAL;
+
+	if (drvdata) {
+		/* copy the driver data into regulator data */
+		info->features = drvdata->features;
+		info->data = drvdata->data;
+		info->set_voltage = drvdata->set_voltage;
+		info->get_voltage = drvdata->get_voltage;
+	}
+
+	/* Constrain board-specific capabilities according to what
+	 * this driver and the chip itself can actually do.
+	 */
+	c = &initdata->constraints;
+	c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY;
+	c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
+				| REGULATOR_CHANGE_MODE
+				| REGULATOR_CHANGE_STATUS;
+	switch (id) {
+	case TWL4030_REG_VIO:
+	case TWL4030_REG_VDD1:
+	case TWL4030_REG_VDD2:
+	case TWL4030_REG_VPLL1:
+	case TWL4030_REG_VINTANA1:
+	case TWL4030_REG_VINTANA2:
+	case TWL4030_REG_VINTDIG:
+		c->always_on = true;
+		break;
+	default:
+		break;
+	}
+
+	switch (id) {
+	case TWL6025_REG_SMPS3:
+		if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3)
+			info->flags |= SMPS_EXTENDED_EN;
+		if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3)
+			info->flags |= SMPS_OFFSET_EN;
+		break;
+	case TWL6025_REG_SMPS4:
+		if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4)
+			info->flags |= SMPS_EXTENDED_EN;
+		if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4)
+			info->flags |= SMPS_OFFSET_EN;
+		break;
+	case TWL6025_REG_VIO:
+		if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO)
+			info->flags |= SMPS_EXTENDED_EN;
+		if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO)
+			info->flags |= SMPS_OFFSET_EN;
+		break;
+	}
+
+	rdev = regulator_register(&info->desc, &pdev->dev, initdata, info,
+							pdev->dev.of_node);
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "can't register %s, %ld\n",
+				info->desc.name, PTR_ERR(rdev));
+		return PTR_ERR(rdev);
+	}
+	platform_set_drvdata(pdev, rdev);
+
+	if (twl_class_is_4030())
+		twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
+						info->remap);
+
+	/* NOTE:  many regulators support short-circuit IRQs (presentable
+	 * as REGULATOR_OVER_CURRENT notifications?) configured via:
+	 *  - SC_CONFIG
+	 *  - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4)
+	 *  - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2)
+	 *  - IT_CONFIG
+	 */
+
+	return 0;
+}
+
+static int __devexit twlreg_remove(struct platform_device *pdev)
+{
+	regulator_unregister(platform_get_drvdata(pdev));
+	return 0;
+}
+
+MODULE_ALIAS("platform:twl_reg");
+
+static struct platform_driver twlreg_driver = {
+	.probe		= twlreg_probe,
+	.remove		= __devexit_p(twlreg_remove),
+	/* NOTE: short name, to work around driver model truncation of
+	 * "twl_regulator.12" (and friends) to "twl_regulator.1".
+	 */
+	.driver  = {
+		.name  = "twl_reg",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(twl_of_match),
+	},
+};
+
+static int __init twlreg_init(void)
+{
+	return platform_driver_register(&twlreg_driver);
+}
+subsys_initcall(twlreg_init);
+
+static void __exit twlreg_exit(void)
+{
+	platform_driver_unregister(&twlreg_driver);
+}
+module_exit(twlreg_exit)
+
+MODULE_DESCRIPTION("TWL regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/userspace-consumer.c b/ap/os/linux/linux-3.4.x/drivers/regulator/userspace-consumer.c
new file mode 100644
index 0000000..518667e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/userspace-consumer.c
@@ -0,0 +1,192 @@
+/*
+ * userspace-consumer.c
+ *
+ * Copyright 2009 CompuLab, Ltd.
+ *
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based of virtual consumer driver:
+ *   Copyright 2008 Wolfson Microelectronics PLC.
+ *   Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/userspace-consumer.h>
+#include <linux/slab.h>
+
+struct userspace_consumer_data {
+	const char *name;
+
+	struct mutex lock;
+	bool enabled;
+
+	int num_supplies;
+	struct regulator_bulk_data *supplies;
+};
+
+static ssize_t reg_show_name(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct userspace_consumer_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+
+static ssize_t reg_show_state(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct userspace_consumer_data *data = dev_get_drvdata(dev);
+
+	if (data->enabled)
+		return sprintf(buf, "enabled\n");
+
+	return sprintf(buf, "disabled\n");
+}
+
+static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct userspace_consumer_data *data = dev_get_drvdata(dev);
+	bool enabled;
+	int ret;
+
+	/*
+	 * sysfs_streq() doesn't need the \n's, but we add them so the strings
+	 * will be shared with show_state(), above.
+	 */
+	if (sysfs_streq(buf, "enabled\n") || sysfs_streq(buf, "1"))
+		enabled = true;
+	else if (sysfs_streq(buf, "disabled\n") || sysfs_streq(buf, "0"))
+		enabled = false;
+	else {
+		dev_err(dev, "Configuring invalid mode\n");
+		return count;
+	}
+
+	mutex_lock(&data->lock);
+	if (enabled != data->enabled) {
+		if (enabled)
+			ret = regulator_bulk_enable(data->num_supplies,
+						    data->supplies);
+		else
+			ret = regulator_bulk_disable(data->num_supplies,
+						     data->supplies);
+
+		if (ret == 0)
+			data->enabled = enabled;
+		else
+			dev_err(dev, "Failed to configure state: %d\n", ret);
+	}
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static DEVICE_ATTR(name, 0444, reg_show_name, NULL);
+static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state);
+
+static struct attribute *attributes[] = {
+	&dev_attr_name.attr,
+	&dev_attr_state.attr,
+	NULL,
+};
+
+static const struct attribute_group attr_group = {
+	.attrs	= attributes,
+};
+
+static int regulator_userspace_consumer_probe(struct platform_device *pdev)
+{
+	struct regulator_userspace_consumer_data *pdata;
+	struct userspace_consumer_data *drvdata;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata)
+		return -EINVAL;
+
+	drvdata = kzalloc(sizeof(struct userspace_consumer_data), GFP_KERNEL);
+	if (drvdata == NULL)
+		return -ENOMEM;
+
+	drvdata->name = pdata->name;
+	drvdata->num_supplies = pdata->num_supplies;
+	drvdata->supplies = pdata->supplies;
+
+	mutex_init(&drvdata->lock);
+
+	ret = regulator_bulk_get(&pdev->dev, drvdata->num_supplies,
+				 drvdata->supplies);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret);
+		goto err_alloc_supplies;
+	}
+
+	ret = sysfs_create_group(&pdev->dev.kobj, &attr_group);
+	if (ret != 0)
+		goto err_create_attrs;
+
+	if (pdata->init_on) {
+		ret = regulator_bulk_enable(drvdata->num_supplies,
+					    drvdata->supplies);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed to set initial state: %d\n", ret);
+			goto err_enable;
+		}
+	}
+
+	drvdata->enabled = pdata->init_on;
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;
+
+err_enable:
+	sysfs_remove_group(&pdev->dev.kobj, &attr_group);
+
+err_create_attrs:
+	regulator_bulk_free(drvdata->num_supplies, drvdata->supplies);
+
+err_alloc_supplies:
+	kfree(drvdata);
+	return ret;
+}
+
+static int regulator_userspace_consumer_remove(struct platform_device *pdev)
+{
+	struct userspace_consumer_data *data = platform_get_drvdata(pdev);
+
+	sysfs_remove_group(&pdev->dev.kobj, &attr_group);
+
+	if (data->enabled)
+		regulator_bulk_disable(data->num_supplies, data->supplies);
+
+	regulator_bulk_free(data->num_supplies, data->supplies);
+	kfree(data);
+
+	return 0;
+}
+
+static struct platform_driver regulator_userspace_consumer_driver = {
+	.probe		= regulator_userspace_consumer_probe,
+	.remove		= regulator_userspace_consumer_remove,
+	.driver		= {
+		.name		= "reg-userspace-consumer",
+	},
+};
+
+module_platform_driver(regulator_userspace_consumer_driver);
+
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/virtual.c b/ap/os/linux/linux-3.4.x/drivers/regulator/virtual.c
new file mode 100644
index 0000000..ee0b161
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/virtual.c
@@ -0,0 +1,360 @@
+/*
+ * reg-virtual-consumer.c
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+struct virtual_consumer_data {
+	struct mutex lock;
+	struct regulator *regulator;
+	bool enabled;
+	int min_uV;
+	int max_uV;
+	int min_uA;
+	int max_uA;
+	unsigned int mode;
+};
+
+static void update_voltage_constraints(struct device *dev,
+				       struct virtual_consumer_data *data)
+{
+	int ret;
+
+	if (data->min_uV && data->max_uV
+	    && data->min_uV <= data->max_uV) {
+		dev_dbg(dev, "Requesting %d-%duV\n",
+			data->min_uV, data->max_uV);
+		ret = regulator_set_voltage(data->regulator,
+					data->min_uV, data->max_uV);
+		if (ret != 0) {
+			dev_err(dev,
+				"regulator_set_voltage() failed: %d\n", ret);
+			return;
+		}
+	}
+
+	if (data->min_uV && data->max_uV && !data->enabled) {
+		dev_dbg(dev, "Enabling regulator\n");
+		ret = regulator_enable(data->regulator);
+		if (ret == 0)
+			data->enabled = true;
+		else
+			dev_err(dev, "regulator_enable() failed: %d\n",
+				ret);
+	}
+
+	if (!(data->min_uV && data->max_uV) && data->enabled) {
+		dev_dbg(dev, "Disabling regulator\n");
+		ret = regulator_disable(data->regulator);
+		if (ret == 0)
+			data->enabled = false;
+		else
+			dev_err(dev, "regulator_disable() failed: %d\n",
+				ret);
+	}
+}
+
+static void update_current_limit_constraints(struct device *dev,
+					  struct virtual_consumer_data *data)
+{
+	int ret;
+
+	if (data->max_uA
+	    && data->min_uA <= data->max_uA) {
+		dev_dbg(dev, "Requesting %d-%duA\n",
+			data->min_uA, data->max_uA);
+		ret = regulator_set_current_limit(data->regulator,
+					data->min_uA, data->max_uA);
+		if (ret != 0) {
+			dev_err(dev,
+				"regulator_set_current_limit() failed: %d\n",
+				ret);
+			return;
+		}
+	}
+
+	if (data->max_uA && !data->enabled) {
+		dev_dbg(dev, "Enabling regulator\n");
+		ret = regulator_enable(data->regulator);
+		if (ret == 0)
+			data->enabled = true;
+		else
+			dev_err(dev, "regulator_enable() failed: %d\n",
+				ret);
+	}
+
+	if (!(data->min_uA && data->max_uA) && data->enabled) {
+		dev_dbg(dev, "Disabling regulator\n");
+		ret = regulator_disable(data->regulator);
+		if (ret == 0)
+			data->enabled = false;
+		else
+			dev_err(dev, "regulator_disable() failed: %d\n",
+				ret);
+	}
+}
+
+static ssize_t show_min_uV(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->min_uV);
+}
+
+static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (strict_strtol(buf, 10, &val) != 0)
+		return count;
+
+	mutex_lock(&data->lock);
+
+	data->min_uV = val;
+	update_voltage_constraints(dev, data);
+
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_max_uV(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->max_uV);
+}
+
+static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (strict_strtol(buf, 10, &val) != 0)
+		return count;
+
+	mutex_lock(&data->lock);
+
+	data->max_uV = val;
+	update_voltage_constraints(dev, data);
+
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_min_uA(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->min_uA);
+}
+
+static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (strict_strtol(buf, 10, &val) != 0)
+		return count;
+
+	mutex_lock(&data->lock);
+
+	data->min_uA = val;
+	update_current_limit_constraints(dev, data);
+
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_max_uA(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", data->max_uA);
+}
+
+static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+	long val;
+
+	if (strict_strtol(buf, 10, &val) != 0)
+		return count;
+
+	mutex_lock(&data->lock);
+
+	data->max_uA = val;
+	update_current_limit_constraints(dev, data);
+
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static ssize_t show_mode(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+
+	switch (data->mode) {
+	case REGULATOR_MODE_FAST:
+		return sprintf(buf, "fast\n");
+	case REGULATOR_MODE_NORMAL:
+		return sprintf(buf, "normal\n");
+	case REGULATOR_MODE_IDLE:
+		return sprintf(buf, "idle\n");
+	case REGULATOR_MODE_STANDBY:
+		return sprintf(buf, "standby\n");
+	default:
+		return sprintf(buf, "unknown\n");
+	}
+}
+
+static ssize_t set_mode(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct virtual_consumer_data *data = dev_get_drvdata(dev);
+	unsigned int mode;
+	int ret;
+
+	/*
+	 * sysfs_streq() doesn't need the \n's, but we add them so the strings
+	 * will be shared with show_mode(), above.
+	 */
+	if (sysfs_streq(buf, "fast\n"))
+		mode = REGULATOR_MODE_FAST;
+	else if (sysfs_streq(buf, "normal\n"))
+		mode = REGULATOR_MODE_NORMAL;
+	else if (sysfs_streq(buf, "idle\n"))
+		mode = REGULATOR_MODE_IDLE;
+	else if (sysfs_streq(buf, "standby\n"))
+		mode = REGULATOR_MODE_STANDBY;
+	else {
+		dev_err(dev, "Configuring invalid mode\n");
+		return count;
+	}
+
+	mutex_lock(&data->lock);
+	ret = regulator_set_mode(data->regulator, mode);
+	if (ret == 0)
+		data->mode = mode;
+	else
+		dev_err(dev, "Failed to configure mode: %d\n", ret);
+	mutex_unlock(&data->lock);
+
+	return count;
+}
+
+static DEVICE_ATTR(min_microvolts, 0666, show_min_uV, set_min_uV);
+static DEVICE_ATTR(max_microvolts, 0666, show_max_uV, set_max_uV);
+static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA);
+static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA);
+static DEVICE_ATTR(mode, 0666, show_mode, set_mode);
+
+static struct attribute *regulator_virtual_attributes[] = {
+	&dev_attr_min_microvolts.attr,
+	&dev_attr_max_microvolts.attr,
+	&dev_attr_min_microamps.attr,
+	&dev_attr_max_microamps.attr,
+	&dev_attr_mode.attr,
+	NULL
+};
+
+static const struct attribute_group regulator_virtual_attr_group = {
+	.attrs	= regulator_virtual_attributes,
+};
+
+static int __devinit regulator_virtual_probe(struct platform_device *pdev)
+{
+	char *reg_id = pdev->dev.platform_data;
+	struct virtual_consumer_data *drvdata;
+	int ret;
+
+	drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL);
+	if (drvdata == NULL)
+		return -ENOMEM;
+
+	mutex_init(&drvdata->lock);
+
+	drvdata->regulator = regulator_get(&pdev->dev, reg_id);
+	if (IS_ERR(drvdata->regulator)) {
+		ret = PTR_ERR(drvdata->regulator);
+		dev_err(&pdev->dev, "Failed to obtain supply '%s': %d\n",
+			reg_id, ret);
+		goto err;
+	}
+
+	ret = sysfs_create_group(&pdev->dev.kobj,
+				 &regulator_virtual_attr_group);
+	if (ret != 0) {
+		dev_err(&pdev->dev,
+			"Failed to create attribute group: %d\n", ret);
+		goto err_regulator;
+	}
+
+	drvdata->mode = regulator_get_mode(drvdata->regulator);
+
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;
+
+err_regulator:
+	regulator_put(drvdata->regulator);
+err:
+	kfree(drvdata);
+	return ret;
+}
+
+static int __devexit regulator_virtual_remove(struct platform_device *pdev)
+{
+	struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev);
+
+	sysfs_remove_group(&pdev->dev.kobj, &regulator_virtual_attr_group);
+
+	if (drvdata->enabled)
+		regulator_disable(drvdata->regulator);
+	regulator_put(drvdata->regulator);
+
+	kfree(drvdata);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver regulator_virtual_consumer_driver = {
+	.probe		= regulator_virtual_probe,
+	.remove		= __devexit_p(regulator_virtual_remove),
+	.driver		= {
+		.name		= "reg-virt-consumer",
+		.owner		= THIS_MODULE,
+	},
+};
+
+module_platform_driver(regulator_virtual_consumer_driver);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Virtual regulator consumer");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:reg-virt-consumer");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/wm831x-dcdc.c b/ap/os/linux/linux-3.4.x/drivers/regulator/wm831x-dcdc.c
new file mode 100644
index 0000000..97bb31d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/wm831x-dcdc.c
@@ -0,0 +1,1053 @@
+/*
+ * wm831x-dcdc.c  --  DC-DC buck convertor driver for the WM831x series
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/regulator.h>
+#include <linux/mfd/wm831x/pdata.h>
+
+#define WM831X_BUCKV_MAX_SELECTOR 0x68
+#define WM831X_BUCKP_MAX_SELECTOR 0x66
+
+#define WM831X_DCDC_MODE_FAST    0
+#define WM831X_DCDC_MODE_NORMAL  1
+#define WM831X_DCDC_MODE_IDLE    2
+#define WM831X_DCDC_MODE_STANDBY 3
+
+#define WM831X_DCDC_MAX_NAME 6
+
+/* Register offsets in control block */
+#define WM831X_DCDC_CONTROL_1     0
+#define WM831X_DCDC_CONTROL_2     1
+#define WM831X_DCDC_ON_CONFIG     2
+#define WM831X_DCDC_SLEEP_CONTROL 3
+#define WM831X_DCDC_DVS_CONTROL   4
+
+/*
+ * Shared
+ */
+
+struct wm831x_dcdc {
+	char name[WM831X_DCDC_MAX_NAME];
+	struct regulator_desc desc;
+	int base;
+	struct wm831x *wm831x;
+	struct regulator_dev *regulator;
+	int dvs_gpio;
+	int dvs_gpio_state;
+	int on_vsel;
+	int dvs_vsel;
+};
+
+static int wm831x_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	int mask = 1 << rdev_get_id(rdev);
+	int reg;
+
+	reg = wm831x_reg_read(wm831x, WM831X_DCDC_ENABLE);
+	if (reg < 0)
+		return reg;
+
+	if (reg & mask)
+		return 1;
+	else
+		return 0;
+}
+
+static int wm831x_dcdc_enable(struct regulator_dev *rdev)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	int mask = 1 << rdev_get_id(rdev);
+
+	return wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, mask, mask);
+}
+
+static int wm831x_dcdc_disable(struct regulator_dev *rdev)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	int mask = 1 << rdev_get_id(rdev);
+
+	return wm831x_set_bits(wm831x, WM831X_DCDC_ENABLE, mask, 0);
+}
+
+static unsigned int wm831x_dcdc_get_mode(struct regulator_dev *rdev)
+
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+	int val;
+
+	val = wm831x_reg_read(wm831x, reg);
+	if (val < 0)
+		return val;
+
+	val = (val & WM831X_DC1_ON_MODE_MASK) >> WM831X_DC1_ON_MODE_SHIFT;
+
+	switch (val) {
+	case WM831X_DCDC_MODE_FAST:
+		return REGULATOR_MODE_FAST;
+	case WM831X_DCDC_MODE_NORMAL:
+		return REGULATOR_MODE_NORMAL;
+	case WM831X_DCDC_MODE_STANDBY:
+		return REGULATOR_MODE_STANDBY;
+	case WM831X_DCDC_MODE_IDLE:
+		return REGULATOR_MODE_IDLE;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+}
+
+static int wm831x_dcdc_set_mode_int(struct wm831x *wm831x, int reg,
+				    unsigned int mode)
+{
+	int val;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		val = WM831X_DCDC_MODE_FAST;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = WM831X_DCDC_MODE_NORMAL;
+		break;
+	case REGULATOR_MODE_STANDBY:
+		val = WM831X_DCDC_MODE_STANDBY;
+		break;
+	case REGULATOR_MODE_IDLE:
+		val = WM831X_DCDC_MODE_IDLE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return wm831x_set_bits(wm831x, reg, WM831X_DC1_ON_MODE_MASK,
+			       val << WM831X_DC1_ON_MODE_SHIFT);
+}
+
+static int wm831x_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+
+	return wm831x_dcdc_set_mode_int(wm831x, reg, mode);
+}
+
+static int wm831x_dcdc_set_suspend_mode(struct regulator_dev *rdev,
+					unsigned int mode)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
+
+	return wm831x_dcdc_set_mode_int(wm831x, reg, mode);
+}
+
+static int wm831x_dcdc_get_status(struct regulator_dev *rdev)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	int ret;
+
+	/* First, check for errors */
+	ret = wm831x_reg_read(wm831x, WM831X_DCDC_UV_STATUS);
+	if (ret < 0)
+		return ret;
+
+	if (ret & (1 << rdev_get_id(rdev))) {
+		dev_dbg(wm831x->dev, "DCDC%d under voltage\n",
+			rdev_get_id(rdev) + 1);
+		return REGULATOR_STATUS_ERROR;
+	}
+
+	/* DCDC1 and DCDC2 can additionally detect high voltage/current */
+	if (rdev_get_id(rdev) < 2) {
+		if (ret & (WM831X_DC1_OV_STS << rdev_get_id(rdev))) {
+			dev_dbg(wm831x->dev, "DCDC%d over voltage\n",
+				rdev_get_id(rdev) + 1);
+			return REGULATOR_STATUS_ERROR;
+		}
+
+		if (ret & (WM831X_DC1_HC_STS << rdev_get_id(rdev))) {
+			dev_dbg(wm831x->dev, "DCDC%d over current\n",
+				rdev_get_id(rdev) + 1);
+			return REGULATOR_STATUS_ERROR;
+		}
+	}
+
+	/* Is the regulator on? */
+	ret = wm831x_reg_read(wm831x, WM831X_DCDC_STATUS);
+	if (ret < 0)
+		return ret;
+	if (!(ret & (1 << rdev_get_id(rdev))))
+		return REGULATOR_STATUS_OFF;
+
+	/* TODO: When we handle hardware control modes so we can report the
+	 * current mode. */
+	return REGULATOR_STATUS_ON;
+}
+
+static irqreturn_t wm831x_dcdc_uv_irq(int irq, void *data)
+{
+	struct wm831x_dcdc *dcdc = data;
+
+	regulator_notifier_call_chain(dcdc->regulator,
+				      REGULATOR_EVENT_UNDER_VOLTAGE,
+				      NULL);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wm831x_dcdc_oc_irq(int irq, void *data)
+{
+	struct wm831x_dcdc *dcdc = data;
+
+	regulator_notifier_call_chain(dcdc->regulator,
+				      REGULATOR_EVENT_OVER_CURRENT,
+				      NULL);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * BUCKV specifics
+ */
+
+static int wm831x_buckv_list_voltage(struct regulator_dev *rdev,
+				      unsigned selector)
+{
+	if (selector <= 0x8)
+		return 600000;
+	if (selector <= WM831X_BUCKV_MAX_SELECTOR)
+		return 600000 + ((selector - 0x8) * 12500);
+	return -EINVAL;
+}
+
+static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
+					   int min_uV, int max_uV)
+{
+	u16 vsel;
+
+	if (min_uV < 600000)
+		vsel = 0;
+	else if (min_uV <= 1800000)
+		vsel = ((min_uV - 600000) / 12500) + 8;
+	else
+		return -EINVAL;
+
+	if (wm831x_buckv_list_voltage(rdev, vsel) > max_uV)
+		return -EINVAL;
+
+	return vsel;
+}
+
+static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+
+	if (state == dcdc->dvs_gpio_state)
+		return 0;
+
+	dcdc->dvs_gpio_state = state;
+	gpio_set_value(dcdc->dvs_gpio, state);
+
+	/* Should wait for DVS state change to be asserted if we have
+	 * a GPIO for it, for now assume the device is configured
+	 * for the fastest possible transition.
+	 */
+
+	return 0;
+}
+
+static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV, unsigned *selector)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+	int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL;
+	int vsel, ret;
+
+	vsel = wm831x_buckv_select_min_voltage(rdev, min_uV, max_uV);
+	if (vsel < 0)
+		return vsel;
+
+	*selector = vsel;
+
+	/* If this value is already set then do a GPIO update if we can */
+	if (dcdc->dvs_gpio && dcdc->on_vsel == vsel)
+		return wm831x_buckv_set_dvs(rdev, 0);
+
+	if (dcdc->dvs_gpio && dcdc->dvs_vsel == vsel)
+		return wm831x_buckv_set_dvs(rdev, 1);
+
+	/* Always set the ON status to the minimum voltage */
+	ret = wm831x_set_bits(wm831x, on_reg, WM831X_DC1_ON_VSEL_MASK, vsel);
+	if (ret < 0)
+		return ret;
+	dcdc->on_vsel = vsel;
+
+	if (!dcdc->dvs_gpio)
+		return ret;
+
+	/* Kick the voltage transition now */
+	ret = wm831x_buckv_set_dvs(rdev, 0);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If this VSEL is higher than the last one we've seen then
+	 * remember it as the DVS VSEL.  This is optimised for CPUfreq
+	 * usage where we want to get to the highest voltage very
+	 * quickly.
+	 */
+	if (vsel > dcdc->dvs_vsel) {
+		ret = wm831x_set_bits(wm831x, dvs_reg,
+				      WM831X_DC1_DVS_VSEL_MASK,
+				      vsel);
+		if (ret == 0)
+			dcdc->dvs_vsel = vsel;
+		else
+			dev_warn(wm831x->dev,
+				 "Failed to set DCDC DVS VSEL: %d\n", ret);
+	}
+
+	return 0;
+}
+
+static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev,
+					    int uV)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
+	int vsel;
+
+	vsel = wm831x_buckv_select_min_voltage(rdev, uV, uV);
+	if (vsel < 0)
+		return vsel;
+
+	return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel);
+}
+
+static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+
+	if (dcdc->dvs_gpio && dcdc->dvs_gpio_state)
+		return dcdc->dvs_vsel;
+	else
+		return dcdc->on_vsel;
+}
+
+/* Current limit options */
+static u16 wm831x_dcdc_ilim[] = {
+	125, 250, 375, 500, 625, 750, 875, 1000
+};
+
+static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev,
+					   int min_uA, int max_uA)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	u16 reg = dcdc->base + WM831X_DCDC_CONTROL_2;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm831x_dcdc_ilim); i++) {
+		if ((min_uA <= wm831x_dcdc_ilim[i]) &&
+		    (wm831x_dcdc_ilim[i] <= max_uA))
+			break;
+	}
+	if (i == ARRAY_SIZE(wm831x_dcdc_ilim))
+		return -EINVAL;
+
+	return wm831x_set_bits(wm831x, reg, WM831X_DC1_HC_THR_MASK,
+			       i << WM831X_DC1_HC_THR_SHIFT);
+}
+
+static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	u16 reg = dcdc->base + WM831X_DCDC_CONTROL_2;
+	int val;
+
+	val = wm831x_reg_read(wm831x, reg);
+	if (val < 0)
+		return val;
+
+	val = (val & WM831X_DC1_HC_THR_MASK) >> WM831X_DC1_HC_THR_SHIFT;
+	return wm831x_dcdc_ilim[val];
+}
+
+static struct regulator_ops wm831x_buckv_ops = {
+	.set_voltage = wm831x_buckv_set_voltage,
+	.get_voltage_sel = wm831x_buckv_get_voltage_sel,
+	.list_voltage = wm831x_buckv_list_voltage,
+	.set_suspend_voltage = wm831x_buckv_set_suspend_voltage,
+	.set_current_limit = wm831x_buckv_set_current_limit,
+	.get_current_limit = wm831x_buckv_get_current_limit,
+
+	.is_enabled = wm831x_dcdc_is_enabled,
+	.enable = wm831x_dcdc_enable,
+	.disable = wm831x_dcdc_disable,
+	.get_status = wm831x_dcdc_get_status,
+	.get_mode = wm831x_dcdc_get_mode,
+	.set_mode = wm831x_dcdc_set_mode,
+	.set_suspend_mode = wm831x_dcdc_set_suspend_mode,
+};
+
+/*
+ * Set up DVS control.  We just log errors since we can still run
+ * (with reduced performance) if we fail.
+ */
+static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
+					    struct wm831x_buckv_pdata *pdata)
+{
+	struct wm831x *wm831x = dcdc->wm831x;
+	int ret;
+	u16 ctrl;
+
+	if (!pdata || !pdata->dvs_gpio)
+		return;
+
+	ret = gpio_request(pdata->dvs_gpio, "DCDC DVS");
+	if (ret < 0) {
+		dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
+			dcdc->name, ret);
+		return;
+	}
+
+	/* gpiolib won't let us read the GPIO status so pick the higher
+	 * of the two existing voltages so we take it as platform data.
+	 */
+	dcdc->dvs_gpio_state = pdata->dvs_init_state;
+
+	ret = gpio_direction_output(pdata->dvs_gpio, dcdc->dvs_gpio_state);
+	if (ret < 0) {
+		dev_err(wm831x->dev, "Failed to enable %s DVS GPIO: %d\n",
+			dcdc->name, ret);
+		gpio_free(pdata->dvs_gpio);
+		return;
+	}
+
+	dcdc->dvs_gpio = pdata->dvs_gpio;
+
+	switch (pdata->dvs_control_src) {
+	case 1:
+		ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
+		break;
+	case 2:
+		ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT;
+		break;
+	default:
+		dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n",
+			pdata->dvs_control_src, dcdc->name);
+		return;
+	}
+
+	/* If DVS_VSEL is set to the minimum value then raise it to ON_VSEL
+	 * to make bootstrapping a bit smoother.
+	 */
+	if (!dcdc->dvs_vsel) {
+		ret = wm831x_set_bits(wm831x,
+				      dcdc->base + WM831X_DCDC_DVS_CONTROL,
+				      WM831X_DC1_DVS_VSEL_MASK, dcdc->on_vsel);
+		if (ret == 0)
+			dcdc->dvs_vsel = dcdc->on_vsel;
+		else
+			dev_warn(wm831x->dev, "Failed to set DVS_VSEL: %d\n",
+				 ret);
+	}
+
+	ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
+			      WM831X_DC1_DVS_SRC_MASK, ctrl);
+	if (ret < 0) {
+		dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n",
+			dcdc->name, ret);
+	}
+}
+
+static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	int id;
+	struct wm831x_dcdc *dcdc;
+	struct resource *res;
+	int ret, irq;
+
+	if (pdata && pdata->wm831x_num)
+		id = (pdata->wm831x_num * 10) + 1;
+	else
+		id = 0;
+	id = pdev->id - id;
+
+	dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
+
+	if (pdata == NULL || pdata->dcdc[id] == NULL)
+		return -ENODEV;
+
+	dcdc = devm_kzalloc(&pdev->dev,  sizeof(struct wm831x_dcdc),
+			    GFP_KERNEL);
+	if (dcdc == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	dcdc->wm831x = wm831x;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No I/O resource\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	dcdc->base = res->start;
+
+	snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1);
+	dcdc->desc.name = dcdc->name;
+	dcdc->desc.id = id;
+	dcdc->desc.type = REGULATOR_VOLTAGE;
+	dcdc->desc.n_voltages = WM831X_BUCKV_MAX_SELECTOR + 1;
+	dcdc->desc.ops = &wm831x_buckv_ops;
+	dcdc->desc.owner = THIS_MODULE;
+
+	ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
+	if (ret < 0) {
+		dev_err(wm831x->dev, "Failed to read ON VSEL: %d\n", ret);
+		goto err;
+	}
+	dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK;
+
+	ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL);
+	if (ret < 0) {
+		dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret);
+		goto err;
+	}
+	dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK;
+
+	if (pdata->dcdc[id])
+		wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data);
+
+	dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
+					     pdata->dcdc[id], dcdc, NULL);
+	if (IS_ERR(dcdc->regulator)) {
+		ret = PTR_ERR(dcdc->regulator);
+		dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
+			id + 1, ret);
+		goto err;
+	}
+
+	irq = platform_get_irq_byname(pdev, "UV");
+	ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq,
+				   IRQF_TRIGGER_RISING, dcdc->name, dcdc);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
+			irq, ret);
+		goto err_regulator;
+	}
+
+	irq = platform_get_irq_byname(pdev, "HC");
+	ret = request_threaded_irq(irq, NULL, wm831x_dcdc_oc_irq,
+				   IRQF_TRIGGER_RISING, dcdc->name, dcdc);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request HC IRQ %d: %d\n",
+			irq, ret);
+		goto err_uv;
+	}
+
+	platform_set_drvdata(pdev, dcdc);
+
+	return 0;
+
+err_uv:
+	free_irq(platform_get_irq_byname(pdev, "UV"), dcdc);
+err_regulator:
+	regulator_unregister(dcdc->regulator);
+err:
+	if (dcdc->dvs_gpio)
+		gpio_free(dcdc->dvs_gpio);
+	return ret;
+}
+
+static __devexit int wm831x_buckv_remove(struct platform_device *pdev)
+{
+	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	free_irq(platform_get_irq_byname(pdev, "HC"), dcdc);
+	free_irq(platform_get_irq_byname(pdev, "UV"), dcdc);
+	regulator_unregister(dcdc->regulator);
+	if (dcdc->dvs_gpio)
+		gpio_free(dcdc->dvs_gpio);
+
+	return 0;
+}
+
+static struct platform_driver wm831x_buckv_driver = {
+	.probe = wm831x_buckv_probe,
+	.remove = __devexit_p(wm831x_buckv_remove),
+	.driver		= {
+		.name	= "wm831x-buckv",
+		.owner	= THIS_MODULE,
+	},
+};
+
+/*
+ * BUCKP specifics
+ */
+
+static int wm831x_buckp_list_voltage(struct regulator_dev *rdev,
+				      unsigned selector)
+{
+	if (selector <= WM831X_BUCKP_MAX_SELECTOR)
+		return 850000 + (selector * 25000);
+	else
+		return -EINVAL;
+}
+
+static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg,
+					int min_uV, int max_uV, int *selector)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	u16 vsel;
+
+	if (min_uV <= 34000000)
+		vsel = (min_uV - 850000) / 25000;
+	else
+		return -EINVAL;
+
+	if (wm831x_buckp_list_voltage(rdev, vsel) > max_uV)
+		return -EINVAL;
+
+	*selector = vsel;
+
+	return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, vsel);
+}
+
+static int wm831x_buckp_set_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV,
+				    unsigned *selector)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+
+	return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV,
+					    selector);
+}
+
+static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev,
+					    int uV)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
+	unsigned selector;
+
+	return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector);
+}
+
+static int wm831x_buckp_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
+	int val;
+
+	val = wm831x_reg_read(wm831x, reg);
+	if (val < 0)
+		return val;
+
+	return val & WM831X_DC3_ON_VSEL_MASK;
+}
+
+static struct regulator_ops wm831x_buckp_ops = {
+	.set_voltage = wm831x_buckp_set_voltage,
+	.get_voltage_sel = wm831x_buckp_get_voltage_sel,
+	.list_voltage = wm831x_buckp_list_voltage,
+	.set_suspend_voltage = wm831x_buckp_set_suspend_voltage,
+
+	.is_enabled = wm831x_dcdc_is_enabled,
+	.enable = wm831x_dcdc_enable,
+	.disable = wm831x_dcdc_disable,
+	.get_status = wm831x_dcdc_get_status,
+	.get_mode = wm831x_dcdc_get_mode,
+	.set_mode = wm831x_dcdc_set_mode,
+	.set_suspend_mode = wm831x_dcdc_set_suspend_mode,
+};
+
+static __devinit int wm831x_buckp_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	int id;
+	struct wm831x_dcdc *dcdc;
+	struct resource *res;
+	int ret, irq;
+
+	if (pdata && pdata->wm831x_num)
+		id = (pdata->wm831x_num * 10) + 1;
+	else
+		id = 0;
+	id = pdev->id - id;
+
+	dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
+
+	if (pdata == NULL || pdata->dcdc[id] == NULL)
+		return -ENODEV;
+
+	dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),
+			    GFP_KERNEL);
+	if (dcdc == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	dcdc->wm831x = wm831x;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No I/O resource\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	dcdc->base = res->start;
+
+	snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1);
+	dcdc->desc.name = dcdc->name;
+	dcdc->desc.id = id;
+	dcdc->desc.type = REGULATOR_VOLTAGE;
+	dcdc->desc.n_voltages = WM831X_BUCKP_MAX_SELECTOR + 1;
+	dcdc->desc.ops = &wm831x_buckp_ops;
+	dcdc->desc.owner = THIS_MODULE;
+
+	dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
+					     pdata->dcdc[id], dcdc, NULL);
+	if (IS_ERR(dcdc->regulator)) {
+		ret = PTR_ERR(dcdc->regulator);
+		dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
+			id + 1, ret);
+		goto err;
+	}
+
+	irq = platform_get_irq_byname(pdev, "UV");
+	ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq,
+				   IRQF_TRIGGER_RISING,	dcdc->name, dcdc);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
+			irq, ret);
+		goto err_regulator;
+	}
+
+	platform_set_drvdata(pdev, dcdc);
+
+	return 0;
+
+err_regulator:
+	regulator_unregister(dcdc->regulator);
+err:
+	return ret;
+}
+
+static __devexit int wm831x_buckp_remove(struct platform_device *pdev)
+{
+	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	free_irq(platform_get_irq_byname(pdev, "UV"), dcdc);
+	regulator_unregister(dcdc->regulator);
+
+	return 0;
+}
+
+static struct platform_driver wm831x_buckp_driver = {
+	.probe = wm831x_buckp_probe,
+	.remove = __devexit_p(wm831x_buckp_remove),
+	.driver		= {
+		.name	= "wm831x-buckp",
+		.owner	= THIS_MODULE,
+	},
+};
+
+/*
+ * DCDC boost convertors
+ */
+
+static int wm831x_boostp_get_status(struct regulator_dev *rdev)
+{
+	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = dcdc->wm831x;
+	int ret;
+
+	/* First, check for errors */
+	ret = wm831x_reg_read(wm831x, WM831X_DCDC_UV_STATUS);
+	if (ret < 0)
+		return ret;
+
+	if (ret & (1 << rdev_get_id(rdev))) {
+		dev_dbg(wm831x->dev, "DCDC%d under voltage\n",
+			rdev_get_id(rdev) + 1);
+		return REGULATOR_STATUS_ERROR;
+	}
+
+	/* Is the regulator on? */
+	ret = wm831x_reg_read(wm831x, WM831X_DCDC_STATUS);
+	if (ret < 0)
+		return ret;
+	if (ret & (1 << rdev_get_id(rdev)))
+		return REGULATOR_STATUS_ON;
+	else
+		return REGULATOR_STATUS_OFF;
+}
+
+static struct regulator_ops wm831x_boostp_ops = {
+	.get_status = wm831x_boostp_get_status,
+
+	.is_enabled = wm831x_dcdc_is_enabled,
+	.enable = wm831x_dcdc_enable,
+	.disable = wm831x_dcdc_disable,
+};
+
+static __devinit int wm831x_boostp_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
+	struct wm831x_dcdc *dcdc;
+	struct resource *res;
+	int ret, irq;
+
+	dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
+
+	if (pdata == NULL || pdata->dcdc[id] == NULL)
+		return -ENODEV;
+
+	dcdc = kzalloc(sizeof(struct wm831x_dcdc), GFP_KERNEL);
+	if (dcdc == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	dcdc->wm831x = wm831x;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No I/O resource\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	dcdc->base = res->start;
+
+	snprintf(dcdc->name, sizeof(dcdc->name), "DCDC%d", id + 1);
+	dcdc->desc.name = dcdc->name;
+	dcdc->desc.id = id;
+	dcdc->desc.type = REGULATOR_VOLTAGE;
+	dcdc->desc.ops = &wm831x_boostp_ops;
+	dcdc->desc.owner = THIS_MODULE;
+
+	dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
+					     pdata->dcdc[id], dcdc, NULL);
+	if (IS_ERR(dcdc->regulator)) {
+		ret = PTR_ERR(dcdc->regulator);
+		dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",
+			id + 1, ret);
+		goto err;
+	}
+
+	irq = platform_get_irq_byname(pdev, "UV");
+	ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq,
+				   IRQF_TRIGGER_RISING, dcdc->name,
+				   dcdc);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
+			irq, ret);
+		goto err_regulator;
+	}
+
+	platform_set_drvdata(pdev, dcdc);
+
+	return 0;
+
+err_regulator:
+	regulator_unregister(dcdc->regulator);
+err:
+	kfree(dcdc);
+	return ret;
+}
+
+static __devexit int wm831x_boostp_remove(struct platform_device *pdev)
+{
+	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	free_irq(platform_get_irq_byname(pdev, "UV"), dcdc);
+	regulator_unregister(dcdc->regulator);
+	kfree(dcdc);
+
+	return 0;
+}
+
+static struct platform_driver wm831x_boostp_driver = {
+	.probe = wm831x_boostp_probe,
+	.remove = __devexit_p(wm831x_boostp_remove),
+	.driver		= {
+		.name	= "wm831x-boostp",
+		.owner	= THIS_MODULE,
+	},
+};
+
+/*
+ * External Power Enable
+ *
+ * These aren't actually DCDCs but look like them in hardware so share
+ * code.
+ */
+
+#define WM831X_EPE_BASE 6
+
+static struct regulator_ops wm831x_epe_ops = {
+	.is_enabled = wm831x_dcdc_is_enabled,
+	.enable = wm831x_dcdc_enable,
+	.disable = wm831x_dcdc_disable,
+	.get_status = wm831x_dcdc_get_status,
+};
+
+static __devinit int wm831x_epe_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	int id = pdev->id % ARRAY_SIZE(pdata->epe);
+	struct wm831x_dcdc *dcdc;
+	int ret;
+
+	dev_dbg(&pdev->dev, "Probing EPE%d\n", id + 1);
+
+	if (pdata == NULL || pdata->epe[id] == NULL)
+		return -ENODEV;
+
+	dcdc = kzalloc(sizeof(struct wm831x_dcdc), GFP_KERNEL);
+	if (dcdc == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	dcdc->wm831x = wm831x;
+
+	/* For current parts this is correct; probably need to revisit
+	 * in future.
+	 */
+	snprintf(dcdc->name, sizeof(dcdc->name), "EPE%d", id + 1);
+	dcdc->desc.name = dcdc->name;
+	dcdc->desc.id = id + WM831X_EPE_BASE; /* Offset in DCDC registers */
+	dcdc->desc.ops = &wm831x_epe_ops;
+	dcdc->desc.type = REGULATOR_VOLTAGE;
+	dcdc->desc.owner = THIS_MODULE;
+
+	dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev,
+					     pdata->epe[id], dcdc, NULL);
+	if (IS_ERR(dcdc->regulator)) {
+		ret = PTR_ERR(dcdc->regulator);
+		dev_err(wm831x->dev, "Failed to register EPE%d: %d\n",
+			id + 1, ret);
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, dcdc);
+
+	return 0;
+
+err:
+	kfree(dcdc);
+	return ret;
+}
+
+static __devexit int wm831x_epe_remove(struct platform_device *pdev)
+{
+	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	regulator_unregister(dcdc->regulator);
+	kfree(dcdc);
+
+	return 0;
+}
+
+static struct platform_driver wm831x_epe_driver = {
+	.probe = wm831x_epe_probe,
+	.remove = __devexit_p(wm831x_epe_remove),
+	.driver		= {
+		.name	= "wm831x-epe",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init wm831x_dcdc_init(void)
+{
+	int ret;
+	ret = platform_driver_register(&wm831x_buckv_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM831x BUCKV driver: %d\n", ret);
+
+	ret = platform_driver_register(&wm831x_buckp_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM831x BUCKP driver: %d\n", ret);
+
+	ret = platform_driver_register(&wm831x_boostp_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM831x BOOST driver: %d\n", ret);
+
+	ret = platform_driver_register(&wm831x_epe_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM831x EPE driver: %d\n", ret);
+
+	return 0;
+}
+subsys_initcall(wm831x_dcdc_init);
+
+static void __exit wm831x_dcdc_exit(void)
+{
+	platform_driver_unregister(&wm831x_epe_driver);
+	platform_driver_unregister(&wm831x_boostp_driver);
+	platform_driver_unregister(&wm831x_buckp_driver);
+	platform_driver_unregister(&wm831x_buckv_driver);
+}
+module_exit(wm831x_dcdc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown");
+MODULE_DESCRIPTION("WM831x DC-DC convertor driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm831x-buckv");
+MODULE_ALIAS("platform:wm831x-buckp");
+MODULE_ALIAS("platform:wm831x-epe");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/wm831x-isink.c b/ap/os/linux/linux-3.4.x/drivers/regulator/wm831x-isink.c
new file mode 100644
index 0000000..b414e09
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/wm831x-isink.c
@@ -0,0 +1,263 @@
+/*
+ * wm831x-isink.c  --  Current sink driver for the WM831x series
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/regulator.h>
+#include <linux/mfd/wm831x/pdata.h>
+
+#define WM831X_ISINK_MAX_NAME 7
+
+struct wm831x_isink {
+	char name[WM831X_ISINK_MAX_NAME];
+	struct regulator_desc desc;
+	int reg;
+	struct wm831x *wm831x;
+	struct regulator_dev *regulator;
+};
+
+static int wm831x_isink_enable(struct regulator_dev *rdev)
+{
+	struct wm831x_isink *isink = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = isink->wm831x;
+	int ret;
+
+	/* We have a two stage enable: first start the ISINK... */
+	ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_ENA,
+			      WM831X_CS1_ENA);
+	if (ret != 0)
+		return ret;
+
+	/* ...then enable drive */
+	ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_DRIVE,
+			      WM831X_CS1_DRIVE);
+	if (ret != 0)
+		wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_ENA, 0);
+
+	return ret;
+
+}
+
+static int wm831x_isink_disable(struct regulator_dev *rdev)
+{
+	struct wm831x_isink *isink = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = isink->wm831x;
+	int ret;
+
+	ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_DRIVE, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = wm831x_set_bits(wm831x, isink->reg, WM831X_CS1_ENA, 0);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+
+}
+
+static int wm831x_isink_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm831x_isink *isink = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = isink->wm831x;
+	int ret;
+
+	ret = wm831x_reg_read(wm831x, isink->reg);
+	if (ret < 0)
+		return ret;
+
+	if ((ret & (WM831X_CS1_ENA | WM831X_CS1_DRIVE)) ==
+	    (WM831X_CS1_ENA | WM831X_CS1_DRIVE))
+		return 1;
+	else
+		return 0;
+}
+
+static int wm831x_isink_set_current(struct regulator_dev *rdev,
+				    int min_uA, int max_uA)
+{
+	struct wm831x_isink *isink = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = isink->wm831x;
+	int ret, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm831x_isinkv_values); i++) {
+		int val = wm831x_isinkv_values[i];
+		if (min_uA <= val && val <= max_uA) {
+			ret = wm831x_set_bits(wm831x, isink->reg,
+					      WM831X_CS1_ISEL_MASK, i);
+			return ret;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int wm831x_isink_get_current(struct regulator_dev *rdev)
+{
+	struct wm831x_isink *isink = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = isink->wm831x;
+	int ret;
+
+	ret = wm831x_reg_read(wm831x, isink->reg);
+	if (ret < 0)
+		return ret;
+
+	ret &= WM831X_CS1_ISEL_MASK;
+	if (ret > WM831X_ISINK_MAX_ISEL)
+		ret = WM831X_ISINK_MAX_ISEL;
+
+	return wm831x_isinkv_values[ret];
+}
+
+static struct regulator_ops wm831x_isink_ops = {
+	.is_enabled = wm831x_isink_is_enabled,
+	.enable = wm831x_isink_enable,
+	.disable = wm831x_isink_disable,
+	.set_current_limit = wm831x_isink_set_current,
+	.get_current_limit = wm831x_isink_get_current,
+};
+
+static irqreturn_t wm831x_isink_irq(int irq, void *data)
+{
+	struct wm831x_isink *isink = data;
+
+	regulator_notifier_call_chain(isink->regulator,
+				      REGULATOR_EVENT_OVER_CURRENT,
+				      NULL);
+
+	return IRQ_HANDLED;
+}
+
+
+static __devinit int wm831x_isink_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	struct wm831x_isink *isink;
+	int id = pdev->id % ARRAY_SIZE(pdata->isink);
+	struct resource *res;
+	int ret, irq;
+
+	dev_dbg(&pdev->dev, "Probing ISINK%d\n", id + 1);
+
+	if (pdata == NULL || pdata->isink[id] == NULL)
+		return -ENODEV;
+
+	isink = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_isink),
+			     GFP_KERNEL);
+	if (isink == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	isink->wm831x = wm831x;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No I/O resource\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	isink->reg = res->start;
+
+	/* For current parts this is correct; probably need to revisit
+	 * in future.
+	 */
+	snprintf(isink->name, sizeof(isink->name), "ISINK%d", id + 1);
+	isink->desc.name = isink->name;
+	isink->desc.id = id;
+	isink->desc.ops = &wm831x_isink_ops;
+	isink->desc.type = REGULATOR_CURRENT;
+	isink->desc.owner = THIS_MODULE;
+
+	isink->regulator = regulator_register(&isink->desc, &pdev->dev,
+					     pdata->isink[id], isink, NULL);
+	if (IS_ERR(isink->regulator)) {
+		ret = PTR_ERR(isink->regulator);
+		dev_err(wm831x->dev, "Failed to register ISINK%d: %d\n",
+			id + 1, ret);
+		goto err;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	ret = request_threaded_irq(irq, NULL, wm831x_isink_irq,
+				   IRQF_TRIGGER_RISING, isink->name, isink);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request ISINK IRQ %d: %d\n",
+			irq, ret);
+		goto err_regulator;
+	}
+
+	platform_set_drvdata(pdev, isink);
+
+	return 0;
+
+err_regulator:
+	regulator_unregister(isink->regulator);
+err:
+	return ret;
+}
+
+static __devexit int wm831x_isink_remove(struct platform_device *pdev)
+{
+	struct wm831x_isink *isink = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	free_irq(platform_get_irq(pdev, 0), isink);
+
+	regulator_unregister(isink->regulator);
+
+	return 0;
+}
+
+static struct platform_driver wm831x_isink_driver = {
+	.probe = wm831x_isink_probe,
+	.remove = __devexit_p(wm831x_isink_remove),
+	.driver		= {
+		.name	= "wm831x-isink",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init wm831x_isink_init(void)
+{
+	int ret;
+	ret = platform_driver_register(&wm831x_isink_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM831x ISINK driver: %d\n", ret);
+
+	return ret;
+}
+subsys_initcall(wm831x_isink_init);
+
+static void __exit wm831x_isink_exit(void)
+{
+	platform_driver_unregister(&wm831x_isink_driver);
+}
+module_exit(wm831x_isink_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown");
+MODULE_DESCRIPTION("WM831x current sink driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm831x-isink");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/wm831x-ldo.c b/ap/os/linux/linux-3.4.x/drivers/regulator/wm831x-ldo.c
new file mode 100644
index 0000000..641e9f6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/wm831x-ldo.c
@@ -0,0 +1,883 @@
+/*
+ * wm831x-ldo.c  --  LDO driver for the WM831x series
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/regulator.h>
+#include <linux/mfd/wm831x/pdata.h>
+
+#define WM831X_LDO_MAX_NAME 6
+
+#define WM831X_LDO_CONTROL       0
+#define WM831X_LDO_ON_CONTROL    1
+#define WM831X_LDO_SLEEP_CONTROL 2
+
+#define WM831X_ALIVE_LDO_ON_CONTROL    0
+#define WM831X_ALIVE_LDO_SLEEP_CONTROL 1
+
+struct wm831x_ldo {
+	char name[WM831X_LDO_MAX_NAME];
+	struct regulator_desc desc;
+	int base;
+	struct wm831x *wm831x;
+	struct regulator_dev *regulator;
+};
+
+/*
+ * Shared
+ */
+
+static int wm831x_ldo_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int mask = 1 << rdev_get_id(rdev);
+	int reg;
+
+	reg = wm831x_reg_read(wm831x, WM831X_LDO_ENABLE);
+	if (reg < 0)
+		return reg;
+
+	if (reg & mask)
+		return 1;
+	else
+		return 0;
+}
+
+static int wm831x_ldo_enable(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int mask = 1 << rdev_get_id(rdev);
+
+	return wm831x_set_bits(wm831x, WM831X_LDO_ENABLE, mask, mask);
+}
+
+static int wm831x_ldo_disable(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int mask = 1 << rdev_get_id(rdev);
+
+	return wm831x_set_bits(wm831x, WM831X_LDO_ENABLE, mask, 0);
+}
+
+static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data)
+{
+	struct wm831x_ldo *ldo = data;
+
+	regulator_notifier_call_chain(ldo->regulator,
+				      REGULATOR_EVENT_UNDER_VOLTAGE,
+				      NULL);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * General purpose LDOs
+ */
+
+#define WM831X_GP_LDO_SELECTOR_LOW 0xe
+#define WM831X_GP_LDO_MAX_SELECTOR 0x1f
+
+static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev,
+				      unsigned int selector)
+{
+	/* 0.9-1.6V in 50mV steps */
+	if (selector <= WM831X_GP_LDO_SELECTOR_LOW)
+		return 900000 + (selector * 50000);
+	/* 1.7-3.3V in 50mV steps */
+	if (selector <= WM831X_GP_LDO_MAX_SELECTOR)
+		return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW)
+				  * 100000);
+	return -EINVAL;
+}
+
+static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg,
+					 int min_uV, int max_uV,
+					 unsigned *selector)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int vsel, ret;
+
+	if (min_uV < 900000)
+		vsel = 0;
+	else if (min_uV < 1700000)
+		vsel = ((min_uV - 900000) / 50000);
+	else
+		vsel = ((min_uV - 1700000) / 100000)
+			+ WM831X_GP_LDO_SELECTOR_LOW + 1;
+
+	ret = wm831x_gp_ldo_list_voltage(rdev, vsel);
+	if (ret < 0)
+		return ret;
+	if (ret < min_uV || ret > max_uV)
+		return -EINVAL;
+
+	*selector = vsel;
+
+	return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, vsel);
+}
+
+static int wm831x_gp_ldo_set_voltage(struct regulator_dev *rdev,
+				     int min_uV, int max_uV,
+				     unsigned *selector)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	int reg = ldo->base + WM831X_LDO_ON_CONTROL;
+
+	return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
+					     selector);
+}
+
+static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
+					     int uV)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
+	unsigned int selector;
+
+	return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+}
+
+static int wm831x_gp_ldo_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int reg = ldo->base + WM831X_LDO_ON_CONTROL;
+	int ret;
+
+	ret = wm831x_reg_read(wm831x, reg);
+	if (ret < 0)
+		return ret;
+
+	ret &= WM831X_LDO1_ON_VSEL_MASK;
+
+	return ret;
+}
+
+static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
+	int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
+	int ret;
+
+	ret = wm831x_reg_read(wm831x, on_reg);
+	if (ret < 0)
+		return ret;
+
+	if (!(ret & WM831X_LDO1_ON_MODE))
+		return REGULATOR_MODE_NORMAL;
+
+	ret = wm831x_reg_read(wm831x, ctrl_reg);
+	if (ret < 0)
+		return ret;
+
+	if (ret & WM831X_LDO1_LP_MODE)
+		return REGULATOR_MODE_STANDBY;
+	else
+		return REGULATOR_MODE_IDLE;
+}
+
+static int wm831x_gp_ldo_set_mode(struct regulator_dev *rdev,
+				  unsigned int mode)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
+	int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
+	int ret;
+
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		ret = wm831x_set_bits(wm831x, on_reg,
+				      WM831X_LDO1_ON_MODE, 0);
+		if (ret < 0)
+			return ret;
+		break;
+
+	case REGULATOR_MODE_IDLE:
+		ret = wm831x_set_bits(wm831x, ctrl_reg,
+				      WM831X_LDO1_LP_MODE, 0);
+		if (ret < 0)
+			return ret;
+
+		ret = wm831x_set_bits(wm831x, on_reg,
+				      WM831X_LDO1_ON_MODE,
+				      WM831X_LDO1_ON_MODE);
+		if (ret < 0)
+			return ret;
+		break;
+
+	case REGULATOR_MODE_STANDBY:
+		ret = wm831x_set_bits(wm831x, ctrl_reg,
+				      WM831X_LDO1_LP_MODE,
+				      WM831X_LDO1_LP_MODE);
+		if (ret < 0)
+			return ret;
+
+		ret = wm831x_set_bits(wm831x, on_reg,
+				      WM831X_LDO1_ON_MODE,
+				      WM831X_LDO1_ON_MODE);
+		if (ret < 0)
+			return ret;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm831x_gp_ldo_get_status(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int mask = 1 << rdev_get_id(rdev);
+	int ret;
+
+	/* Is the regulator on? */
+	ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
+	if (ret < 0)
+		return ret;
+	if (!(ret & mask))
+		return REGULATOR_STATUS_OFF;
+
+	/* Is it reporting under voltage? */
+	ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
+	if (ret & mask)
+		return REGULATOR_STATUS_ERROR;
+
+	ret = wm831x_gp_ldo_get_mode(rdev);
+	if (ret < 0)
+		return ret;
+	else
+		return regulator_mode_to_status(ret);
+}
+
+static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
+						   int input_uV,
+						   int output_uV, int load_uA)
+{
+	if (load_uA < 20000)
+		return REGULATOR_MODE_STANDBY;
+	if (load_uA < 50000)
+		return REGULATOR_MODE_IDLE;
+	return REGULATOR_MODE_NORMAL;
+}
+
+
+static struct regulator_ops wm831x_gp_ldo_ops = {
+	.list_voltage = wm831x_gp_ldo_list_voltage,
+	.get_voltage_sel = wm831x_gp_ldo_get_voltage_sel,
+	.set_voltage = wm831x_gp_ldo_set_voltage,
+	.set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
+	.get_mode = wm831x_gp_ldo_get_mode,
+	.set_mode = wm831x_gp_ldo_set_mode,
+	.get_status = wm831x_gp_ldo_get_status,
+	.get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
+
+	.is_enabled = wm831x_ldo_is_enabled,
+	.enable = wm831x_ldo_enable,
+	.disable = wm831x_ldo_disable,
+};
+
+static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	int id;
+	struct wm831x_ldo *ldo;
+	struct resource *res;
+	int ret, irq;
+
+	if (pdata && pdata->wm831x_num)
+		id = (pdata->wm831x_num * 10) + 1;
+	else
+		id = 0;
+	id = pdev->id - id;
+
+	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
+
+	if (pdata == NULL || pdata->ldo[id] == NULL)
+		return -ENODEV;
+
+	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
+	if (ldo == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	ldo->wm831x = wm831x;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No I/O resource\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	ldo->base = res->start;
+
+	snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
+	ldo->desc.name = ldo->name;
+	ldo->desc.id = id;
+	ldo->desc.type = REGULATOR_VOLTAGE;
+	ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1;
+	ldo->desc.ops = &wm831x_gp_ldo_ops;
+	ldo->desc.owner = THIS_MODULE;
+
+	ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
+					     pdata->ldo[id], ldo, NULL);
+	if (IS_ERR(ldo->regulator)) {
+		ret = PTR_ERR(ldo->regulator);
+		dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
+			id + 1, ret);
+		goto err;
+	}
+
+	irq = platform_get_irq_byname(pdev, "UV");
+	ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
+				   IRQF_TRIGGER_RISING, ldo->name,
+				   ldo);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
+			irq, ret);
+		goto err_regulator;
+	}
+
+	platform_set_drvdata(pdev, ldo);
+
+	return 0;
+
+err_regulator:
+	regulator_unregister(ldo->regulator);
+err:
+	return ret;
+}
+
+static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev)
+{
+	struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	free_irq(platform_get_irq_byname(pdev, "UV"), ldo);
+	regulator_unregister(ldo->regulator);
+
+	return 0;
+}
+
+static struct platform_driver wm831x_gp_ldo_driver = {
+	.probe = wm831x_gp_ldo_probe,
+	.remove = __devexit_p(wm831x_gp_ldo_remove),
+	.driver		= {
+		.name	= "wm831x-ldo",
+		.owner	= THIS_MODULE,
+	},
+};
+
+/*
+ * Analogue LDOs
+ */
+
+
+#define WM831X_ALDO_SELECTOR_LOW 0xc
+#define WM831X_ALDO_MAX_SELECTOR 0x1f
+
+static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
+				      unsigned int selector)
+{
+	/* 1-1.6V in 50mV steps */
+	if (selector <= WM831X_ALDO_SELECTOR_LOW)
+		return 1000000 + (selector * 50000);
+	/* 1.7-3.5V in 50mV steps */
+	if (selector <= WM831X_ALDO_MAX_SELECTOR)
+		return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW)
+				  * 100000);
+	return -EINVAL;
+}
+
+static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg,
+				       int min_uV, int max_uV,
+				       unsigned *selector)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int vsel, ret;
+
+	if (min_uV < 1000000)
+		vsel = 0;
+	else if (min_uV < 1700000)
+		vsel = ((min_uV - 1000000) / 50000);
+	else
+		vsel = ((min_uV - 1700000) / 100000)
+			+ WM831X_ALDO_SELECTOR_LOW + 1;
+
+	ret = wm831x_aldo_list_voltage(rdev, vsel);
+	if (ret < 0)
+		return ret;
+	if (ret < min_uV || ret > max_uV)
+		return -EINVAL;
+
+	*selector = vsel;
+
+	return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, vsel);
+}
+
+static int wm831x_aldo_set_voltage(struct regulator_dev *rdev,
+				   int min_uV, int max_uV, unsigned *selector)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	int reg = ldo->base + WM831X_LDO_ON_CONTROL;
+
+	return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV,
+					   selector);
+}
+
+static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
+					     int uV)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
+	unsigned int selector;
+
+	return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+}
+
+static int wm831x_aldo_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int reg = ldo->base + WM831X_LDO_ON_CONTROL;
+	int ret;
+
+	ret = wm831x_reg_read(wm831x, reg);
+	if (ret < 0)
+		return ret;
+
+	ret &= WM831X_LDO7_ON_VSEL_MASK;
+
+	return ret;
+}
+
+static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
+	int ret;
+
+	ret = wm831x_reg_read(wm831x, on_reg);
+	if (ret < 0)
+		return 0;
+
+	if (ret & WM831X_LDO7_ON_MODE)
+		return REGULATOR_MODE_IDLE;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int wm831x_aldo_set_mode(struct regulator_dev *rdev,
+				  unsigned int mode)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
+	int ret;
+
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE, 0);
+		if (ret < 0)
+			return ret;
+		break;
+
+	case REGULATOR_MODE_IDLE:
+		ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE,
+				      WM831X_LDO7_ON_MODE);
+		if (ret < 0)
+			return ret;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm831x_aldo_get_status(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int mask = 1 << rdev_get_id(rdev);
+	int ret;
+
+	/* Is the regulator on? */
+	ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
+	if (ret < 0)
+		return ret;
+	if (!(ret & mask))
+		return REGULATOR_STATUS_OFF;
+
+	/* Is it reporting under voltage? */
+	ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
+	if (ret & mask)
+		return REGULATOR_STATUS_ERROR;
+
+	ret = wm831x_aldo_get_mode(rdev);
+	if (ret < 0)
+		return ret;
+	else
+		return regulator_mode_to_status(ret);
+}
+
+static struct regulator_ops wm831x_aldo_ops = {
+	.list_voltage = wm831x_aldo_list_voltage,
+	.get_voltage_sel = wm831x_aldo_get_voltage_sel,
+	.set_voltage = wm831x_aldo_set_voltage,
+	.set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
+	.get_mode = wm831x_aldo_get_mode,
+	.set_mode = wm831x_aldo_set_mode,
+	.get_status = wm831x_aldo_get_status,
+
+	.is_enabled = wm831x_ldo_is_enabled,
+	.enable = wm831x_ldo_enable,
+	.disable = wm831x_ldo_disable,
+};
+
+static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	int id;
+	struct wm831x_ldo *ldo;
+	struct resource *res;
+	int ret, irq;
+
+	if (pdata && pdata->wm831x_num)
+		id = (pdata->wm831x_num * 10) + 1;
+	else
+		id = 0;
+	id = pdev->id - id;
+
+	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
+
+	if (pdata == NULL || pdata->ldo[id] == NULL)
+		return -ENODEV;
+
+	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
+	if (ldo == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	ldo->wm831x = wm831x;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No I/O resource\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	ldo->base = res->start;
+
+	snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
+	ldo->desc.name = ldo->name;
+	ldo->desc.id = id;
+	ldo->desc.type = REGULATOR_VOLTAGE;
+	ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1;
+	ldo->desc.ops = &wm831x_aldo_ops;
+	ldo->desc.owner = THIS_MODULE;
+
+	ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
+					     pdata->ldo[id], ldo, NULL);
+	if (IS_ERR(ldo->regulator)) {
+		ret = PTR_ERR(ldo->regulator);
+		dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
+			id + 1, ret);
+		goto err;
+	}
+
+	irq = platform_get_irq_byname(pdev, "UV");
+	ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
+				   IRQF_TRIGGER_RISING, ldo->name, ldo);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
+			irq, ret);
+		goto err_regulator;
+	}
+
+	platform_set_drvdata(pdev, ldo);
+
+	return 0;
+
+err_regulator:
+	regulator_unregister(ldo->regulator);
+err:
+	return ret;
+}
+
+static __devexit int wm831x_aldo_remove(struct platform_device *pdev)
+{
+	struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
+
+	free_irq(platform_get_irq_byname(pdev, "UV"), ldo);
+	regulator_unregister(ldo->regulator);
+
+	return 0;
+}
+
+static struct platform_driver wm831x_aldo_driver = {
+	.probe = wm831x_aldo_probe,
+	.remove = __devexit_p(wm831x_aldo_remove),
+	.driver		= {
+		.name	= "wm831x-aldo",
+		.owner	= THIS_MODULE,
+	},
+};
+
+/*
+ * Alive LDO
+ */
+
+#define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
+
+static int wm831x_alive_ldo_list_voltage(struct regulator_dev *rdev,
+				      unsigned int selector)
+{
+	/* 0.8-1.55V in 50mV steps */
+	if (selector <= WM831X_ALIVE_LDO_MAX_SELECTOR)
+		return 800000 + (selector * 50000);
+	return -EINVAL;
+}
+
+static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev,
+					    int reg,
+					    int min_uV, int max_uV,
+					    unsigned *selector)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int vsel, ret;
+
+	vsel = (min_uV - 800000) / 50000;
+
+	ret = wm831x_alive_ldo_list_voltage(rdev, vsel);
+	if (ret < 0)
+		return ret;
+	if (ret < min_uV || ret > max_uV)
+		return -EINVAL;
+
+	*selector = vsel;
+
+	return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, vsel);
+}
+
+static int wm831x_alive_ldo_set_voltage(struct regulator_dev *rdev,
+					int min_uV, int max_uV,
+					unsigned *selector)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
+
+	return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
+						selector);
+}
+
+static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
+					     int uV)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	int reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
+	unsigned selector;
+
+	return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+}
+
+static int wm831x_alive_ldo_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
+	int ret;
+
+	ret = wm831x_reg_read(wm831x, reg);
+	if (ret < 0)
+		return ret;
+
+	ret &= WM831X_LDO11_ON_VSEL_MASK;
+
+	return ret;
+}
+
+static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
+{
+	struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
+	struct wm831x *wm831x = ldo->wm831x;
+	int mask = 1 << rdev_get_id(rdev);
+	int ret;
+
+	/* Is the regulator on? */
+	ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
+	if (ret < 0)
+		return ret;
+	if (ret & mask)
+		return REGULATOR_STATUS_ON;
+	else
+		return REGULATOR_STATUS_OFF;
+}
+
+static struct regulator_ops wm831x_alive_ldo_ops = {
+	.list_voltage = wm831x_alive_ldo_list_voltage,
+	.get_voltage_sel = wm831x_alive_ldo_get_voltage_sel,
+	.set_voltage = wm831x_alive_ldo_set_voltage,
+	.set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
+	.get_status = wm831x_alive_ldo_get_status,
+
+	.is_enabled = wm831x_ldo_is_enabled,
+	.enable = wm831x_ldo_enable,
+	.disable = wm831x_ldo_disable,
+};
+
+static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev)
+{
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	int id;
+	struct wm831x_ldo *ldo;
+	struct resource *res;
+	int ret;
+
+	if (pdata && pdata->wm831x_num)
+		id = (pdata->wm831x_num * 10) + 1;
+	else
+		id = 0;
+	id = pdev->id - id;
+
+
+	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
+
+	if (pdata == NULL || pdata->ldo[id] == NULL)
+		return -ENODEV;
+
+	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
+	if (ldo == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	ldo->wm831x = wm831x;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "No I/O resource\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	ldo->base = res->start;
+
+	snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
+	ldo->desc.name = ldo->name;
+	ldo->desc.id = id;
+	ldo->desc.type = REGULATOR_VOLTAGE;
+	ldo->desc.n_voltages = WM831X_ALIVE_LDO_MAX_SELECTOR + 1;
+	ldo->desc.ops = &wm831x_alive_ldo_ops;
+	ldo->desc.owner = THIS_MODULE;
+
+	ldo->regulator = regulator_register(&ldo->desc, &pdev->dev,
+					     pdata->ldo[id], ldo, NULL);
+	if (IS_ERR(ldo->regulator)) {
+		ret = PTR_ERR(ldo->regulator);
+		dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
+			id + 1, ret);
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, ldo);
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static __devexit int wm831x_alive_ldo_remove(struct platform_device *pdev)
+{
+	struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
+
+	regulator_unregister(ldo->regulator);
+
+	return 0;
+}
+
+static struct platform_driver wm831x_alive_ldo_driver = {
+	.probe = wm831x_alive_ldo_probe,
+	.remove = __devexit_p(wm831x_alive_ldo_remove),
+	.driver		= {
+		.name	= "wm831x-alive-ldo",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init wm831x_ldo_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&wm831x_gp_ldo_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM831x GP LDO driver: %d\n", ret);
+
+	ret = platform_driver_register(&wm831x_aldo_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM831x ALDO driver: %d\n", ret);
+
+	ret = platform_driver_register(&wm831x_alive_ldo_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM831x alive LDO driver: %d\n",
+		       ret);
+
+	return 0;
+}
+subsys_initcall(wm831x_ldo_init);
+
+static void __exit wm831x_ldo_exit(void)
+{
+	platform_driver_unregister(&wm831x_alive_ldo_driver);
+	platform_driver_unregister(&wm831x_aldo_driver);
+	platform_driver_unregister(&wm831x_gp_ldo_driver);
+}
+module_exit(wm831x_ldo_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM831x LDO driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm831x-ldo");
+MODULE_ALIAS("platform:wm831x-aldo");
+MODULE_ALIAS("platform:wm831x-aliveldo");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/wm8350-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/wm8350-regulator.c
new file mode 100644
index 0000000..05ecfb8
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/wm8350-regulator.c
@@ -0,0 +1,1623 @@
+/*
+ * wm8350.c  --  Voltage and current regulation for the Wolfson WM8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *         linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/* Maximum value possible for VSEL */
+#define WM8350_DCDC_MAX_VSEL 0x66
+
+/* Microamps */
+static const int isink_cur[] = {
+	4,
+	5,
+	6,
+	7,
+	8,
+	10,
+	11,
+	14,
+	16,
+	19,
+	23,
+	27,
+	32,
+	39,
+	46,
+	54,
+	65,
+	77,
+	92,
+	109,
+	130,
+	154,
+	183,
+	218,
+	259,
+	308,
+	367,
+	436,
+	518,
+	616,
+	733,
+	872,
+	1037,
+	1233,
+	1466,
+	1744,
+	2073,
+	2466,
+	2933,
+	3487,
+	4147,
+	4932,
+	5865,
+	6975,
+	8294,
+	9864,
+	11730,
+	13949,
+	16589,
+	19728,
+	23460,
+	27899,
+	33178,
+	39455,
+	46920,
+	55798,
+	66355,
+	78910,
+	93840,
+	111596,
+	132710,
+	157820,
+	187681,
+	223191
+};
+
+static int get_isink_val(int min_uA, int max_uA, u16 *setting)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(isink_cur); i++) {
+		if (min_uA <= isink_cur[i] && max_uA >= isink_cur[i]) {
+			*setting = i;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static inline int wm8350_ldo_val_to_mvolts(unsigned int val)
+{
+	if (val < 16)
+		return (val * 50) + 900;
+	else
+		return ((val - 16) * 100) + 1800;
+
+}
+
+static inline unsigned int wm8350_ldo_mvolts_to_val(int mV)
+{
+	if (mV < 1800)
+		return (mV - 900) / 50;
+	else
+		return ((mV - 1800) / 100) + 16;
+}
+
+static inline int wm8350_dcdc_val_to_mvolts(unsigned int val)
+{
+	return (val * 25) + 850;
+}
+
+static inline unsigned int wm8350_dcdc_mvolts_to_val(int mV)
+{
+	return (mV - 850) / 25;
+}
+
+static int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA,
+	int max_uA)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+	u16 val, setting;
+	int ret;
+
+	ret = get_isink_val(min_uA, max_uA, &setting);
+	if (ret != 0)
+		return ret;
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+		    ~WM8350_CS1_ISEL_MASK;
+		wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_A,
+				 val | setting);
+		break;
+	case WM8350_ISINK_B:
+		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+		    ~WM8350_CS1_ISEL_MASK;
+		wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_B,
+				 val | setting);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_isink_get_current(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+	u16 val;
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+		    WM8350_CS1_ISEL_MASK;
+		break;
+	case WM8350_ISINK_B:
+		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+		    WM8350_CS1_ISEL_MASK;
+		break;
+	default:
+		return 0;
+	}
+
+	return isink_cur[val];
+}
+
+/* turn on ISINK followed by DCDC */
+static int wm8350_isink_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		switch (wm8350->pmic.isink_A_dcdc) {
+		case WM8350_DCDC_2:
+		case WM8350_DCDC_5:
+			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+					WM8350_CS1_ENA);
+			wm8350_set_bits(wm8350, WM8350_CSA_FLASH_CONTROL,
+					WM8350_CS1_DRIVE);
+			wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+					1 << (wm8350->pmic.isink_A_dcdc -
+					      WM8350_DCDC_1));
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case WM8350_ISINK_B:
+		switch (wm8350->pmic.isink_B_dcdc) {
+		case WM8350_DCDC_2:
+		case WM8350_DCDC_5:
+			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+					WM8350_CS2_ENA);
+			wm8350_set_bits(wm8350, WM8350_CSB_FLASH_CONTROL,
+					WM8350_CS2_DRIVE);
+			wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+					1 << (wm8350->pmic.isink_B_dcdc -
+					      WM8350_DCDC_1));
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wm8350_isink_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		switch (wm8350->pmic.isink_A_dcdc) {
+		case WM8350_DCDC_2:
+		case WM8350_DCDC_5:
+			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+					  1 << (wm8350->pmic.isink_A_dcdc -
+						WM8350_DCDC_1));
+			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+					  WM8350_CS1_ENA);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case WM8350_ISINK_B:
+		switch (wm8350->pmic.isink_B_dcdc) {
+		case WM8350_DCDC_2:
+		case WM8350_DCDC_5:
+			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+					  1 << (wm8350->pmic.isink_B_dcdc -
+						WM8350_DCDC_1));
+			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+					  WM8350_CS2_ENA);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wm8350_isink_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+		    0x8000;
+	case WM8350_ISINK_B:
+		return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+		    0x8000;
+	}
+	return -EINVAL;
+}
+
+static int wm8350_isink_enable_time(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int isink = rdev_get_id(rdev);
+	int reg;
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		reg = wm8350_reg_read(wm8350, WM8350_CSA_FLASH_CONTROL);
+		break;
+	case WM8350_ISINK_B:
+		reg = wm8350_reg_read(wm8350, WM8350_CSB_FLASH_CONTROL);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (reg & WM8350_CS1_FLASH_MODE) {
+		switch (reg & WM8350_CS1_ON_RAMP_MASK) {
+		case 0:
+			return 0;
+		case 1:
+			return 1950;
+		case 2:
+			return 3910;
+		case 3:
+			return 7800;
+		}
+	} else {
+		switch (reg & WM8350_CS1_ON_RAMP_MASK) {
+		case 0:
+			return 0;
+		case 1:
+			return 250000;
+		case 2:
+			return 500000;
+		case 3:
+			return 1000000;
+		}
+	}
+
+	return -EINVAL;
+}
+
+
+int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
+			   u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
+			   u16 drive)
+{
+	switch (isink) {
+	case WM8350_ISINK_A:
+		wm8350_reg_write(wm8350, WM8350_CSA_FLASH_CONTROL,
+				 (mode ? WM8350_CS1_FLASH_MODE : 0) |
+				 (trigger ? WM8350_CS1_TRIGSRC : 0) |
+				 duration | on_ramp | off_ramp | drive);
+		break;
+	case WM8350_ISINK_B:
+		wm8350_reg_write(wm8350, WM8350_CSB_FLASH_CONTROL,
+				 (mode ? WM8350_CS2_FLASH_MODE : 0) |
+				 (trigger ? WM8350_CS2_TRIGSRC : 0) |
+				 duration | on_ramp | off_ramp | drive);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
+
+static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
+				   int max_uV, unsigned *selector)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, dcdc = rdev_get_id(rdev), mV,
+		min_mV = min_uV / 1000, max_mV = max_uV / 1000;
+	u16 val;
+
+	if (min_mV < 850 || min_mV > 4025)
+		return -EINVAL;
+	if (max_mV < 850 || max_mV > 4025)
+		return -EINVAL;
+
+	/* step size is 25mV */
+	mV = (min_mV - 826) / 25;
+	if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
+		return -EINVAL;
+	BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		volt_reg = WM8350_DCDC1_CONTROL;
+		break;
+	case WM8350_DCDC_3:
+		volt_reg = WM8350_DCDC3_CONTROL;
+		break;
+	case WM8350_DCDC_4:
+		volt_reg = WM8350_DCDC4_CONTROL;
+		break;
+	case WM8350_DCDC_6:
+		volt_reg = WM8350_DCDC6_CONTROL;
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	*selector = mV;
+
+	/* all DCDCs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+	wm8350_reg_write(wm8350, volt_reg, val | mV);
+	return 0;
+}
+
+static int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, dcdc = rdev_get_id(rdev);
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		volt_reg = WM8350_DCDC1_CONTROL;
+		break;
+	case WM8350_DCDC_3:
+		volt_reg = WM8350_DCDC3_CONTROL;
+		break;
+	case WM8350_DCDC_4:
+		volt_reg = WM8350_DCDC4_CONTROL;
+		break;
+	case WM8350_DCDC_6:
+		volt_reg = WM8350_DCDC6_CONTROL;
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	/* all DCDCs have same mV bits */
+	return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
+}
+
+static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	if (selector > WM8350_DCDC_MAX_VSEL)
+		return -EINVAL;
+	return wm8350_dcdc_val_to_mvolts(selector) * 1000;
+}
+
+static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);
+
+	if (mV && (mV < 850 || mV > 4025)) {
+		dev_err(wm8350->dev,
+			"DCDC%d suspend voltage %d mV out of range\n",
+			dcdc, mV);
+		return -EINVAL;
+	}
+	if (mV == 0)
+		mV = 850;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		volt_reg = WM8350_DCDC1_LOW_POWER;
+		break;
+	case WM8350_DCDC_3:
+		volt_reg = WM8350_DCDC3_LOW_POWER;
+		break;
+	case WM8350_DCDC_4:
+		volt_reg = WM8350_DCDC4_LOW_POWER;
+		break;
+	case WM8350_DCDC_6:
+		volt_reg = WM8350_DCDC6_LOW_POWER;
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	/* all DCDCs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+	wm8350_reg_write(wm8350, volt_reg,
+			 val | wm8350_dcdc_mvolts_to_val(mV));
+	return 0;
+}
+
+static int wm8350_dcdc_set_suspend_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER)
+			& ~WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+			val | wm8350->pmic.dcdc1_hib_mode);
+		break;
+	case WM8350_DCDC_3:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER)
+			& ~WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+			val | wm8350->pmic.dcdc3_hib_mode);
+		break;
+	case WM8350_DCDC_4:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER)
+			& ~WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+			val | wm8350->pmic.dcdc4_hib_mode);
+		break;
+	case WM8350_DCDC_6:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER)
+			& ~WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+			val | wm8350->pmic.dcdc6_hib_mode);
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_dcdc_set_suspend_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+				 val | WM8350_DCDC_HIB_MODE_DIS);
+		break;
+	case WM8350_DCDC_3:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+				 val | WM8350_DCDC_HIB_MODE_DIS);
+		break;
+	case WM8350_DCDC_4:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+				 val | WM8350_DCDC_HIB_MODE_DIS);
+		break;
+	case WM8350_DCDC_6:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+				 val | WM8350_DCDC_HIB_MODE_DIS);
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	switch (dcdc) {
+	case WM8350_DCDC_2:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+		    & ~WM8350_DC2_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+		    (WM8350_DC2_HIB_MODE_ACTIVE << WM8350_DC2_HIB_MODE_SHIFT));
+		break;
+	case WM8350_DCDC_5:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+		    & ~WM8350_DC5_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+		    (WM8350_DC5_HIB_MODE_ACTIVE << WM8350_DC5_HIB_MODE_SHIFT));
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	switch (dcdc) {
+	case WM8350_DCDC_2:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+		    & ~WM8350_DC2_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+		    (WM8350_DC2_HIB_MODE_DISABLE << WM8350_DC2_HIB_MODE_SHIFT));
+		break;
+	case WM8350_DCDC_5:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+		    & ~WM8350_DC5_HIB_MODE_MASK;
+		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+		    (WM8350_DC5_HIB_MODE_DISABLE << WM8350_DC5_HIB_MODE_SHIFT));
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
+	unsigned int mode)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 *hib_mode;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		hib_mode = &wm8350->pmic.dcdc1_hib_mode;
+		break;
+	case WM8350_DCDC_3:
+		hib_mode = &wm8350->pmic.dcdc3_hib_mode;
+		break;
+	case WM8350_DCDC_4:
+		hib_mode = &wm8350->pmic.dcdc4_hib_mode;
+		break;
+	case WM8350_DCDC_6:
+		hib_mode = &wm8350->pmic.dcdc6_hib_mode;
+		break;
+	case WM8350_DCDC_2:
+	case WM8350_DCDC_5:
+	default:
+		return -EINVAL;
+	}
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		*hib_mode = WM8350_DCDC_HIB_MODE_IMAGE;
+		break;
+	case REGULATOR_MODE_IDLE:
+		*hib_mode = WM8350_DCDC_HIB_MODE_STANDBY;
+		break;
+	case REGULATOR_MODE_STANDBY:
+		*hib_mode = WM8350_DCDC_HIB_MODE_LDO_IM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);
+
+	if (mV < 900 || mV > 3300) {
+		dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
+			ldo, mV);
+		return -EINVAL;
+	}
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_LOW_POWER;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_LOW_POWER;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_LOW_POWER;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_LOW_POWER;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* all LDOs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+	wm8350_reg_write(wm8350, volt_reg,
+			 val | wm8350_ldo_mvolts_to_val(mV));
+	return 0;
+}
+
+static int wm8350_ldo_set_suspend_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, ldo = rdev_get_id(rdev);
+	u16 val;
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_LOW_POWER;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_LOW_POWER;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_LOW_POWER;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_LOW_POWER;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* all LDOs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+	wm8350_reg_write(wm8350, volt_reg, val);
+	return 0;
+}
+
+static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, ldo = rdev_get_id(rdev);
+	u16 val;
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_LOW_POWER;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_LOW_POWER;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_LOW_POWER;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_LOW_POWER;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* all LDOs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+	wm8350_reg_write(wm8350, volt_reg, val | WM8350_LDO1_HIB_MODE_DIS);
+	return 0;
+}
+
+static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
+				  int max_uV, unsigned *selector)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
+		max_mV = max_uV / 1000;
+	u16 val;
+
+	if (min_mV < 900 || min_mV > 3300)
+		return -EINVAL;
+	if (max_mV < 900 || max_mV > 3300)
+		return -EINVAL;
+
+	if (min_mV < 1800) {
+		/* step size is 50mV < 1800mV */
+		mV = (min_mV - 851) / 50;
+		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+			return -EINVAL;
+		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+	} else {
+		/* step size is 100mV > 1800mV */
+		mV = ((min_mV - 1701) / 100) + 16;
+		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+			return -EINVAL;
+		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+	}
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_CONTROL;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_CONTROL;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_CONTROL;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_CONTROL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*selector = mV;
+
+	/* all LDOs have same mV bits */
+	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+	wm8350_reg_write(wm8350, volt_reg, val | mV);
+	return 0;
+}
+
+static int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int volt_reg, ldo = rdev_get_id(rdev);
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		volt_reg = WM8350_LDO1_CONTROL;
+		break;
+	case WM8350_LDO_2:
+		volt_reg = WM8350_LDO2_CONTROL;
+		break;
+	case WM8350_LDO_3:
+		volt_reg = WM8350_LDO3_CONTROL;
+		break;
+	case WM8350_LDO_4:
+		volt_reg = WM8350_LDO4_CONTROL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* all LDOs have same mV bits */
+	return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
+}
+
+static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	if (selector > WM8350_LDO1_VSEL_MASK)
+		return -EINVAL;
+	return wm8350_ldo_val_to_mvolts(selector) * 1000;
+}
+
+int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
+			 u16 stop, u16 fault)
+{
+	int slot_reg;
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+		__func__, dcdc, start, stop);
+
+	/* slot valid ? */
+	if (start > 15 || stop > 15)
+		return -EINVAL;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		slot_reg = WM8350_DCDC1_TIMEOUTS;
+		break;
+	case WM8350_DCDC_2:
+		slot_reg = WM8350_DCDC2_TIMEOUTS;
+		break;
+	case WM8350_DCDC_3:
+		slot_reg = WM8350_DCDC3_TIMEOUTS;
+		break;
+	case WM8350_DCDC_4:
+		slot_reg = WM8350_DCDC4_TIMEOUTS;
+		break;
+	case WM8350_DCDC_5:
+		slot_reg = WM8350_DCDC5_TIMEOUTS;
+		break;
+	case WM8350_DCDC_6:
+		slot_reg = WM8350_DCDC6_TIMEOUTS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = wm8350_reg_read(wm8350, slot_reg) &
+	    ~(WM8350_DC1_ENSLOT_MASK | WM8350_DC1_SDSLOT_MASK |
+	      WM8350_DC1_ERRACT_MASK);
+	wm8350_reg_write(wm8350, slot_reg,
+			 val | (start << WM8350_DC1_ENSLOT_SHIFT) |
+			 (stop << WM8350_DC1_SDSLOT_SHIFT) |
+			 (fault << WM8350_DC1_ERRACT_SHIFT));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc_set_slot);
+
+int wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop)
+{
+	int slot_reg;
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+		__func__, ldo, start, stop);
+
+	/* slot valid ? */
+	if (start > 15 || stop > 15)
+		return -EINVAL;
+
+	switch (ldo) {
+	case WM8350_LDO_1:
+		slot_reg = WM8350_LDO1_TIMEOUTS;
+		break;
+	case WM8350_LDO_2:
+		slot_reg = WM8350_LDO2_TIMEOUTS;
+		break;
+	case WM8350_LDO_3:
+		slot_reg = WM8350_LDO3_TIMEOUTS;
+		break;
+	case WM8350_LDO_4:
+		slot_reg = WM8350_LDO4_TIMEOUTS;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = wm8350_reg_read(wm8350, slot_reg) & ~WM8350_LDO1_SDSLOT_MASK;
+	wm8350_reg_write(wm8350, slot_reg, val | ((start << 10) | (stop << 6)));
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_ldo_set_slot);
+
+int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
+			   u16 ilim, u16 ramp, u16 feedback)
+{
+	u16 val;
+
+	dev_dbg(wm8350->dev, "%s %d mode: %s %s\n", __func__, dcdc,
+		mode ? "normal" : "boost", ilim ? "low" : "normal");
+
+	switch (dcdc) {
+	case WM8350_DCDC_2:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+		    & ~(WM8350_DC2_MODE_MASK | WM8350_DC2_ILIM_MASK |
+			WM8350_DC2_RMP_MASK | WM8350_DC2_FBSRC_MASK);
+		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+				 (mode << WM8350_DC2_MODE_SHIFT) |
+				 (ilim << WM8350_DC2_ILIM_SHIFT) |
+				 (ramp << WM8350_DC2_RMP_SHIFT) |
+				 (feedback << WM8350_DC2_FBSRC_SHIFT));
+		break;
+	case WM8350_DCDC_5:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+		    & ~(WM8350_DC5_MODE_MASK | WM8350_DC5_ILIM_MASK |
+			WM8350_DC5_RMP_MASK | WM8350_DC5_FBSRC_MASK);
+		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+				 (mode << WM8350_DC5_MODE_SHIFT) |
+				 (ilim << WM8350_DC5_ILIM_SHIFT) |
+				 (ramp << WM8350_DC5_RMP_SHIFT) |
+				 (feedback << WM8350_DC5_FBSRC_SHIFT));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
+
+static int wm8350_dcdc_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 shift;
+
+	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+		return -EINVAL;
+
+	shift = dcdc - WM8350_DCDC_1;
+	wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+	return 0;
+}
+
+static int wm8350_dcdc_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 shift;
+
+	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+		return -EINVAL;
+
+	shift = dcdc - WM8350_DCDC_1;
+	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+
+	return 0;
+}
+
+static int wm8350_ldo_enable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int ldo = rdev_get_id(rdev);
+	u16 shift;
+
+	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+		return -EINVAL;
+
+	shift = (ldo - WM8350_LDO_1) + 8;
+	wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+	return 0;
+}
+
+static int wm8350_ldo_disable(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int ldo = rdev_get_id(rdev);
+	u16 shift;
+
+	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+		return -EINVAL;
+
+	shift = (ldo - WM8350_LDO_1) + 8;
+	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+	return 0;
+}
+
+static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
+{
+	int reg = 0, ret;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		reg = WM8350_DCDC1_FORCE_PWM;
+		break;
+	case WM8350_DCDC_3:
+		reg = WM8350_DCDC3_FORCE_PWM;
+		break;
+	case WM8350_DCDC_4:
+		reg = WM8350_DCDC4_FORCE_PWM;
+		break;
+	case WM8350_DCDC_6:
+		reg = WM8350_DCDC6_FORCE_PWM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (enable)
+		ret = wm8350_set_bits(wm8350, reg,
+			WM8350_DCDC1_FORCE_PWM_ENA);
+	else
+		ret = wm8350_clear_bits(wm8350, reg,
+			WM8350_DCDC1_FORCE_PWM_ENA);
+	return ret;
+}
+
+static int wm8350_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 val;
+
+	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+		return -EINVAL;
+
+	if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+		return -EINVAL;
+
+	val = 1 << (dcdc - WM8350_DCDC_1);
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		/* force continuous mode */
+		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+		force_continuous_enable(wm8350, dcdc, 1);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		/* active / pulse skipping */
+		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+		force_continuous_enable(wm8350, dcdc, 0);
+		break;
+	case REGULATOR_MODE_IDLE:
+		/* standby mode */
+		force_continuous_enable(wm8350, dcdc, 0);
+		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+		wm8350_clear_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+		break;
+	case REGULATOR_MODE_STANDBY:
+		/* LDO mode */
+		force_continuous_enable(wm8350, dcdc, 0);
+		wm8350_set_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+		break;
+	}
+
+	return 0;
+}
+
+static unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev);
+	u16 mask, sleep, active, force;
+	int mode = REGULATOR_MODE_NORMAL;
+	int reg;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+		reg = WM8350_DCDC1_FORCE_PWM;
+		break;
+	case WM8350_DCDC_3:
+		reg = WM8350_DCDC3_FORCE_PWM;
+		break;
+	case WM8350_DCDC_4:
+		reg = WM8350_DCDC4_FORCE_PWM;
+		break;
+	case WM8350_DCDC_6:
+		reg = WM8350_DCDC6_FORCE_PWM;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask = 1 << (dcdc - WM8350_DCDC_1);
+	active = wm8350_reg_read(wm8350, WM8350_DCDC_ACTIVE_OPTIONS) & mask;
+	force = wm8350_reg_read(wm8350, reg) & WM8350_DCDC1_FORCE_PWM_ENA;
+	sleep = wm8350_reg_read(wm8350, WM8350_DCDC_SLEEP_OPTIONS) & mask;
+
+	dev_dbg(wm8350->dev, "mask %x active %x sleep %x force %x",
+		mask, active, sleep, force);
+
+	if (active && !sleep) {
+		if (force)
+			mode = REGULATOR_MODE_FAST;
+		else
+			mode = REGULATOR_MODE_NORMAL;
+	} else if (!active && !sleep)
+		mode = REGULATOR_MODE_IDLE;
+	else if (sleep)
+		mode = REGULATOR_MODE_STANDBY;
+
+	return mode;
+}
+
+static unsigned int wm8350_ldo_get_mode(struct regulator_dev *rdev)
+{
+	return REGULATOR_MODE_NORMAL;
+}
+
+struct wm8350_dcdc_efficiency {
+	int uA_load_min;
+	int uA_load_max;
+	unsigned int mode;
+};
+
+static const struct wm8350_dcdc_efficiency dcdc1_6_efficiency[] = {
+	{0, 10000, REGULATOR_MODE_STANDBY},       /* 0 - 10mA - LDO */
+	{10000, 100000, REGULATOR_MODE_IDLE},     /* 10mA - 100mA - Standby */
+	{100000, 1000000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+	{-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static const struct wm8350_dcdc_efficiency dcdc3_4_efficiency[] = {
+	{0, 10000, REGULATOR_MODE_STANDBY},      /* 0 - 10mA - LDO */
+	{10000, 100000, REGULATOR_MODE_IDLE},    /* 10mA - 100mA - Standby */
+	{100000, 800000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+	{-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static unsigned int get_mode(int uA, const struct wm8350_dcdc_efficiency *eff)
+{
+	int i = 0;
+
+	while (eff[i].uA_load_min != -1) {
+		if (uA >= eff[i].uA_load_min && uA <= eff[i].uA_load_max)
+			return eff[i].mode;
+	}
+	return REGULATOR_MODE_NORMAL;
+}
+
+/* Query the regulator for it's most efficient mode @ uV,uA
+ * WM8350 regulator efficiency is pretty similar over
+ * different input and output uV.
+ */
+static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
+						 int input_uV, int output_uV,
+						 int output_uA)
+{
+	int dcdc = rdev_get_id(rdev), mode;
+
+	switch (dcdc) {
+	case WM8350_DCDC_1:
+	case WM8350_DCDC_6:
+		mode = get_mode(output_uA, dcdc1_6_efficiency);
+		break;
+	case WM8350_DCDC_3:
+	case WM8350_DCDC_4:
+		mode = get_mode(output_uA, dcdc3_4_efficiency);
+		break;
+	default:
+		mode = REGULATOR_MODE_NORMAL;
+		break;
+	}
+	return mode;
+}
+
+static int wm8350_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int dcdc = rdev_get_id(rdev), shift;
+
+	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+		return -EINVAL;
+
+	shift = dcdc - WM8350_DCDC_1;
+	return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+	    & (1 << shift);
+}
+
+static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+	int ldo = rdev_get_id(rdev), shift;
+
+	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+		return -EINVAL;
+
+	shift = (ldo - WM8350_LDO_1) + 8;
+	return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+	    & (1 << shift);
+}
+
+static struct regulator_ops wm8350_dcdc_ops = {
+	.set_voltage = wm8350_dcdc_set_voltage,
+	.get_voltage_sel = wm8350_dcdc_get_voltage_sel,
+	.list_voltage = wm8350_dcdc_list_voltage,
+	.enable = wm8350_dcdc_enable,
+	.disable = wm8350_dcdc_disable,
+	.get_mode = wm8350_dcdc_get_mode,
+	.set_mode = wm8350_dcdc_set_mode,
+	.get_optimum_mode = wm8350_dcdc_get_optimum_mode,
+	.is_enabled = wm8350_dcdc_is_enabled,
+	.set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
+	.set_suspend_enable = wm8350_dcdc_set_suspend_enable,
+	.set_suspend_disable = wm8350_dcdc_set_suspend_disable,
+	.set_suspend_mode = wm8350_dcdc_set_suspend_mode,
+};
+
+static struct regulator_ops wm8350_dcdc2_5_ops = {
+	.enable = wm8350_dcdc_enable,
+	.disable = wm8350_dcdc_disable,
+	.is_enabled = wm8350_dcdc_is_enabled,
+	.set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
+	.set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_ldo_ops = {
+	.set_voltage = wm8350_ldo_set_voltage,
+	.get_voltage_sel = wm8350_ldo_get_voltage_sel,
+	.list_voltage = wm8350_ldo_list_voltage,
+	.enable = wm8350_ldo_enable,
+	.disable = wm8350_ldo_disable,
+	.is_enabled = wm8350_ldo_is_enabled,
+	.get_mode = wm8350_ldo_get_mode,
+	.set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
+	.set_suspend_enable = wm8350_ldo_set_suspend_enable,
+	.set_suspend_disable = wm8350_ldo_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_isink_ops = {
+	.set_current_limit = wm8350_isink_set_current,
+	.get_current_limit = wm8350_isink_get_current,
+	.enable = wm8350_isink_enable,
+	.disable = wm8350_isink_disable,
+	.is_enabled = wm8350_isink_is_enabled,
+	.enable_time = wm8350_isink_enable_time,
+};
+
+static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
+	{
+		.name = "DCDC1",
+		.id = WM8350_DCDC_1,
+		.ops = &wm8350_dcdc_ops,
+		.irq = WM8350_IRQ_UV_DC1,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC2",
+		.id = WM8350_DCDC_2,
+		.ops = &wm8350_dcdc2_5_ops,
+		.irq = WM8350_IRQ_UV_DC2,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC3",
+		.id = WM8350_DCDC_3,
+		.ops = &wm8350_dcdc_ops,
+		.irq = WM8350_IRQ_UV_DC3,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC4",
+		.id = WM8350_DCDC_4,
+		.ops = &wm8350_dcdc_ops,
+		.irq = WM8350_IRQ_UV_DC4,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC5",
+		.id = WM8350_DCDC_5,
+		.ops = &wm8350_dcdc2_5_ops,
+		.irq = WM8350_IRQ_UV_DC5,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	 },
+	{
+		.name = "DCDC6",
+		.id = WM8350_DCDC_6,
+		.ops = &wm8350_dcdc_ops,
+		.irq = WM8350_IRQ_UV_DC6,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO1",
+		.id = WM8350_LDO_1,
+		.ops = &wm8350_ldo_ops,
+		.irq = WM8350_IRQ_UV_LDO1,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8350_LDO1_VSEL_MASK + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO2",
+		.id = WM8350_LDO_2,
+		.ops = &wm8350_ldo_ops,
+		.irq = WM8350_IRQ_UV_LDO2,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8350_LDO2_VSEL_MASK + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO3",
+		.id = WM8350_LDO_3,
+		.ops = &wm8350_ldo_ops,
+		.irq = WM8350_IRQ_UV_LDO3,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8350_LDO3_VSEL_MASK + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO4",
+		.id = WM8350_LDO_4,
+		.ops = &wm8350_ldo_ops,
+		.irq = WM8350_IRQ_UV_LDO4,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8350_LDO4_VSEL_MASK + 1,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "ISINKA",
+		.id = WM8350_ISINK_A,
+		.ops = &wm8350_isink_ops,
+		.irq = WM8350_IRQ_CS1,
+		.type = REGULATOR_CURRENT,
+		.owner = THIS_MODULE,
+	 },
+	{
+		.name = "ISINKB",
+		.id = WM8350_ISINK_B,
+		.ops = &wm8350_isink_ops,
+		.irq = WM8350_IRQ_CS2,
+		.type = REGULATOR_CURRENT,
+		.owner = THIS_MODULE,
+	 },
+};
+
+static irqreturn_t pmic_uv_handler(int irq, void *data)
+{
+	struct regulator_dev *rdev = (struct regulator_dev *)data;
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+
+	mutex_lock(&rdev->mutex);
+	if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
+		regulator_notifier_call_chain(rdev,
+					      REGULATOR_EVENT_REGULATION_OUT,
+					      wm8350);
+	else
+		regulator_notifier_call_chain(rdev,
+					      REGULATOR_EVENT_UNDER_VOLTAGE,
+					      wm8350);
+	mutex_unlock(&rdev->mutex);
+
+	return IRQ_HANDLED;
+}
+
+static int wm8350_regulator_probe(struct platform_device *pdev)
+{
+	struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
+	struct regulator_dev *rdev;
+	int ret;
+	u16 val;
+
+	if (pdev->id < WM8350_DCDC_1 || pdev->id > WM8350_ISINK_B)
+		return -ENODEV;
+
+	/* do any regulatior specific init */
+	switch (pdev->id) {
+	case WM8350_DCDC_1:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		break;
+	case WM8350_DCDC_3:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		break;
+	case WM8350_DCDC_4:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		break;
+	case WM8350_DCDC_6:
+		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+		break;
+	}
+
+	/* register regulator */
+	rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
+				  pdev->dev.platform_data,
+				  dev_get_drvdata(&pdev->dev), NULL);
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "failed to register %s\n",
+			wm8350_reg[pdev->id].name);
+		return PTR_ERR(rdev);
+	}
+
+	/* register regulator IRQ */
+	ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,
+				  pmic_uv_handler, 0, "UV", rdev);
+	if (ret < 0) {
+		regulator_unregister(rdev);
+		dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",
+			wm8350_reg[pdev->id].name);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int wm8350_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+
+	wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev);
+
+	regulator_unregister(rdev);
+
+	return 0;
+}
+
+int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
+			      struct regulator_init_data *initdata)
+{
+	struct platform_device *pdev;
+	int ret;
+	if (reg < 0 || reg >= NUM_WM8350_REGULATORS)
+		return -EINVAL;
+
+	if (wm8350->pmic.pdev[reg])
+		return -EBUSY;
+
+	if (reg >= WM8350_DCDC_1 && reg <= WM8350_DCDC_6 &&
+	    reg > wm8350->pmic.max_dcdc)
+		return -ENODEV;
+	if (reg >= WM8350_ISINK_A && reg <= WM8350_ISINK_B &&
+	    reg > wm8350->pmic.max_isink)
+		return -ENODEV;
+
+	pdev = platform_device_alloc("wm8350-regulator", reg);
+	if (!pdev)
+		return -ENOMEM;
+
+	wm8350->pmic.pdev[reg] = pdev;
+
+	initdata->driver_data = wm8350;
+
+	pdev->dev.platform_data = initdata;
+	pdev->dev.parent = wm8350->dev;
+	platform_set_drvdata(pdev, wm8350);
+
+	ret = platform_device_add(pdev);
+
+	if (ret != 0) {
+		dev_err(wm8350->dev, "Failed to register regulator %d: %d\n",
+			reg, ret);
+		platform_device_put(pdev);
+		wm8350->pmic.pdev[reg] = NULL;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_regulator);
+
+/**
+ * wm8350_register_led - Register a WM8350 LED output
+ *
+ * @param wm8350 The WM8350 device to configure.
+ * @param lednum LED device index to create.
+ * @param dcdc The DCDC to use for the LED.
+ * @param isink The ISINK to use for the LED.
+ * @param pdata Configuration for the LED.
+ *
+ * The WM8350 supports the use of an ISINK together with a DCDC to
+ * provide a power-efficient LED driver.  This function registers the
+ * regulators and instantiates the platform device for a LED.  The
+ * operating modes for the LED regulators must be configured using
+ * wm8350_isink_set_flash(), wm8350_dcdc25_set_mode() and
+ * wm8350_dcdc_set_slot() prior to calling this function.
+ */
+int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink,
+			struct wm8350_led_platform_data *pdata)
+{
+	struct wm8350_led *led;
+	struct platform_device *pdev;
+	int ret;
+
+	if (lednum >= ARRAY_SIZE(wm8350->pmic.led) || lednum < 0) {
+		dev_err(wm8350->dev, "Invalid LED index %d\n", lednum);
+		return -ENODEV;
+	}
+
+	led = &wm8350->pmic.led[lednum];
+
+	if (led->pdev) {
+		dev_err(wm8350->dev, "LED %d already allocated\n", lednum);
+		return -EINVAL;
+	}
+
+	pdev = platform_device_alloc("wm8350-led", lednum);
+	if (pdev == NULL) {
+		dev_err(wm8350->dev, "Failed to allocate LED %d\n", lednum);
+		return -ENOMEM;
+	}
+
+	led->isink_consumer.dev_name = dev_name(&pdev->dev);
+	led->isink_consumer.supply = "led_isink";
+	led->isink_init.num_consumer_supplies = 1;
+	led->isink_init.consumer_supplies = &led->isink_consumer;
+	led->isink_init.constraints.min_uA = 0;
+	led->isink_init.constraints.max_uA = pdata->max_uA;
+	led->isink_init.constraints.valid_ops_mask
+		= REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS;
+	led->isink_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
+	ret = wm8350_register_regulator(wm8350, isink, &led->isink_init);
+	if (ret != 0) {
+		platform_device_put(pdev);
+		return ret;
+	}
+
+	led->dcdc_consumer.dev_name = dev_name(&pdev->dev);
+	led->dcdc_consumer.supply = "led_vcc";
+	led->dcdc_init.num_consumer_supplies = 1;
+	led->dcdc_init.consumer_supplies = &led->dcdc_consumer;
+	led->dcdc_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
+	led->dcdc_init.constraints.valid_ops_mask =  REGULATOR_CHANGE_STATUS;
+	ret = wm8350_register_regulator(wm8350, dcdc, &led->dcdc_init);
+	if (ret != 0) {
+		platform_device_put(pdev);
+		return ret;
+	}
+
+	switch (isink) {
+	case WM8350_ISINK_A:
+		wm8350->pmic.isink_A_dcdc = dcdc;
+		break;
+	case WM8350_ISINK_B:
+		wm8350->pmic.isink_B_dcdc = dcdc;
+		break;
+	}
+
+	pdev->dev.platform_data = pdata;
+	pdev->dev.parent = wm8350->dev;
+	ret = platform_device_add(pdev);
+	if (ret != 0) {
+		dev_err(wm8350->dev, "Failed to register LED %d: %d\n",
+			lednum, ret);
+		platform_device_put(pdev);
+		return ret;
+	}
+
+	led->pdev = pdev;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_led);
+
+static struct platform_driver wm8350_regulator_driver = {
+	.probe = wm8350_regulator_probe,
+	.remove = wm8350_regulator_remove,
+	.driver		= {
+		.name	= "wm8350-regulator",
+	},
+};
+
+static int __init wm8350_regulator_init(void)
+{
+	return platform_driver_register(&wm8350_regulator_driver);
+}
+subsys_initcall(wm8350_regulator_init);
+
+static void __exit wm8350_regulator_exit(void)
+{
+	platform_driver_unregister(&wm8350_regulator_driver);
+}
+module_exit(wm8350_regulator_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("WM8350 voltage and current regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8350-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/wm8400-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/wm8400-regulator.c
new file mode 100644
index 0000000..8477153
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/wm8400-regulator.c
@@ -0,0 +1,402 @@
+/*
+ * Regulator support for WM8400
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/wm8400-private.h>
+
+static int wm8400_ldo_is_enabled(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+
+	val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+	return (val & WM8400_LDO1_ENA) != 0;
+}
+
+static int wm8400_ldo_enable(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+	return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+			       WM8400_LDO1_ENA, WM8400_LDO1_ENA);
+}
+
+static int wm8400_ldo_disable(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+	return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+			       WM8400_LDO1_ENA, 0);
+}
+
+static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
+				   unsigned selector)
+{
+	if (selector > WM8400_LDO1_VSEL_MASK)
+		return -EINVAL;
+
+	if (selector < 15)
+		return 900000 + (selector * 50000);
+	else
+		return 1600000 + ((selector - 14) * 100000);
+}
+
+static int wm8400_ldo_get_voltage_sel(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+
+	val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+	val &= WM8400_LDO1_VSEL_MASK;
+
+	return val;
+}
+
+static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
+				  int min_uV, int max_uV, unsigned *selector)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+
+	if (min_uV < 900000 || min_uV > 3300000)
+		return -EINVAL;
+
+	if (min_uV < 1700000) {
+		/* Steps of 50mV from 900mV;  */
+		val = DIV_ROUND_UP(min_uV - 900000, 50000);
+
+		if ((val * 50000) + 900000 > max_uV)
+			return -EINVAL;
+		BUG_ON((val * 50000) + 900000 < min_uV);
+	} else {
+		/* Steps of 100mV from 1700mV */
+		val = DIV_ROUND_UP(min_uV - 1700000, 100000);
+
+		if ((val * 100000) + 1700000 > max_uV)
+			return -EINVAL;
+		BUG_ON((val * 100000) + 1700000 < min_uV);
+
+		val += 0xf;
+	}
+
+	*selector = val;
+
+	return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+			       WM8400_LDO1_VSEL_MASK, val);
+}
+
+static struct regulator_ops wm8400_ldo_ops = {
+	.is_enabled = wm8400_ldo_is_enabled,
+	.enable = wm8400_ldo_enable,
+	.disable = wm8400_ldo_disable,
+	.list_voltage = wm8400_ldo_list_voltage,
+	.get_voltage_sel = wm8400_ldo_get_voltage_sel,
+	.set_voltage = wm8400_ldo_set_voltage,
+};
+
+static int wm8400_dcdc_is_enabled(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+	u16 val;
+
+	val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+	return (val & WM8400_DC1_ENA) != 0;
+}
+
+static int wm8400_dcdc_enable(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+	return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+			       WM8400_DC1_ENA, WM8400_DC1_ENA);
+}
+
+static int wm8400_dcdc_disable(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+	return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+			       WM8400_DC1_ENA, 0);
+}
+
+static int wm8400_dcdc_list_voltage(struct regulator_dev *dev,
+				    unsigned selector)
+{
+	if (selector > WM8400_DC1_VSEL_MASK)
+		return -EINVAL;
+
+	return 850000 + (selector * 25000);
+}
+
+static int wm8400_dcdc_get_voltage_sel(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+	val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+	val &= WM8400_DC1_VSEL_MASK;
+
+	return val;
+}
+
+static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
+				   int min_uV, int max_uV, unsigned *selector)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	u16 val;
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+	if (min_uV < 850000)
+		return -EINVAL;
+
+	val = DIV_ROUND_UP(min_uV - 850000, 25000);
+
+	if (850000 + (25000 * val) > max_uV)
+		return -EINVAL;
+	BUG_ON(850000 + (25000 * val) < min_uV);
+
+	*selector = val;
+
+	return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+			       WM8400_DC1_VSEL_MASK, val);
+}
+
+static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+	u16 data[2];
+	int ret;
+
+	ret = wm8400_block_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset, 2,
+				data);
+	if (ret != 0)
+		return 0;
+
+	/* Datasheet: hibernate */
+	if (data[0] & WM8400_DC1_SLEEP)
+		return REGULATOR_MODE_STANDBY;
+
+	/* Datasheet: standby */
+	if (!(data[0] & WM8400_DC1_ACTIVE))
+		return REGULATOR_MODE_IDLE;
+
+	/* Datasheet: active with or without force PWM */
+	if (data[1] & WM8400_DC1_FRC_PWM)
+		return REGULATOR_MODE_FAST;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int wm8400_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+	struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+	int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+	int ret;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		/* Datasheet: active with force PWM */
+		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+				      WM8400_DC1_FRC_PWM, WM8400_DC1_FRC_PWM);
+		if (ret != 0)
+			return ret;
+
+		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+				       WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+				       WM8400_DC1_ACTIVE);
+
+	case REGULATOR_MODE_NORMAL:
+		/* Datasheet: active */
+		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+				      WM8400_DC1_FRC_PWM, 0);
+		if (ret != 0)
+			return ret;
+
+		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+				       WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+				       WM8400_DC1_ACTIVE);
+
+	case REGULATOR_MODE_IDLE:
+		/* Datasheet: standby */
+		ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+				      WM8400_DC1_ACTIVE, 0);
+		if (ret != 0)
+			return ret;
+		return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+				       WM8400_DC1_SLEEP, 0);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
+						 int input_uV, int output_uV,
+						 int load_uA)
+{
+	return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops wm8400_dcdc_ops = {
+	.is_enabled = wm8400_dcdc_is_enabled,
+	.enable = wm8400_dcdc_enable,
+	.disable = wm8400_dcdc_disable,
+	.list_voltage = wm8400_dcdc_list_voltage,
+	.get_voltage_sel = wm8400_dcdc_get_voltage_sel,
+	.set_voltage = wm8400_dcdc_set_voltage,
+	.get_mode = wm8400_dcdc_get_mode,
+	.set_mode = wm8400_dcdc_set_mode,
+	.get_optimum_mode = wm8400_dcdc_get_optimum_mode,
+};
+
+static struct regulator_desc regulators[] = {
+	{
+		.name = "LDO1",
+		.id = WM8400_LDO1,
+		.ops = &wm8400_ldo_ops,
+		.n_voltages = WM8400_LDO1_VSEL_MASK + 1,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO2",
+		.id = WM8400_LDO2,
+		.ops = &wm8400_ldo_ops,
+		.n_voltages = WM8400_LDO2_VSEL_MASK + 1,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO3",
+		.id = WM8400_LDO3,
+		.ops = &wm8400_ldo_ops,
+		.n_voltages = WM8400_LDO3_VSEL_MASK + 1,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO4",
+		.id = WM8400_LDO4,
+		.ops = &wm8400_ldo_ops,
+		.n_voltages = WM8400_LDO4_VSEL_MASK + 1,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC1",
+		.id = WM8400_DCDC1,
+		.ops = &wm8400_dcdc_ops,
+		.n_voltages = WM8400_DC1_VSEL_MASK + 1,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC2",
+		.id = WM8400_DCDC2,
+		.ops = &wm8400_dcdc_ops,
+		.n_voltages = WM8400_DC2_VSEL_MASK + 1,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __devinit wm8400_regulator_probe(struct platform_device *pdev)
+{
+	struct wm8400 *wm8400 = container_of(pdev, struct wm8400, regulators[pdev->id]);
+	struct regulator_dev *rdev;
+
+	rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
+				  pdev->dev.platform_data, wm8400, NULL);
+
+	if (IS_ERR(rdev))
+		return PTR_ERR(rdev);
+
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+}
+
+static int __devexit wm8400_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	regulator_unregister(rdev);
+
+	return 0;
+}
+
+static struct platform_driver wm8400_regulator_driver = {
+	.driver = {
+		.name = "wm8400-regulator",
+	},
+	.probe = wm8400_regulator_probe,
+	.remove = __devexit_p(wm8400_regulator_remove),
+};
+
+/**
+ * wm8400_register_regulator - enable software control of a WM8400 regulator
+ *
+ * This function enables software control of a WM8400 regulator via
+ * the regulator API.  It is intended to be called from the
+ * platform_init() callback of the WM8400 MFD driver.
+ *
+ * @param dev      The WM8400 device to operate on.
+ * @param reg      The regulator to control.
+ * @param initdata Regulator initdata for the regulator.
+ */
+int wm8400_register_regulator(struct device *dev, int reg,
+			      struct regulator_init_data *initdata)
+{
+	struct wm8400 *wm8400 = dev_get_drvdata(dev);
+
+	if (wm8400->regulators[reg].name)
+		return -EBUSY;
+
+	initdata->driver_data = wm8400;
+
+	wm8400->regulators[reg].name = "wm8400-regulator";
+	wm8400->regulators[reg].id = reg;
+	wm8400->regulators[reg].dev.parent = dev;
+	wm8400->regulators[reg].dev.platform_data = initdata;
+
+	return platform_device_register(&wm8400->regulators[reg]);
+}
+EXPORT_SYMBOL_GPL(wm8400_register_regulator);
+
+static int __init wm8400_regulator_init(void)
+{
+	return platform_driver_register(&wm8400_regulator_driver);
+}
+subsys_initcall(wm8400_regulator_init);
+
+static void __exit wm8400_regulator_exit(void)
+{
+	platform_driver_unregister(&wm8400_regulator_driver);
+}
+module_exit(wm8400_regulator_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM8400 regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8400-regulator");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/wm8994-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/wm8994-regulator.c
new file mode 100644
index 0000000..75ed402
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/wm8994-regulator.c
@@ -0,0 +1,335 @@
+/*
+ * wm8994-regulator.c  --  Regulator driver for the WM8994
+ *
+ * Copyright 2009 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/mfd/wm8994/pdata.h>
+
+struct wm8994_ldo {
+	int enable;
+	bool is_enabled;
+	struct regulator_dev *regulator;
+	struct wm8994 *wm8994;
+};
+
+#define WM8994_LDO1_MAX_SELECTOR 0x7
+#define WM8994_LDO2_MAX_SELECTOR 0x3
+
+static int wm8994_ldo_enable(struct regulator_dev *rdev)
+{
+	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+
+	/* If we have no soft control assume that the LDO is always enabled. */
+	if (!ldo->enable)
+		return 0;
+
+	gpio_set_value_cansleep(ldo->enable, 1);
+	ldo->is_enabled = true;
+
+	return 0;
+}
+
+static int wm8994_ldo_disable(struct regulator_dev *rdev)
+{
+	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+
+	/* If we have no soft control assume that the LDO is always enabled. */
+	if (!ldo->enable)
+		return -EINVAL;
+
+	gpio_set_value_cansleep(ldo->enable, 0);
+	ldo->is_enabled = false;
+
+	return 0;
+}
+
+static int wm8994_ldo_is_enabled(struct regulator_dev *rdev)
+{
+	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+
+	return ldo->is_enabled;
+}
+
+static int wm8994_ldo_enable_time(struct regulator_dev *rdev)
+{
+	/* 3ms is fairly conservative but this shouldn't be too performance
+	 * critical; can be tweaked per-system if required. */
+	return 3000;
+}
+
+static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev,
+				    unsigned int selector)
+{
+	if (selector > WM8994_LDO1_MAX_SELECTOR)
+		return -EINVAL;
+
+	return (selector * 100000) + 2400000;
+}
+
+static int wm8994_ldo1_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+	int val;
+
+	val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_1);
+	if (val < 0)
+		return val;
+
+	return (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT;
+}
+
+static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev,
+				   int min_uV, int max_uV, unsigned *s)
+{
+	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+	int selector, v;
+
+	selector = (min_uV - 2400000) / 100000;
+	v = wm8994_ldo1_list_voltage(rdev, selector);
+	if (v < 0 || v > max_uV)
+		return -EINVAL;
+
+	*s = selector;
+	selector <<= WM8994_LDO1_VSEL_SHIFT;
+
+	return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1,
+			       WM8994_LDO1_VSEL_MASK, selector);
+}
+
+static struct regulator_ops wm8994_ldo1_ops = {
+	.enable = wm8994_ldo_enable,
+	.disable = wm8994_ldo_disable,
+	.is_enabled = wm8994_ldo_is_enabled,
+	.enable_time = wm8994_ldo_enable_time,
+
+	.list_voltage = wm8994_ldo1_list_voltage,
+	.get_voltage_sel = wm8994_ldo1_get_voltage_sel,
+	.set_voltage = wm8994_ldo1_set_voltage,
+};
+
+static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
+				    unsigned int selector)
+{
+	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+
+	if (selector > WM8994_LDO2_MAX_SELECTOR)
+		return -EINVAL;
+
+	switch (ldo->wm8994->type) {
+	case WM8994:
+		return (selector * 100000) + 900000;
+	case WM8958:
+		return (selector * 100000) + 1000000;
+	case WM1811:
+		switch (selector) {
+		case 0:
+			return -EINVAL;
+		default:
+			return (selector * 100000) + 950000;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+	int val;
+
+	val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_2);
+	if (val < 0)
+		return val;
+
+	return (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT;
+}
+
+static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
+				   int min_uV, int max_uV, unsigned *s)
+{
+	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+	int selector, v;
+
+	switch (ldo->wm8994->type) {
+	case WM8994:
+		selector = (min_uV - 900000) / 100000;
+		break;
+	case WM8958:
+		selector = (min_uV - 1000000) / 100000;
+		break;
+	case WM1811:
+		selector = (min_uV - 950000) / 100000;
+		if (selector == 0)
+			selector = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	v = wm8994_ldo2_list_voltage(rdev, selector);
+	if (v < 0 || v > max_uV)
+		return -EINVAL;
+
+	*s = selector;
+	selector <<= WM8994_LDO2_VSEL_SHIFT;
+
+	return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2,
+			       WM8994_LDO2_VSEL_MASK, selector);
+}
+
+static struct regulator_ops wm8994_ldo2_ops = {
+	.enable = wm8994_ldo_enable,
+	.disable = wm8994_ldo_disable,
+	.is_enabled = wm8994_ldo_is_enabled,
+	.enable_time = wm8994_ldo_enable_time,
+
+	.list_voltage = wm8994_ldo2_list_voltage,
+	.get_voltage_sel = wm8994_ldo2_get_voltage_sel,
+	.set_voltage = wm8994_ldo2_set_voltage,
+};
+
+static struct regulator_desc wm8994_ldo_desc[] = {
+	{
+		.name = "LDO1",
+		.id = 1,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8994_LDO1_MAX_SELECTOR + 1,
+		.ops = &wm8994_ldo1_ops,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "LDO2",
+		.id = 2,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = WM8994_LDO2_MAX_SELECTOR + 1,
+		.ops = &wm8994_ldo2_ops,
+		.owner = THIS_MODULE,
+	},
+};
+
+static __devinit int wm8994_ldo_probe(struct platform_device *pdev)
+{
+	struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
+	struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+	int id = pdev->id % ARRAY_SIZE(pdata->ldo);
+	struct wm8994_ldo *ldo;
+	int ret;
+
+	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
+
+	if (!pdata)
+		return -ENODEV;
+
+	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL);
+	if (ldo == NULL) {
+		dev_err(&pdev->dev, "Unable to allocate private data\n");
+		return -ENOMEM;
+	}
+
+	ldo->wm8994 = wm8994;
+
+	if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) {
+		ldo->enable = pdata->ldo[id].enable;
+
+		ret = gpio_request(ldo->enable, "WM8994 LDO enable");
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n",
+				ret);
+			goto err;
+		}
+
+		ret = gpio_direction_output(ldo->enable, ldo->is_enabled);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Failed to set GPIO up: %d\n",
+				ret);
+			goto err_gpio;
+		}
+	} else
+		ldo->is_enabled = true;
+
+	ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev,
+					     pdata->ldo[id].init_data, ldo, NULL);
+	if (IS_ERR(ldo->regulator)) {
+		ret = PTR_ERR(ldo->regulator);
+		dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
+			id + 1, ret);
+		goto err_gpio;
+	}
+
+	platform_set_drvdata(pdev, ldo);
+
+	return 0;
+
+err_gpio:
+	if (gpio_is_valid(ldo->enable))
+		gpio_free(ldo->enable);
+err:
+	return ret;
+}
+
+static __devexit int wm8994_ldo_remove(struct platform_device *pdev)
+{
+	struct wm8994_ldo *ldo = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	regulator_unregister(ldo->regulator);
+	if (gpio_is_valid(ldo->enable))
+		gpio_free(ldo->enable);
+
+	return 0;
+}
+
+static struct platform_driver wm8994_ldo_driver = {
+	.probe = wm8994_ldo_probe,
+	.remove = __devexit_p(wm8994_ldo_remove),
+	.driver		= {
+		.name	= "wm8994-ldo",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init wm8994_ldo_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&wm8994_ldo_driver);
+	if (ret != 0)
+		pr_err("Failed to register Wm8994 GP LDO driver: %d\n", ret);
+
+	return ret;
+}
+subsys_initcall(wm8994_ldo_init);
+
+static void __exit wm8994_ldo_exit(void)
+{
+	platform_driver_unregister(&wm8994_ldo_driver);
+}
+module_exit(wm8994_ldo_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM8994 LDO driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8994-ldo");
diff --git a/ap/os/linux/linux-3.4.x/drivers/regulator/zx234290-regulator.c b/ap/os/linux/linux-3.4.x/drivers/regulator/zx234290-regulator.c
new file mode 100644
index 0000000..9fd17d6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/regulator/zx234290-regulator.c
@@ -0,0 +1,705 @@
+/*
+ * zx234290-regulator.c  --  ZTE zx234290
+ *
+ * Copyright 2013 ZTE Corporation.
+ *
+ * Author: Dong Jian <>
+ *
+ *  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 driver is based on wm8350 implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/zx234290.h>
+
+//#define ZX234290_REG_VCOIN	16	/* 0x02	*/
+//#define ZX234290_REG_VRF	17	/* fixed	*/
+
+/* Number of step-down converters available */
+#define ZX234290_NUM_DCDC	5
+
+/* Number of LDO voltage regulators  available */
+#define ZX234290_NUM_LDO	11
+
+/* Number of total regulators available */
+#define ZX234290_NUM_REGULATOR		(ZX234290_NUM_DCDC + ZX234290_NUM_LDO)
+
+
+struct zx_info {
+	const char *name;
+};
+
+static struct zx_info zx234290_regs[] = {
+	{
+		.name = "LDO1",
+	},
+	{
+		.name = "LDO2",
+	},
+	{
+		.name = "LDO3",
+	},
+	{
+		.name = "LDO4",
+	},
+	{
+		.name = "LDO5",
+	},
+	{
+		.name = "LDO6",
+	},
+	{
+		.name = "LDO7",
+	},
+	{
+		.name = "LDO8",
+	},
+	{
+		.name = "LDO9",
+	},
+	{
+		.name = "LDO10",
+	},
+	{
+		.name = "LDO11",
+	},
+	{
+		.name = "DCDC0",
+	},
+	{
+		.name = "DCDC1",
+	},
+	{
+		.name = "DCDC2",
+	},
+	{
+		.name = "DCDC3",
+	},
+	{
+		.name = "DCDC4",
+	},
+};
+
+struct zx234290_reg {
+	struct regulator_desc desc[ZX234290_NUM_REGULATOR];
+	struct zx234290 *mfd;
+	struct regulator_dev *rdev[ZX234290_NUM_REGULATOR];
+	struct zx_info *info[ZX234290_NUM_REGULATOR];
+	/* for read/write access */
+	struct mutex io_lock;
+	int mode;
+	int (*get_ctrl_reg)(int);
+	int normal_mode_reg;
+	int sleep_mode_reg;
+};
+
+
+/* LDO output enable mask */
+#define	ZX234290_EN1_LDO1_EN	BIT(0)
+#define	ZX234290_EN1_LDO2_EN	BIT(1)
+#define	ZX234290_EN1_LDO3_EN	BIT(2)
+#define	ZX234290_EN1_LDO4_EN	BIT(3)
+#define	ZX234290_EN1_LDO5_EN	BIT(4)
+#define	ZX234290_EN1_LDO6_EN	BIT(5)
+#define	ZX234290_EN1_LDO7_EN	BIT(6)
+#define	ZX234290_EN1_LDO8_EN	BIT(7)
+
+#define	ZX234290_EN2_LDO9_EN	BIT(0)
+#define	ZX234290_EN2_LDO10_EN	BIT(1)
+#define	ZX234290_EN2_LDO11_EN	BIT(2)
+#define	ZX234290_EN2_BUCK0_EN	BIT(3)
+#define	ZX234290_EN2_BUCK1_EN	BIT(4)
+#define	ZX234290_EN2_BUCK2_EN	BIT(5)
+#define	ZX234290_EN2_BUCK3_EN	BIT(6)
+#define	ZX234290_EN2_BUCK4_EN	BIT(7)
+
+
+#if 1
+static const int ldo5_voltage_map[] = {
+	3300,
+};
+
+/* VLA - ldo1/2/3/10	*/
+static const int ldoa_voltage_map[] = {
+	   0,  800,  850,  900,  950, 1000, 1050, 1100,
+	1200, 1500, 1800, 2000, 2500, 2800, 3000, 3300,
+};
+
+/* VLB - VCOIN 2bit	*/
+static const int ldob_voltage_map[] = {
+	1800, 2500, 3000, 3300,
+};
+
+/* VLAC - ldo11	*/
+static const int ldoc_voltage_map[] = {
+	   0,  800,  825,  850,  875,  900,  925,  950,
+	 975, 1000, 1025, 1050, 1075, 1100, 1800, 2800,
+};
+
+/* VLD - ldo4/6/7/8/9	*/
+static const int ldod_voltage_map[] = {
+	   0, 1500, 1600, 1800, 1850, 2000, 2005, 2500,
+	2550, 2700, 2750, 2800, 2850, 2900, 2950, 3000,
+};
+
+/* VBA - BUCK0/1 	5bit 0x1f	*/
+static const int bucka_voltage_map[] = {
+	   0,  700,  725,  750,  775,  800,  825,  850,
+	 875,  900,	 925,  950,  975, 1000, 1025, 1050,
+	1075, 1100,	1125, 1150, 1175, 1200, 1225, 1250,
+	1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250,
+};
+
+/* VBC - BUCK2 		4bit 0x0f  0000 1111	*/
+static const int buckc_voltage_map[] = {
+	   0,  900,  950, 1000, 1050, 1100,
+	1150, 1200, 1250, 1300, 1350, 1400,
+	1450, 1500, 1550, 1600,
+};
+
+/*  VBD-BUCK3	*/
+static const int buck3_voltage_map[] = {
+	1600,
+};
+
+/*  VBE-BUCK4	*/
+static const int buck4_voltage_map[] = {
+	3600,
+};
+
+/* BUCK3/4 EXTERNAL ADJUSTABLE	*/
+/* LDO5- FIXED	*/
+/* VLA-ldo1/2/3/10  VLB-VCOIN-2bit VLAC-ldo11 VLD-ldo4/6/7/8/9	*/
+static const int *ldo_voltage_map[] = {
+	ldoa_voltage_map,	/* ldo1	*/
+	ldoa_voltage_map,
+	ldoa_voltage_map,	/* ldo3	*/
+	ldod_voltage_map,	/* ldo4	*/
+	ldo5_voltage_map,	/* ldo5	*/
+	ldod_voltage_map,	/* ldo6	*/
+	ldod_voltage_map,
+	ldod_voltage_map,
+	ldod_voltage_map,	/* ldo9	*/
+	ldoa_voltage_map,	/* ldo10	*/
+	ldoc_voltage_map,	/* ldo11	*/
+	ldob_voltage_map,	/* coin	*/
+};
+
+/* VBA-BUCK0/1  VBC-BUCK2    EXTERNAL ADJUSTABLE-BUCK3/4 	*/
+static const int *buck_voltage_map[] = {
+	bucka_voltage_map,	/* buck0	*/
+	bucka_voltage_map,	/* buck1	*/
+	buckc_voltage_map,	/* buck2	*/
+	buck3_voltage_map,	/* buck3    */
+	buck4_voltage_map,	/* buck4	*/
+};
+
+#if 1
+static const int ldo_output_enable_mask[] = {
+	ZX234290_EN1_LDO1_EN,
+	ZX234290_EN1_LDO2_EN,
+	ZX234290_EN1_LDO3_EN,
+	ZX234290_EN1_LDO4_EN,
+	ZX234290_EN1_LDO5_EN,
+	ZX234290_EN1_LDO6_EN,
+	ZX234290_EN1_LDO7_EN,
+	ZX234290_EN1_LDO8_EN,
+
+	ZX234290_EN2_LDO9_EN,
+	ZX234290_EN2_LDO10_EN,
+	ZX234290_EN2_LDO11_EN,
+	ZX234290_EN2_BUCK0_EN,
+	ZX234290_EN2_BUCK1_EN,
+	ZX234290_EN2_BUCK2_EN,
+	ZX234290_EN2_BUCK3_EN,
+	ZX234290_EN2_BUCK4_EN,
+};
+
+/* ²»ÓøÃÊý×é ÓÃÄǸöº¯Êý  zx234290_get_ctrl_register	*/
+static const int ldo_output_enable_addr[] = {
+	ZX234290_REG_ADDR_LDO_EN1,
+	ZX234290_REG_ADDR_LDO_EN2,
+};
+#endif
+
+#endif
+
+#define ZX234290_COIN_VOL_MASK 0x02
+
+#define ZX234290_LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[x])
+#define ZX234290_LDO_VOL_MASK(x) (((x) % 2) ? 0xf0 : 0x0f)
+
+/* enable	*/
+#define ZX234290_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x])
+
+#define ZX234290_BUCK_VOL_VALUE_MAP(x) (buck_voltage_map[x])
+#define ZX234290_BUCK_VOL_MASK(x) (((x) != 13) ? 0x1f : 0x0f)	/* 0001 1111  or 0000 1111	*/
+
+/* ͨ¹ýLDO id »ñÈ¡¸ÃLDOµÄ ʹÄÜ ¼Ä´æÆ÷	*/
+static int zx234290_get_ctrl_register(int id)
+{
+	if (id >= ZX234290_REG_LDO1 && id <= ZX234290_REG_LDO8)
+		return ZX234290_REG_ADDR_LDO_EN1;
+	else if (id >= ZX234290_REG_LDO9 && id <= ZX234290_REG_DCDC4)
+		return ZX234290_REG_ADDR_LDO_EN2;
+	else
+		return -EINVAL;
+}
+
+/* Ñ¡ÔñµçѹÉèÖüĴæÆ÷*/
+static int zx234290_get_sel_register(struct zx234290_reg *pmic, int id)
+{
+	u8 reg = 0;
+
+	switch(id) {
+	case ZX234290_REG_DCDC0:	/* 0x1f	*/
+		reg = ZX234290_REG_ADDR_BUCK0_VOL;
+	case ZX234290_REG_DCDC1:	/* 0x1f	*/
+		reg = ZX234290_REG_ADDR_BUCK1_VOL;
+		break;
+	case ZX234290_REG_DCDC2:	/* 0x0f	*/
+		reg = ZX234290_REG_ADDR_BUCK2_VOL;
+		break;
+	case ZX234290_REG_LDO1:	/* 0x0f	*/
+	case ZX234290_REG_LDO2: /* 0xf0	*/
+		reg = ZX234290_REG_ADDR_LDO12_VOL;
+		break;
+	case ZX234290_REG_LDO3:	/* 0x0f	*/
+	case ZX234290_REG_LDO4: /* 0xf0	*/
+		reg = ZX234290_REG_ADDR_LDO34_VOL;
+		break;
+	case ZX234290_REG_LDO6: /* 0xf0	*/
+		reg = ZX234290_REG_ADDR_LDO6_VOL;
+		break;
+	case ZX234290_REG_LDO7:	/* 0x0f	*/
+	case ZX234290_REG_LDO8: /* 0xf0	*/
+		reg = ZX234290_REG_ADDR_LDO78_VOL;
+		break;
+	case ZX234290_REG_LDO9:	/* 0x0f	*/
+	case ZX234290_REG_LDO10: /* 0xf0	*/
+		reg = ZX234290_REG_ADDR_LDO910_VOL;
+		break;
+	case ZX234290_REG_LDO11: /* 0xf0	*/
+		reg = ZX234290_REG_ADDR_LDO11_VOL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return reg;
+}
+
+static int zx234290_get_mode_regiters(struct zx234290_reg *pmic, int id)
+{
+	switch (id) {
+	case ZX234290_REG_DCDC0:
+	case ZX234290_REG_DCDC1:
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_BUCK01_MODE;/* 0x0c	*/
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_BUCK01_MODE; /* 0x03 */
+		break;
+	case ZX234290_REG_DCDC2:
+	case ZX234290_REG_DCDC3:
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_BUCK23_MODE;
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_BUCK23_MODE;
+		break;
+	case ZX234290_REG_DCDC4:
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_BUCK4_MODE;
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_BUCK4_MODE;
+		break;
+	case ZX234290_REG_LDO1:
+	case ZX234290_REG_LDO2:
+	case ZX234290_REG_LDO3:
+	case ZX234290_REG_LDO4:
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_LDO1234_MODE;
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_LDO1234_MODE;
+		break;
+	case ZX234290_REG_LDO5:
+	case ZX234290_REG_LDO6:
+	case ZX234290_REG_LDO7:
+	case ZX234290_REG_LDO8:
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_LDO5678_MODE;
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_LDO5678_MODE;
+		break;
+	case ZX234290_REG_LDO9:
+	case ZX234290_REG_LDO10:
+	case ZX234290_REG_LDO11:
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_LDO91011_MODE;
+		pmic->normal_mode_reg = ZX234290_REG_ADDR_LDO91011_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#if 1	/* enable	*/
+static int zx234290_reg_is_enabled(struct regulator_dev *dev)
+{
+	struct zx234290_reg *pmic = rdev_get_drvdata(dev);
+	struct zx234290 *mfd = pmic->mfd;
+	int reg, value, id = rdev_get_id(dev);
+
+	if (id < ZX234290_REG_LDO1 || id > ZX234290_REG_DCDC4)
+		return -EINVAL;
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	value = zx234290_reg_read(mfd, reg);
+	if (value < 0)
+		return value;
+
+	return value & (ZX234290_LDO_OUTPUT_ENABLE_MASK(id));
+}
+
+static int zx234290_reg_enable(struct regulator_dev *dev)
+{
+	struct zx234290_reg *pmic = rdev_get_drvdata(dev);
+	struct zx234290 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev);
+	int reg;
+
+	if (id < ZX234290_REG_LDO1 || id > ZX234290_REG_DCDC4)
+		return -EINVAL;
+
+	/* »ñȡʹÄܼĴæÆ÷	*/
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	/* ¶Ô ZX234290_REG_ENABLED 1000 0000 ¸ßλ Öà 1	*/
+	return zx234290_set_bits(mfd, reg, ZX234290_LDO_OUTPUT_ENABLE_MASK(id));
+}
+
+static int zx234290_reg_disable(struct regulator_dev *dev)
+{
+	struct zx234290_reg *pmic = rdev_get_drvdata(dev);
+	struct zx234290 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev), reg;
+
+	reg = pmic->get_ctrl_reg(id);
+	if (reg < 0)
+		return reg;
+
+	return zx234290_clear_bits(mfd, reg, ZX234290_LDO_OUTPUT_ENABLE_MASK(id));
+}
+#endif
+
+static int zx234290_set_voltage_sel(struct regulator_dev *dev,
+					 unsigned selector)
+{
+	struct zx234290_reg *pmic = rdev_get_drvdata(dev);
+	struct zx234290 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev);
+	int value;
+	u8 reg;
+
+	reg = zx234290_get_sel_register(pmic, id);
+	value = zx234290_reg_read(mfd, reg);
+
+	if (id >= ZX234290_REG_LDO1 && id <= ZX234290_REG_LDO11 && id != ZX234290_REG_LDO5)
+	{
+		value &= ~(ZX234290_LDO_VOL_MASK(id));
+		if (id%2)selector *=16;	/* leftshit 5bits	*/
+	}
+	else if (id >= ZX234290_REG_DCDC1 && id <= ZX234290_REG_DCDC2)
+		value &= ~(ZX234290_BUCK_VOL_MASK(id));
+	else
+		return -EINVAL;
+
+	return zx234290_reg_write(mfd, reg, selector | value);
+}
+
+
+
+#if 1
+static int zx234290_ldo_list_voltage(struct regulator_dev *dev, unsigned selector)
+{
+	int ldo = rdev_get_id(dev) - ZX234290_REG_LDO1;
+	return 1000 * ZX234290_LDO_VOL_VALUE_MAP(ldo)[selector];
+}
+
+static int zx234290_ldo_get_voltage(struct regulator_dev *dev)
+{
+	struct zx234290_reg *pmic = rdev_get_drvdata(dev);
+	struct zx234290 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev);
+	int reg, vsel;
+
+	/* Ñ¡ÔñµçѹÉèÖüĴæÆ÷	*/
+	reg = zx234290_get_sel_register(pmic, id);
+	if (reg < 0)
+		return reg;
+
+	/* ¶ÁÈ¡µçѹ	*/
+	vsel = zx234290_reg_read(mfd, reg);
+	vsel &= ZX234290_LDO_VOL_MASK(id); /* 0000 1111	*/
+	/* ldo2/4/6/8/10 ¸ß4λ	*/
+	if(id%2)
+		vsel/=16;
+
+	/* »ñÈ¡vsel slector ¼´µçѹµÄÐòÁÐ  È»ºóͨ¹ýlist·µ»Øµçѹ	*/
+	return zx234290_ldo_list_voltage(dev, vsel);
+}
+
+/* Operations permitted on LDOx */
+static struct regulator_ops zx234290_ops_ldo = {
+	.is_enabled = zx234290_reg_is_enabled,
+	.enable = zx234290_reg_enable,
+	.disable = zx234290_reg_disable,
+	.get_voltage = zx234290_ldo_get_voltage,
+	.set_voltage_sel = zx234290_set_voltage_sel,
+	.list_voltage = zx234290_ldo_list_voltage,
+};
+#endif
+
+
+
+#if 1
+static int zx234290_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
+{
+	int buck = rdev_get_id(dev) - ZX234290_REG_DCDC0;
+	return 1000 * buck_voltage_map[buck][index];
+}
+
+#if 0
+static int zx234290_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+	struct zx234290_reg *pmic = rdev_get_drvdata(dev);
+	struct zx234290 *mfd = pmic->mfd;
+	int normal_mode, sleep_mode, id = rdev_get_id(dev);
+
+	zx234290_get_mode_regiters(pmic, id);
+
+	normal_mode = zx234290_reg_read(mfd, pmic->normal_mode_reg);
+	sleep_mode = zx234290_reg_read(mfd, pmic->sleep_mode_reg);
+
+	normal_mode &= DCDCCTRL_DCDC_MODE_MASK;
+	sleep_mode &= DCDC_AVS_ECO_MASK;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		/* Verify if mode alredy set */
+		if (normal_mode && !sleep_mode)
+			break;
+		zx234290_set_bits(mfd, pmic->normal_mode, DCDCCTRL_DCDC_MODE_MASK);
+		zx234290_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+		break;
+	case REGULATOR_MODE_NORMAL:
+	case REGULATOR_MODE_IDLE:
+		if (!normal_mode && !sleep_mode)
+			break;
+		zx234290_clear_bits(mfd, pmic->normal_mode, DCDCCTRL_DCDC_MODE_MASK);
+		zx234290_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+		break;
+	case REGULATOR_MODE_STANDBY:
+		if (!normal_mode && sleep_mode)
+			break;
+		zx234290_clear_bits(mfd, pmic->normal_mode, DCDCCTRL_DCDC_MODE_MASK);
+		zx234290_set_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned int zx234290_get_mode(struct regulator_dev *dev)
+{
+	struct zx234290_reg *pmic = rdev_get_drvdata(dev);
+	struct zx234290 *mfd = pmic->mfd;
+	int pwm_mode, eco, mode = 0, id = rdev_get_id(dev);
+
+	zx234290_get_mode_regiters(pmic, id);
+
+	pwm_mode = zx234290_reg_read(mfd, pmic->normal_mode_reg);
+	eco = zx234290_reg_read(mfd, pmic->sleep_mode_reg);
+
+	pwm_mode &= DCDCCTRL_DCDC_MODE_MASK;
+	eco &= DCDC_AVS_ECO_MASK;
+
+	if (pwm_mode && !eco)
+		mode = REGULATOR_MODE_FAST;
+	else if (!pwm_mode && !eco)
+		mode = REGULATOR_MODE_NORMAL;
+	else if (!pwm_mode && eco)
+		mode = REGULATOR_MODE_STANDBY;
+
+	return mode;
+}
+#endif
+
+static int zx234290_dcdc_get_voltage(struct regulator_dev *dev)
+{
+	struct zx234290_reg *pmic = rdev_get_drvdata(dev);
+	struct zx234290 *mfd = pmic->mfd;
+	int id = rdev_get_id(dev);
+	int reg, vsel;
+
+	/* Ñ¡ÔñµçѹÉèÖüĴæÆ÷	*/
+	reg = zx234290_get_sel_register(pmic, id);
+	if (reg < 0)
+		return reg;
+
+	/* ¶ÁÈ¡µçѹ	*/
+	vsel = zx234290_reg_read(mfd, reg);
+	vsel &= ZX234290_BUCK_VOL_MASK(id); /* 0001 1111	*/
+
+	/* »ñÈ¡vsel slector ¼´µçѹµÄÐòÁÐ  È»ºóͨ¹ýlist·µ»Øµçѹ	*/
+	return zx234290_dcdc_list_voltage(dev, vsel);
+}
+
+/* Operations permitted on DCDCx */
+static struct regulator_ops zx234290_ops_dcdc = {
+	.is_enabled = zx234290_reg_is_enabled,
+	.enable = zx234290_reg_enable,
+	.disable = zx234290_reg_disable,
+/*	.set_mode = zx234290_set_mode,
+	.get_mode = zx234290_get_mode,
+*/	.get_voltage = zx234290_dcdc_get_voltage,
+	.set_voltage_sel = zx234290_set_voltage_sel,
+	.list_voltage = zx234290_dcdc_list_voltage,
+};
+#endif
+
+static __devinit int zx234290_probe(struct platform_device *pdev)
+{
+	struct zx234290 *zx234290 = dev_get_drvdata(pdev->dev.parent);
+	struct zx_info *info;
+	struct regulator_init_data *reg_data;
+	struct regulator_dev *rdev;
+	struct zx234290_reg *pmic;
+	struct zx234290_board *pmic_plat_data;
+	struct zx234290_platform_data *zx234290_plat_data;
+
+	int i, err;
+
+	pr_info("%s hello \n", __func__);
+
+	pmic_plat_data = dev_get_platdata(pdev->dev.parent);
+	if (!pmic_plat_data)
+		return -EINVAL;
+
+	pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	mutex_init(&pmic->io_lock);
+	pmic->mfd = zx234290;
+	platform_set_drvdata(pdev, pmic);
+
+	pmic->get_ctrl_reg = &zx234290_get_ctrl_register;
+	info = zx234290_regs;
+
+#if 1
+	pmic->desc[0].n_voltages =  // 1/2/3/10
+	pmic->desc[1].n_voltages =
+	pmic->desc[2].n_voltages =
+	pmic->desc[9].n_voltages = ARRAY_SIZE(ldoa_voltage_map);
+	pmic->desc[3].n_voltages =
+	pmic->desc[5].n_voltages =
+	pmic->desc[6].n_voltages =
+	pmic->desc[7].n_voltages =
+	pmic->desc[8].n_voltages =	ARRAY_SIZE(ldod_voltage_map); // 4/6/7/8/9
+	pmic->desc[10].n_voltages = ARRAY_SIZE(ldoc_voltage_map); // 11
+	pmic->desc[11].n_voltages =
+	pmic->desc[12].n_voltages = ARRAY_SIZE(bucka_voltage_map); // buck0/1
+	pmic->desc[13].n_voltages = ARRAY_SIZE(buckc_voltage_map); // buck2
+	pmic->desc[4].n_voltages =
+	pmic->desc[14].n_voltages =
+	pmic->desc[15].n_voltages = 1;
+#endif
+
+
+	for (i = 0; i < ZX234290_NUM_REGULATOR; i++, info++) {
+		/* Register the regulators */
+		pmic->info[i] = info;
+		pmic->desc[i].name = info->name;
+		pmic->desc[i].id = i;
+		pmic->desc[i].ops = (i > ZX234290_REG_LDO11 ?
+			&zx234290_ops_dcdc : &zx234290_ops_ldo);
+		pmic->desc[i].type = REGULATOR_VOLTAGE;
+		pmic->desc[i].owner = THIS_MODULE;
+
+		zx234290_plat_data= pmic_plat_data->regulator_pdata[i];
+		reg_data = zx234290_plat_data->reg_init_data;
+
+		rdev = regulator_register(&pmic->desc[i],
+					zx234290->dev, reg_data, pmic, NULL);
+
+
+		if (IS_ERR(rdev)) {
+			dev_err(zx234290->dev,
+				"failed to register %s regulator\n",
+				pdev->name);
+			err = PTR_ERR(rdev);
+			goto err;
+		}
+
+		/* Save regulator for cleanup */
+		pmic->rdev[i] = rdev;
+	}
+	return 0;
+
+err:
+	while (--i >= 0)
+		regulator_unregister(pmic->rdev[i]);
+
+	kfree(pmic);
+	return err;
+}
+
+static int __devexit zx234290_remove(struct platform_device *pdev)
+{
+	struct zx234290_reg *zx234290_reg = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < ZX234290_NUM_REGULATOR; i++)
+		regulator_unregister(zx234290_reg->rdev[i]);
+
+	kfree(zx234290_reg);
+	return 0;
+}
+
+static struct platform_driver zx234290_driver = {
+	.driver = {
+		.name = "zx234290-regulators",
+		.owner = THIS_MODULE,
+	},
+	.probe = zx234290_probe,
+	.remove = __devexit_p(zx234290_remove),
+};
+
+static int __init zx234290_init(void)
+{
+	pr_info("%s hello\n", __func__);
+	return platform_driver_register(&zx234290_driver);
+}
+subsys_initcall(zx234290_init);
+
+static void __exit zx234290_cleanup(void)
+{
+	platform_driver_unregister(&zx234290_driver);
+}
+module_exit(zx234290_cleanup);
+
+MODULE_AUTHOR("DongJian");
+MODULE_DESCRIPTION("ZX234290 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:zx234290-regulator");