lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 14 Aug 2013 16:58:02 +0200
From:	Florian Lobmaier <florian.lobmaier@....com>
To:	linux-kernel@...r.kernel.org
Cc:	broonie@...nel.org, lgirdwood@...il.com,
	Florian Lobmaier <florian.lobmaier@....com>
Subject: [PATCH] added support for ams AS3722 regulator


Signed-off-by: Florian Lobmaier <florian.lobmaier@....com>
---
 drivers/regulator/Kconfig            |    7 +
 drivers/regulator/Makefile           |    1 +
 drivers/regulator/as3722-regulator.c | 1336 ++++++++++++++++++++++++++++++++++
 3 files changed, 1344 insertions(+), 0 deletions(-)
 create mode 100644 drivers/regulator/as3722-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index f1e6ad9..a41adf0 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -533,5 +533,12 @@ config REGULATOR_AS3711
 	  This driver provides support for the voltage regulators on the
 	  AS3711 PMIC
 
+config REGULATOR_AS3722
+        tristate "ams AS3722 PMIC regulators"
+        depends on MFD_AS3722
+        help
+          This driver provides support for the voltage regulators of the
+          ams AS3722 PMIC.
+
 endif
 
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ba4a3cf..78669a5 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
 obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
 obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
 obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
+obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DA9055)	+= da9055-regulator.o
diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c
new file mode 100644
index 0000000..bb589c0
--- /dev/null
+++ b/drivers/regulator/as3722-regulator.c
@@ -0,0 +1,1336 @@
+/*
+ * as3722-regulator.c - voltage regulator support for AS3722
+ *
+ * Copyright (C) 2013 ams
+ *
+ * Author: Florian Lobmaier <florian.lobmaier@....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/bug.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/mfd/as3722-reg.h>
+#include <linux/mfd/as3722-plat.h>
+
+struct as3722_register_mapping {
+	u8 reg_id;
+	u8 reg_vsel;
+	u32 reg_enable;
+	u8 enable_bit;
+	u8 reg_stby_enable;
+};
+
+struct as3722_register_mapping as3722_reg_lookup[] = {
+	{
+		.reg_id = AS3722_LDO0,
+		.reg_vsel = AS3722_LDO0_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL0_REG,
+		.enable_bit = AS3722_LDO0_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD2_REG,
+	},
+	{
+		.reg_id = AS3722_LDO1,
+		.reg_vsel = AS3722_LDO1_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL0_REG,
+		.enable_bit = AS3722_LDO1_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD2_REG,
+	},
+	{
+		.reg_id = AS3722_LDO2,
+		.reg_vsel = AS3722_LDO2_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL0_REG,
+		.enable_bit = AS3722_LDO2_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD2_REG,
+	},
+	{
+		.reg_id = AS3722_LDO3,
+		.reg_vsel = AS3722_LDO3_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL0_REG,
+		.enable_bit = AS3722_LDO3_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD2_REG,
+	},
+	{
+		.reg_id = AS3722_LDO4,
+		.reg_vsel = AS3722_LDO4_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL0_REG,
+		.enable_bit = AS3722_LDO4_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD2_REG,
+	},
+	{
+		.reg_id = AS3722_LDO5,
+		.reg_vsel = AS3722_LDO5_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL0_REG,
+		.enable_bit = AS3722_LDO5_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD2_REG,
+	},
+	{
+		.reg_id = AS3722_LDO6,
+		.reg_vsel = AS3722_LDO6_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL0_REG,
+		.enable_bit = AS3722_LDO6_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD2_REG,
+	},
+	{
+		.reg_id = AS3722_LDO7,
+		.reg_vsel = AS3722_LDO7_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL0_REG,
+		.enable_bit = AS3722_LDO7_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD2_REG,
+	},
+	{
+		.reg_id = AS3722_LDO9,
+		.reg_vsel = AS3722_LDO9_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL1_REG,
+		.enable_bit = AS3722_LDO9_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD3_REG,
+	},
+	{
+		.reg_id = AS3722_LDO10,
+		.reg_vsel = AS3722_LDO10_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL1_REG,
+		.enable_bit = AS3722_LDO10_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD3_REG,
+	},
+	{
+		.reg_id = AS3722_LDO11,
+		.reg_vsel = AS3722_LDO11_VOLTAGE_REG,
+		.reg_enable = AS3722_LDOCONTROL1_REG,
+		.enable_bit = AS3722_LDO11_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD3_REG,
+	},
+	{
+		.reg_id = AS3722_SD0,
+		.reg_vsel = AS3722_SD0_VOLTAGE_REG,
+		.reg_enable = AS3722_SD_CONTROL_REG,
+		.enable_bit = AS3722_SD0_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD1_REG,
+	},
+	{
+		.reg_id = AS3722_SD1,
+		.reg_vsel = AS3722_SD1_VOLTAGE_REG,
+		.reg_enable = AS3722_SD_CONTROL_REG,
+		.enable_bit = AS3722_SD1_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD1_REG,
+	},
+	{
+		.reg_id = AS3722_SD2,
+		.reg_vsel = AS3722_SD2_VOLTAGE_REG,
+		.reg_enable = AS3722_SD_CONTROL_REG,
+		.enable_bit = AS3722_SD2_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD1_REG,
+	},
+	{
+		.reg_id = AS3722_SD3,
+		.reg_vsel = AS3722_SD3_VOLTAGE_REG,
+		.reg_enable = AS3722_SD_CONTROL_REG,
+		.enable_bit = AS3722_SD3_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD1_REG,
+	},
+	{
+		.reg_id = AS3722_SD4,
+		.reg_vsel = AS3722_SD4_VOLTAGE_REG,
+		.reg_enable = AS3722_SD_CONTROL_REG,
+		.enable_bit = AS3722_SD4_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD1_REG,
+	},
+	{
+		.reg_id = AS3722_SD5,
+		.reg_vsel = AS3722_SD5_VOLTAGE_REG,
+		.reg_enable = AS3722_SD_CONTROL_REG,
+		.enable_bit = AS3722_SD5_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD1_REG,
+	},
+	{
+		.reg_id = AS3722_SD6,
+		.reg_vsel = AS3722_SD6_VOLTAGE_REG,
+		.reg_enable = AS3722_SD_CONTROL_REG,
+		.enable_bit = AS3722_SD6_ON,
+		.reg_stby_enable = AS3722_REG_STANDBY_MOD1_REG,
+	},
+};
+
+/*
+ * as3722 ldo0 extended input range (0.825-1.25V)  */
+static int as3722_ldo0_is_enabled(struct regulator_dev *dev)
+{
+	u32 val;
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722, AS3722_LDOCONTROL0_REG, &val);
+	return (val & AS3722_LDO0_CTRL_MASK) != 0;
+}
+
+static int as3722_ldo0_enable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	return as3722_set_bits(as3722,
+			       as3722_reg_lookup[rdev_get_id(dev)].reg_enable,
+			       AS3722_LDO0_CTRL_MASK, AS3722_LDO0_ON);
+}
+
+static int as3722_ldo0_disable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	return as3722_set_bits(as3722,
+			       as3722_reg_lookup[rdev_get_id(dev)].reg_enable,
+			       AS3722_LDO0_CTRL_MASK, 0);
+}
+
+static int as3722_ldo0_list_voltage(struct regulator_dev *dev,
+				    unsigned selector)
+{
+	if (selector >= AS3722_LDO0_VSEL_MAX)
+		return -EINVAL;
+
+	return 800000 + (selector + 1) * 25000;
+}
+
+static int as3722_ldo0_map_voltage(struct regulator_dev *dev,
+				   int min_uV, int max_uV)
+{
+	int val, sel;
+
+	if (min_uV > 1250000 || max_uV < 825000)
+		return -EINVAL;
+
+	/* 25mV steps from 0.825V-1.25V */
+	val = (min_uV - 800001) / 25000 + 1;
+	if (val < 1)
+		val = 1;
+
+	sel = (u8) val;
+	if (sel * 25000 + 800000 > max_uV)
+		return -EINVAL;
+
+	BUG_ON(sel * 25000 + 800000 < min_uV);
+	BUG_ON(sel > AS3722_LDO0_VSEL_MAX);
+
+	return sel;
+}
+
+static int as3722_ldo0_get_voltage(struct regulator_dev *dev)
+{
+	u32 val;
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722,
+			as3722_reg_lookup[rdev_get_id(dev)].reg_vsel, &val);
+	val &= AS3722_LDO_VSEL_MASK;
+	if (val > 0)
+		val--;  /* ldo vsel has min value of 1, selector starts
+			   at 0 */
+
+	return as3722_ldo0_list_voltage(dev, val);
+}
+
+static int as3722_ldo0_set_voltage(struct regulator_dev *dev,
+				   int min_uV, int max_uV, unsigned *selector)
+{
+	u8 reg_val;
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	reg_val = as3722_ldo0_map_voltage(dev, min_uV, max_uV);
+
+	return as3722_set_bits(as3722,
+			       as3722_reg_lookup[rdev_get_id(dev)].reg_vsel,
+			       AS3722_LDO_VSEL_MASK, reg_val);
+}
+
+static int as3722_ldo0_get_current_limit(struct regulator_dev *dev)
+{
+	u32 val;
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722, as3722_reg_lookup[rdev_get_id(dev)].reg_vsel,
+			&val);
+	val &= AS3722_LDO_ILIMIT_MASK;
+
+	/* return ldo specific values */
+	if (val)
+		return 300000;
+
+	return 150000;
+}
+
+static int as3722_ldo0_set_current_limit(struct regulator_dev *dev,
+					 int min_uA, int max_uA)
+{
+	u8 val;
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	/* we check the values in case the constraints are wrong */
+	if (min_uA <= 150000 && max_uA >= 150000)
+		val = 0;
+	else if (min_uA > 150000 && max_uA >= 300000)
+		val = AS3722_LDO_ILIMIT_BIT;
+	else
+		return -EINVAL;
+
+	return as3722_set_bits(as3722,
+			       as3722_reg_lookup[rdev_get_id(dev)].reg_vsel,
+			       AS3722_LDO_ILIMIT_MASK, val);
+}
+
+static int as3722_ldo0_set_suspend_voltage(struct regulator_dev *dev, int uV)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+	int sel;
+
+	if (as3722->reg_stby_counter > (AS3722_MAX_REG_STBY_COUNT-1))
+		return -EINVAL;
+
+	sel = as3722_ldo0_map_voltage(dev, uV, uV);
+	if (sel < 0)
+		return -EINVAL;
+
+	/* regulator select */
+	as3722_set_bits(as3722,
+			AS3722_REG0_CONTROL_REG + as3722->reg_stby_counter,
+			AS3722_REG_SELECT_STBY_MASK,
+			as3722_reg_lookup[id].reg_vsel);
+	/* apply voltage */
+	as3722_set_bits(as3722,
+			AS3722_REG0_VOLTAGE_REG + as3722->reg_stby_counter,
+			AS3722_REG_VOLTAGE_STBY_MASK,
+			sel);
+	as3722->reg_stby_counter++;
+
+	return 0;
+}
+
+static int as3722_ldo0_set_suspend_enable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+
+	as3722_set_bits(as3722,
+			as3722_reg_lookup[id].reg_stby_enable,
+			as3722_reg_lookup[id].enable_bit,
+			as3722_reg_lookup[id].enable_bit);
+
+	return 0;
+}
+
+static int as3722_ldo0_set_suspend_disable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+
+	as3722_set_bits(as3722,
+			as3722_reg_lookup[id].reg_stby_enable,
+			as3722_reg_lookup[id].enable_bit,
+			0);
+
+	return 0;
+}
+
+static struct regulator_ops as3722_ldo0_ops = {
+	.is_enabled = as3722_ldo0_is_enabled,
+	.enable = as3722_ldo0_enable,
+	.disable = as3722_ldo0_disable,
+	.list_voltage = as3722_ldo0_list_voltage,
+	.map_voltage = as3722_ldo0_map_voltage,
+	.get_voltage = as3722_ldo0_get_voltage,
+	.set_voltage = as3722_ldo0_set_voltage,
+	.get_current_limit = as3722_ldo0_get_current_limit,
+	.set_current_limit = as3722_ldo0_set_current_limit,
+	.set_suspend_voltage = as3722_ldo0_set_suspend_voltage,
+	.set_suspend_enable = as3722_ldo0_set_suspend_enable,
+	.set_suspend_disable = as3722_ldo0_set_suspend_disable,
+};
+
+/*
+ * as3722 ldo3 low output range (0.61V-1.5V)  */
+static int as3722_ldo3_is_enabled(struct regulator_dev *dev)
+{
+	u32 val = 0;
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722, as3722_reg_lookup[rdev_get_id(dev)].reg_enable,
+			&val);
+	return (val & AS3722_LDO3_CTRL_MASK) != 0;
+}
+
+static int as3722_ldo3_enable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	return as3722_set_bits(as3722,
+			       as3722_reg_lookup[rdev_get_id(dev)].reg_enable,
+			       AS3722_LDO3_CTRL_MASK, AS3722_LDO3_ON);
+}
+
+static int as3722_ldo3_disable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	return as3722_set_bits(as3722,
+			       as3722_reg_lookup[rdev_get_id(dev)].reg_enable,
+			       AS3722_LDO3_CTRL_MASK, 0);
+}
+
+static int as3722_ldo3_list_voltage(struct regulator_dev *dev,
+				    unsigned selector)
+{
+	if (selector >= AS3722_LDO3_VSEL_MAX)
+		return -EINVAL;
+
+	return 600000 + (selector + 1) * 20000;
+}
+
+static int as3722_ldo3_map_voltage(struct regulator_dev *dev,
+				   int min_uV, int max_uV)
+{
+	int val, sel;
+
+	if (min_uV > 1500000 || max_uV < 620000)
+		return -EINVAL;
+
+	/* 20mV steps from 0.62V to 1.5V */
+	val = (min_uV - 600001) / 20000 + 1;
+	if (val < 1)
+		val = 1;
+
+	sel = (u8) val;
+	if (sel * 20000 + 600000 > max_uV)
+		return -EINVAL;
+
+	BUG_ON(sel * 20000 + 600000 < min_uV);
+	BUG_ON(sel > AS3722_LDO3_VSEL_MAX);
+
+	return sel;
+}
+
+static int as3722_ldo3_get_voltage(struct regulator_dev *dev)
+{
+	u32 val;
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722,
+			as3722_reg_lookup[rdev_get_id(dev)].reg_vsel, &val);
+	val &= AS3722_LDO3_VSEL_MASK;
+	if (val > 0)
+		val--;  /* ldo vsel has min value 1, selector starts at
+			   0 */
+
+	return as3722_ldo3_list_voltage(dev, val);
+}
+
+static int as3722_ldo3_set_voltage(struct regulator_dev *dev,
+				   int min_uV, int max_uV, unsigned *selector)
+{
+	u8 reg_val;
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	reg_val = as3722_ldo3_map_voltage(dev, min_uV, max_uV);
+
+	return as3722_set_bits(as3722,
+			       as3722_reg_lookup[rdev_get_id(dev)].reg_vsel,
+			       AS3722_LDO3_VSEL_MASK, reg_val);
+}
+
+static int as3722_ldo3_get_current_limit(struct regulator_dev *dev)
+{
+	return 150000;
+}
+
+static int as3722_ldo3_set_suspend_voltage(struct regulator_dev *dev, int uV)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+	int sel;
+
+	if (as3722->reg_stby_counter > (AS3722_MAX_REG_STBY_COUNT-1))
+		return -EINVAL;
+
+	sel = as3722_ldo3_map_voltage(dev, uV, uV);
+	if (sel < 0)
+		return -EINVAL;
+
+	/* regulator select */
+	as3722_set_bits(as3722,
+			AS3722_REG0_CONTROL_REG + as3722->reg_stby_counter,
+			AS3722_REG_SELECT_STBY_MASK,
+			as3722_reg_lookup[id].reg_vsel);
+	/* apply voltage */
+	as3722_set_bits(as3722,
+			AS3722_REG0_VOLTAGE_REG + as3722->reg_stby_counter,
+			AS3722_REG_VOLTAGE_STBY_MASK,
+			sel);
+	as3722->reg_stby_counter++;
+
+	return 0;
+}
+
+static int as3722_ldo3_set_suspend_enable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+
+	as3722_set_bits(as3722,
+			as3722_reg_lookup[id].reg_stby_enable,
+			as3722_reg_lookup[id].enable_bit,
+			as3722_reg_lookup[id].enable_bit);
+
+	return 0;
+}
+
+static int as3722_ldo3_set_suspend_disable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+
+	as3722_set_bits(as3722,
+			as3722_reg_lookup[id].reg_stby_enable,
+			as3722_reg_lookup[id].enable_bit,
+			0);
+
+	return 0;
+}
+
+static struct regulator_ops as3722_ldo3_ops = {
+	.is_enabled = as3722_ldo3_is_enabled,
+	.enable = as3722_ldo3_enable,
+	.disable = as3722_ldo3_disable,
+	.list_voltage = as3722_ldo3_list_voltage,
+	.map_voltage = as3722_ldo3_map_voltage,
+	.get_voltage = as3722_ldo3_get_voltage,
+	.set_voltage = as3722_ldo3_set_voltage,
+	.get_current_limit = as3722_ldo3_get_current_limit,
+	.set_suspend_voltage = as3722_ldo3_set_suspend_voltage,
+	.set_suspend_enable = as3722_ldo3_set_suspend_enable,
+	.set_suspend_disable = as3722_ldo3_set_suspend_disable,
+};
+
+/*
+ * as3722 ldo 1-2 and 4-11 (0.8V-3.3V)
+ */
+static int as3722_ldo_is_enabled(struct regulator_dev *dev)
+{
+	u32 val = 0;
+	int id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722, as3722_reg_lookup[id].reg_enable, &val);
+	return (val & as3722_reg_lookup[id].enable_bit) != 0;
+}
+
+static int as3722_ldo_enable(struct regulator_dev *dev)
+{
+	int id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	return as3722_set_bits(as3722, as3722_reg_lookup[id].reg_enable,
+			       as3722_reg_lookup[id].enable_bit,
+			       as3722_reg_lookup[id].enable_bit);
+}
+
+static int as3722_ldo_disable(struct regulator_dev *dev)
+{
+	int id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	return as3722_set_bits(as3722, as3722_reg_lookup[id].reg_enable,
+			       as3722_reg_lookup[id].enable_bit, 0);
+}
+
+static int as3722_ldo_list_voltage(struct regulator_dev *dev,
+				   unsigned selector)
+{
+	if (selector >= AS3722_LDO_NUM_VOLT)
+		return -EINVAL;
+
+	selector++;     /* ldo vsel min value is 1, selector starts at 0. */
+	return 800000 + selector * 25000;
+}
+
+static int as3722_ldo_map_voltage(struct regulator_dev *dev,
+				  int min_uV, int max_uV)
+{
+	int val, sel;
+
+	if (min_uV > 3300000 || max_uV < 825000)
+		return -EINVAL;
+
+	if (min_uV <= 1700000) {
+		/* 25mV steps from 0.825V to 1.7V */
+		val = (min_uV - 800001) / 25000 + 1;
+		if (val < 1)
+			val = 1;
+		sel = (u8) val;
+		if (sel * 25000 + 800000 > max_uV)
+			return -EINVAL;
+		BUG_ON(sel * 25000 + 800000 < min_uV);
+	} else {
+		/* 25mV steps from 1.725V to 3.3V */
+		sel = (min_uV - 1700001) / 25000 + 0x40;
+		if ((sel - 0x40) * 25000 + 1725000 > max_uV)
+			return -EINVAL;
+		BUG_ON((sel - 0x40) * 25000 + 1725000 < min_uV);
+	}
+
+	BUG_ON(sel > AS3722_LDO_VSEL_MAX);
+
+	return sel;
+}
+
+static int as3722_ldo_get_voltage(struct regulator_dev *dev)
+{
+	u32 val;
+	int id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722, as3722_reg_lookup[id].reg_vsel, &val);
+	val &= AS3722_LDO_VSEL_MASK;
+	/* ldo vsel has a gap from 0x25 to 0x3F (27 values). */
+	if (val > AS3722_LDO_VSEL_DNU_MAX)
+		val -= 27;
+	/* ldo vsel min value is 1, selector starts at 0. */
+	if (val > 0)
+		val--;
+
+	return as3722_ldo_list_voltage(dev, val);
+}
+
+static int as3722_ldo_set_voltage(struct regulator_dev *dev,
+				  int min_uV, int max_uV, unsigned *selector)
+{
+	u8 reg_val;
+	int id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	reg_val = as3722_ldo_map_voltage(dev, min_uV, max_uV);
+
+	return as3722_set_bits(as3722, as3722_reg_lookup[id].reg_vsel,
+			       AS3722_LDO_VSEL_MASK, reg_val);
+}
+
+static int as3722_ldo_get_current_limit(struct regulator_dev *dev)
+{
+	u32 val;
+	int id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722, as3722_reg_lookup[id].reg_vsel, &val);
+	val &= AS3722_LDO_ILIMIT_MASK;
+
+	/* return ldo specific values */
+	if (val)
+		return 300000;
+
+	return 150000;
+}
+
+static int as3722_ldo_set_current_limit(struct regulator_dev *dev,
+					int min_uA, int max_uA)
+{
+	u8 val;
+	int loweruA = 150000;
+	int id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	/* we check the values in case the constraints are wrong */
+	if (min_uA <= loweruA && max_uA >= loweruA)
+		val = 0;
+	else if (min_uA > loweruA && max_uA >= 300000)
+		val = AS3722_LDO_ILIMIT_BIT;
+	else
+		return -EINVAL;
+
+	return as3722_set_bits(as3722, as3722_reg_lookup[id].reg_vsel,
+			       AS3722_LDO_ILIMIT_MASK, val);
+}
+
+static int as3722_ldo_set_suspend_voltage(struct regulator_dev *dev, int uV)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+	int sel;
+
+	if (as3722->reg_stby_counter > (AS3722_MAX_REG_STBY_COUNT-1))
+		return -EINVAL;
+
+	sel = as3722_ldo_map_voltage(dev, uV, uV);
+	if (sel < 0)
+		return -EINVAL;
+
+	/* regulator select */
+	as3722_set_bits(as3722,
+			AS3722_REG0_CONTROL_REG + as3722->reg_stby_counter,
+			AS3722_REG_SELECT_STBY_MASK,
+			as3722_reg_lookup[id].reg_vsel);
+	/* apply voltage */
+	as3722_set_bits(as3722,
+			AS3722_REG0_VOLTAGE_REG + as3722->reg_stby_counter,
+			AS3722_REG_VOLTAGE_STBY_MASK,
+			sel);
+	as3722->reg_stby_counter++;
+
+	return 0;
+}
+
+static int as3722_ldo_set_suspend_enable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+
+	as3722_set_bits(as3722,
+			as3722_reg_lookup[id].reg_stby_enable,
+			as3722_reg_lookup[id].enable_bit,
+			as3722_reg_lookup[id].enable_bit);
+
+	return 0;
+}
+
+static int as3722_ldo_set_suspend_disable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+
+	as3722_set_bits(as3722,
+			as3722_reg_lookup[id].reg_stby_enable,
+			as3722_reg_lookup[id].enable_bit,
+			0);
+
+	return 0;
+}
+
+static struct regulator_ops as3722_ldo_ops = {
+	.is_enabled = as3722_ldo_is_enabled,
+	.enable = as3722_ldo_enable,
+	.disable = as3722_ldo_disable,
+	.list_voltage = as3722_ldo_list_voltage,
+	.map_voltage = as3722_ldo_map_voltage,
+	.get_voltage = as3722_ldo_get_voltage,
+	.set_voltage = as3722_ldo_set_voltage,
+	.get_current_limit = as3722_ldo_get_current_limit,
+	.set_current_limit = as3722_ldo_set_current_limit,
+	.set_suspend_voltage = as3722_ldo_set_suspend_voltage,
+	.set_suspend_enable = as3722_ldo_set_suspend_enable,
+	.set_suspend_disable = as3722_ldo_set_suspend_disable,
+};
+
+/*
+ * as3722 step down
+ */
+static int as3722_sd_is_enabled(struct regulator_dev *dev)
+{
+	u32 val;
+	u8 id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722, as3722_reg_lookup[id].reg_enable, &val);
+
+	return (val & as3722_reg_lookup[id].enable_bit) != 0;
+}
+
+static int as3722_sd_enable(struct regulator_dev *dev)
+{
+	u8 id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	return as3722_set_bits(as3722, as3722_reg_lookup[id].reg_enable,
+			       as3722_reg_lookup[id].enable_bit,
+			       as3722_reg_lookup[id].enable_bit);
+}
+
+static int as3722_sd_disable(struct regulator_dev *dev)
+{
+	u8 id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	return as3722_set_bits(as3722, as3722_reg_lookup[id].reg_enable,
+			       as3722_reg_lookup[id].enable_bit, 0);
+}
+
+static unsigned int as3722_sd_get_mode(struct regulator_dev *dev)
+{
+	u32 val;
+	u8 reg_id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722, AS3722_SD_CONTROL_REG, &val);
+
+	switch (rdev_get_id(dev)) {
+	case AS3722_SD0:
+		as3722_reg_read(as3722, AS3722_SD0_CONTROL_REG, &val);
+		if ((val & AS3722_SD0_MODE_MASK) == AS3722_SD0_MODE_FAST)
+			return REGULATOR_MODE_FAST;
+		else
+			return REGULATOR_MODE_NORMAL;
+	case AS3722_SD1:
+		as3722_reg_read(as3722, AS3722_SD1_CONTROL_REG, &val);
+		if ((val & AS3722_SD1_MODE_MASK) == AS3722_SD1_MODE_FAST)
+			return REGULATOR_MODE_FAST;
+		else
+			return REGULATOR_MODE_NORMAL;
+	case AS3722_SD2:
+		as3722_reg_read(as3722, AS3722_SD23_CONTROL_REG, &val);
+		if ((val & AS3722_SD2_MODE_MASK) == AS3722_SD2_MODE_FAST)
+			return REGULATOR_MODE_FAST;
+		else
+			return REGULATOR_MODE_NORMAL;
+	case AS3722_SD3:
+		as3722_reg_read(as3722, AS3722_SD23_CONTROL_REG, &val);
+		if ((val & AS3722_SD3_MODE_MASK) == AS3722_SD3_MODE_FAST)
+			return REGULATOR_MODE_FAST;
+		else
+			return REGULATOR_MODE_NORMAL;
+	case AS3722_SD4:
+		as3722_reg_read(as3722, AS3722_SD4_CONTROL_REG, &val);
+		if ((val & AS3722_SD1_MODE_MASK) == AS3722_SD1_MODE_FAST)
+			return REGULATOR_MODE_FAST;
+		else
+			return REGULATOR_MODE_NORMAL;
+	case AS3722_SD5:
+		as3722_reg_read(as3722, AS3722_SD5_CONTROL_REG, &val);
+		if ((val & AS3722_SD1_MODE_MASK) == AS3722_SD1_MODE_FAST)
+			return REGULATOR_MODE_FAST;
+		else
+			return REGULATOR_MODE_NORMAL;
+	case AS3722_SD6:
+		as3722_reg_read(as3722, AS3722_SD6_CONTROL_REG, &val);
+		if ((val & AS3722_SD1_MODE_MASK) == AS3722_SD1_MODE_FAST)
+			return REGULATOR_MODE_FAST;
+		else
+			return REGULATOR_MODE_NORMAL;
+	default:
+		dev_err(as3722->dev, "regulator id %d invalid.\n", reg_id);
+	}
+
+	return -ERANGE;
+}
+
+static int as3722_sd_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+	u8 val, mask, reg;
+	u8 id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	if (mode != REGULATOR_MODE_FAST && mode != REGULATOR_MODE_NORMAL)
+		return -EINVAL;
+
+	switch (id) {
+	case AS3722_SD0:
+		if (mode == REGULATOR_MODE_FAST)
+			val = AS3722_SD0_MODE_FAST;
+		else
+			val = AS3722_SD0_MODE_NORMAL;
+
+		reg = AS3722_SD0_CONTROL_REG;
+		mask = AS3722_SD0_MODE_MASK;
+		break;
+	case AS3722_SD1:
+		if (mode == REGULATOR_MODE_FAST)
+			val = AS3722_SD1_MODE_FAST;
+		else
+			val = AS3722_SD1_MODE_NORMAL;
+
+		reg = AS3722_SD1_CONTROL_REG;
+		mask = AS3722_SD1_MODE_MASK;
+		break;
+	case AS3722_SD2:
+		if (mode == REGULATOR_MODE_FAST)
+			val = AS3722_SD2_MODE_FAST;
+		else
+			val = AS3722_SD2_MODE_NORMAL;
+
+		reg = AS3722_SD23_CONTROL_REG;
+		mask = AS3722_SD2_MODE_MASK;
+		break;
+	case AS3722_SD3:
+		if (mode == REGULATOR_MODE_FAST)
+			val = AS3722_SD3_MODE_FAST;
+		else
+			val = AS3722_SD3_MODE_NORMAL;
+
+		reg = AS3722_SD23_CONTROL_REG;
+		mask = AS3722_SD3_MODE_MASK;
+		break;
+	case AS3722_SD4:
+		if (mode == REGULATOR_MODE_FAST)
+			val = AS3722_SD4_MODE_FAST;
+		else
+			val = AS3722_SD4_MODE_NORMAL;
+
+		reg = AS3722_SD4_CONTROL_REG;
+		mask = AS3722_SD4_MODE_MASK;
+		break;
+	case AS3722_SD5:
+		if (mode == REGULATOR_MODE_FAST)
+			val = AS3722_SD5_MODE_FAST;
+		else
+			val = AS3722_SD5_MODE_NORMAL;
+
+		reg = AS3722_SD5_CONTROL_REG;
+		mask = AS3722_SD5_MODE_MASK;
+		break;
+	case AS3722_SD6:
+		if (mode == REGULATOR_MODE_FAST)
+			val = AS3722_SD6_MODE_FAST;
+		else
+			val = AS3722_SD6_MODE_NORMAL;
+
+		reg = AS3722_SD6_CONTROL_REG;
+		mask = AS3722_SD6_MODE_MASK;
+		break;
+	default:
+		dev_err(as3722->dev, "regulator id %d invalid.\n", id);
+		return -EINVAL;
+	}
+
+	return as3722_set_bits(as3722, reg, mask, val);
+}
+
+static int as3722_sd_list_voltage(struct regulator_dev *dev,
+				  unsigned selector)
+{
+	u8 id = rdev_get_id(dev);
+
+	if (id == AS3722_SD0 || id == AS3722_SD1 || id == AS3722_SD6) {
+		if (selector >= AS3722_SD0_VSEL_MAX)
+			return -EINVAL;
+
+		return 600000 + (selector + 1) * 10000;
+	} else {
+		if (selector > AS3722_SD2_VSEL_MAX)
+			return -EINVAL;
+
+		/* ldo vsel min value is 1, selector starts at 0. */
+		selector++;
+		if (selector <= 0x40)
+			return 600000 + selector * 12500;
+		if (selector <= 0x70)
+			return 1400000 + (selector - 0x40) * 25000;
+		if (selector <= 0x7F)
+			return 2600000 + (selector - 0x70) * 50000;
+
+		return -ERANGE;
+	}
+	return -EINVAL;
+}
+
+static int as3722_sd_lowpower_map_voltage(struct regulator_dev *dev,
+					  int min_uV, int max_uV)
+{
+	int val, sel;
+
+	/*       0 ... 0        0x00 : not allowed as voltage setting
+	 *  610000 ... 1500000: 0x01 - 0x40, 10mV steps */
+
+	if (min_uV > 1500000 || max_uV < 610000)
+		return -EINVAL;
+
+	val = (min_uV - 600001) / 10000 + 1;
+	if (val < 1)
+		val = 1;
+
+	sel = (u8) val;
+	if (sel * 10000 + 600000 > max_uV)
+		return -EINVAL;
+	BUG_ON(sel * 10000 + 600000 < min_uV);
+
+	return sel;
+}
+
+static int as3722_sd_nom_map_voltage(struct regulator_dev *dev,
+				     int min_uV, int max_uV)
+{
+	int val, sel;
+
+	/*       0 ... 0        0x00 : not allowed as voltage setting
+	 *  612500 ... 1400000: 0x01 - 0x40, 12.5mV steps
+	 * 1425000 ... 2600000: 0x41 - 0x70, 25mV steps
+	 * 2650000 ... 3350000: 0x41 - 0x70, 50mV steps */
+
+	if (min_uV > 3350000 || max_uV < 612500)
+		return -EINVAL;
+
+	if (min_uV <= 1400000) {
+		val = (min_uV - 600001) / 12500 + 1;
+		if (val < 1)
+			val = 1;
+
+		sel = (u8) val;
+		if ((sel * 12500) + 600000 > max_uV)
+			return -EINVAL;
+
+		BUG_ON((sel * 12500) + 600000 < min_uV);
+
+	} else if (min_uV <= 2600000) {
+		sel = (min_uV - 1400001) / 25000 + 1;
+
+		if ((sel * 25000) + 1400000 > max_uV)
+			return -EINVAL;
+
+		BUG_ON((sel * 25000) + 1400000 < min_uV);
+
+		sel += 0x40;
+
+	} else {
+
+		sel = (min_uV - 2600001) / 50000 + 1;
+
+		if ((sel * 50000) + 2600000 > max_uV)
+			return -EINVAL;
+
+		BUG_ON((sel * 50000) + 2600000 < min_uV);
+
+		sel += 0x70;
+	}
+
+	return sel;
+}
+static int as3722_sd_map_voltage(struct regulator_dev *dev,
+				 int min_uV, int max_uV)
+{
+	int id = rdev_get_id(dev);
+
+	if (id == AS3722_SD0 || id == AS3722_SD1 || id == AS3722_SD6)
+		return as3722_sd_lowpower_map_voltage(dev, min_uV, max_uV);
+	else
+		return as3722_sd_nom_map_voltage(dev, min_uV, max_uV);
+}
+
+static int as3722_sd_get_voltage(struct regulator_dev *dev)
+{
+	u32 val;
+	u8 id = rdev_get_id(dev);
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+
+	as3722_reg_read(as3722, as3722_reg_lookup[id].reg_vsel, &val);
+	val &= AS3722_SD_VSEL_MASK;
+	if (val > 0)
+		val--;  /* ldo vsel min value is 1, selector starts at
+			   0. */
+
+	return as3722_sd_list_voltage(dev, val);
+}
+
+static int as3722_sd_set_voltage(struct regulator_dev *dev,
+				 int min_uV, int max_uV, unsigned *selector)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	u8 id = rdev_get_id(dev);
+	int sel;
+
+	sel = as3722_sd_map_voltage(dev, min_uV, max_uV);
+
+	return as3722_set_bits(as3722, as3722_reg_lookup[id].reg_vsel,
+			       AS3722_SD_VSEL_MASK, sel);
+}
+
+static int as3722_sd_set_suspend_voltage(struct regulator_dev *dev, int uV)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+	int sel;
+
+	if (as3722->reg_stby_counter > (AS3722_MAX_REG_STBY_COUNT-1))
+		return -EINVAL;
+
+	sel = as3722_sd_map_voltage(dev, uV, uV);
+	if (sel < 0)
+		return -EINVAL;
+
+	/* regulator select */
+	as3722_set_bits(as3722,
+			AS3722_REG0_CONTROL_REG + as3722->reg_stby_counter,
+			AS3722_REG_SELECT_STBY_MASK,
+			as3722_reg_lookup[id].reg_vsel);
+	/* apply voltage */
+	as3722_set_bits(as3722,
+			AS3722_REG0_VOLTAGE_REG + as3722->reg_stby_counter,
+			AS3722_REG_VOLTAGE_STBY_MASK,
+			sel);
+	as3722->reg_stby_counter++;
+
+	return 0;
+}
+
+static int as3722_sd_set_suspend_enable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+
+	as3722_set_bits(as3722,
+			as3722_reg_lookup[id].reg_stby_enable,
+			as3722_reg_lookup[id].enable_bit,
+			as3722_reg_lookup[id].enable_bit);
+
+	return 0;
+}
+
+static int as3722_sd_set_suspend_disable(struct regulator_dev *dev)
+{
+	struct as3722 *as3722 = rdev_get_drvdata(dev);
+	int id = rdev_get_id(dev);
+
+	as3722_set_bits(as3722,
+			as3722_reg_lookup[id].reg_stby_enable,
+			as3722_reg_lookup[id].enable_bit,
+			0);
+
+	return 0;
+}
+
+static struct regulator_ops as3722_sd_ops = {
+	.is_enabled = as3722_sd_is_enabled,
+	.enable = as3722_sd_enable,
+	.disable = as3722_sd_disable,
+	.list_voltage = as3722_sd_list_voltage,
+	.map_voltage = as3722_sd_map_voltage,
+	.get_voltage = as3722_sd_get_voltage,
+	.set_voltage = as3722_sd_set_voltage,
+	.get_mode = as3722_sd_get_mode,
+	.set_mode = as3722_sd_set_mode,
+	.set_suspend_voltage = as3722_sd_set_suspend_voltage,
+	.set_suspend_enable = as3722_sd_set_suspend_enable,
+	.set_suspend_disable = as3722_sd_set_suspend_disable,
+};
+
+static struct regulator_desc regulators[] = {
+	{
+		.name = "as3722-ldo0",
+		.id = AS3722_LDO0,
+		.ops = &as3722_ldo0_ops,
+		.n_voltages = AS3722_LDO0_VSEL_MAX,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo1",
+		.id = AS3722_LDO1,
+		.ops = &as3722_ldo_ops,
+		.n_voltages = AS3722_LDO_NUM_VOLT,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo2",
+		.id = AS3722_LDO2,
+		.ops = &as3722_ldo_ops,
+		.n_voltages = AS3722_LDO_NUM_VOLT,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo3",
+		.id = AS3722_LDO3,
+		.ops = &as3722_ldo3_ops,
+		.n_voltages = AS3722_LDO3_VSEL_MAX,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo4",
+		.id = AS3722_LDO4,
+		.ops = &as3722_ldo_ops,
+		.n_voltages = AS3722_LDO_NUM_VOLT,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo5",
+		.id = AS3722_LDO5,
+		.ops = &as3722_ldo_ops,
+		.n_voltages = AS3722_LDO_NUM_VOLT,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo6",
+		.id = AS3722_LDO6,
+		.ops = &as3722_ldo_ops,
+		.n_voltages = AS3722_LDO_NUM_VOLT,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo7",
+		.id = AS3722_LDO7,
+		.ops = &as3722_ldo_ops,
+		.n_voltages = AS3722_LDO_NUM_VOLT,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo9",
+		.id = AS3722_LDO9,
+		.ops = &as3722_ldo_ops,
+		.n_voltages = AS3722_LDO_NUM_VOLT,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo10",
+		.id = AS3722_LDO10,
+		.ops = &as3722_ldo_ops,
+		.n_voltages = AS3722_LDO_NUM_VOLT,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-ldo11",
+		.id = AS3722_LDO11,
+		.ops = &as3722_ldo_ops,
+		.n_voltages = AS3722_LDO_NUM_VOLT,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-sd0",
+		.id = AS3722_SD0,
+		.ops = &as3722_sd_ops,
+		.n_voltages = AS3722_SD0_VSEL_MAX,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-sd1",
+		.id = AS3722_SD1,
+		.ops = &as3722_sd_ops,
+		.n_voltages = AS3722_SD0_VSEL_MAX,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-sd2",
+		.id = AS3722_SD2,
+		.ops = &as3722_sd_ops,
+		.n_voltages = AS3722_SD2_VSEL_MAX,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-sd3",
+		.id = AS3722_SD3,
+		.ops = &as3722_sd_ops,
+		.n_voltages = AS3722_SD2_VSEL_MAX,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-sd4",
+		.id = AS3722_SD4,
+		.ops = &as3722_sd_ops,
+		.n_voltages = AS3722_SD2_VSEL_MAX,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-sd5",
+		.id = AS3722_SD5,
+		.ops = &as3722_sd_ops,
+		.n_voltages = AS3722_SD2_VSEL_MAX,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "as3722-sd6",
+		.id = AS3722_SD6,
+		.ops = &as3722_sd_ops,
+		.n_voltages = AS3722_SD0_VSEL_MAX,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int as3722_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev;
+	struct regulator_config config = { };
+	struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent);
+	struct as3722_platform_data *pdata = as3722->dev->platform_data;
+	int regulator;
+
+	if (WARN_ON(pdev->id < 0 || pdev->id >= AS3722_NUM_REGULATORS))
+		return -EINVAL;
+
+	config.dev = pdev->dev.parent;
+	config.driver_data = as3722;
+	config.regmap = as3722->regmap;
+
+	for (regulator = 0; regulator < AS3722_NUM_REGULATORS; regulator++) {
+		if (pdata->reg_init[regulator]) {
+			config.init_data = pdata->reg_init[regulator];
+			rdev = regulator_register(&regulators[regulator],
+						  &config);
+			if (IS_ERR(rdev)) {
+				dev_err(&pdev->dev,
+					"as3722 register"
+					"regulator nr %d err\n",
+					regulator);
+				return PTR_ERR(rdev);
+			}
+			as3722->rdevs[regulator] = rdev;
+		}
+	}
+	return 0;
+}
+
+static int as3722_regulator_remove(struct platform_device *pdev)
+{
+	struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent);
+	int regulator;
+
+	if (WARN_ON(pdev->id < 0 || pdev->id >= AS3722_NUM_REGULATORS))
+		return -EINVAL;
+
+	for (regulator = 0; regulator < AS3722_NUM_REGULATORS; regulator++) {
+		if (as3722->rdevs[regulator]) {
+			regulator_unregister(as3722->rdevs[regulator]);
+			as3722->rdevs[regulator] = NULL;
+		}
+	}
+	return 0;
+}
+
+static struct platform_driver as3722_regulator_driver = {
+	.driver = {
+		.name = "as3722-regulator",
+		.owner = THIS_MODULE,
+	},
+	.probe = as3722_regulator_probe,
+	.remove = as3722_regulator_remove,
+};
+
+static int __init as3722_regulator_init(void)
+{
+	return platform_driver_register(&as3722_regulator_driver);
+}
+
+subsys_initcall(as3722_regulator_init);
+
+static void __exit as3722_regulator_exit(void)
+{
+	platform_driver_unregister(&as3722_regulator_driver);
+}
+
+module_exit(as3722_regulator_exit);
+
+MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@....com>");
+MODULE_DESCRIPTION("AS3722 regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:as3722-regulator");
-- 
1.7.2.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ