diff mbox

[v3,Resend,2/3] regulator: Add support for S2MPA01 regulator

Message ID 1394100057-32677-2-git-send-email-sachin.kamat@linaro.org
State Accepted
Headers show

Commit Message

Sachin Kamat March 6, 2014, 10 a.m. UTC
Add support for S2MPA01 voltage and current regulator.

Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Acked-by: Mark Brown <broonie@linaro.org>
---
 drivers/regulator/Kconfig   |    7 +
 drivers/regulator/Makefile  |    1 +
 drivers/regulator/s2mpa01.c |  483 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 491 insertions(+)
 create mode 100644 drivers/regulator/s2mpa01.c

Comments

Krzysztof Kozlowski March 6, 2014, 10:40 a.m. UTC | #1
On Thu, 2014-03-06 at 15:30 +0530, Sachin Kamat wrote:
> Add support for S2MPA01 voltage and current regulator.
> 
> Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
> Acked-by: Mark Brown <broonie@linaro.org>
> ---
>  drivers/regulator/Kconfig   |    7 +
>  drivers/regulator/Makefile  |    1 +
>  drivers/regulator/s2mpa01.c |  483 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 491 insertions(+)
>  create mode 100644 drivers/regulator/s2mpa01.c
> 
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index 4ddfb6c065c7..5b08ea927870 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -425,6 +425,13 @@ config REGULATOR_RC5T583
>  	  through regulator interface. The device supports multiple DCDC/LDO
>  	  outputs which can be controlled by i2c communication.
>  
> +config REGULATOR_S2MPA01
> +	tristate "Samsung S2MPA01 voltage regulator"
> +	depends on MFD_SEC_CORE
> +	help
> +	 This driver controls Samsung S2MPA01 voltage output regulator
> +	 via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs.
> +
>  config REGULATOR_S2MPS11
>  	tristate "Samsung S2MPS11 voltage regulator"
>  	depends on MFD_SEC_CORE
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index c624dbcdcc76..2d14f7580304 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -58,6 +58,7 @@ obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
>  obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
>  obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
>  obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
> +obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
>  obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
>  obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
>  obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
> diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
> new file mode 100644
> index 000000000000..6ac6e8205a05
> --- /dev/null
> +++ b/drivers/regulator/s2mpa01.c
> @@ -0,0 +1,483 @@
> +/*
> + * Copyright (c) 2013 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/err.h>
> +#include <linux/gpio.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/regulator/of_regulator.h>
> +#include <linux/mfd/samsung/core.h>
> +#include <linux/mfd/samsung/s2mpa01.h>
> +
> +#define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators)
> +
> +struct s2mpa01_info {
> +	struct regulator_dev *rdev[S2MPA01_REGULATOR_MAX];

Hi,

It seems that s2mpa01_info->rdev is not used anywhere, except as return
value of devm_regulator_register. I think you can remove it completely.

Beside that, can this driver be merged into existing s2mps11 regulator
driver?

Best regards,
Krzysztof



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Sachin Kamat March 6, 2014, 11:22 a.m. UTC | #2
Hi Krzysztof,

On 6 March 2014 16:10, Krzysztof Kozlowski <k.kozlowski@samsung.com> wrote:
> On Thu, 2014-03-06 at 15:30 +0530, Sachin Kamat wrote:
>> Add support for S2MPA01 voltage and current regulator.

>> +
>> +struct s2mpa01_info {
>> +     struct regulator_dev *rdev[S2MPA01_REGULATOR_MAX];
>
> Hi,
>
> It seems that s2mpa01_info->rdev is not used anywhere, except as return
> value of devm_regulator_register. I think you can remove it completely.

Yes. I will send a follow up patch for this.

>
> Beside that, can this driver be merged into existing s2mps11 regulator
> driver?

Haven't analyzed this yet. Will look into the possibility of consolidation
later.

Thank you for your feedback.
Lee Jones March 10, 2014, 9:35 a.m. UTC | #3
> >> Add support for S2MPA01 voltage and current regulator.
> 
> >> +
> >> +struct s2mpa01_info {
> >> +     struct regulator_dev *rdev[S2MPA01_REGULATOR_MAX];
> >
> > Hi,
> >
> > It seems that s2mpa01_info->rdev is not used anywhere, except as return
> > value of devm_regulator_register. I think you can remove it completely.
> 
> Yes. I will send a follow up patch for this.

Let's not break things and fix them up later. Fix it in this patch.

> > Beside that, can this driver be merged into existing s2mps11 regulator
> > driver?
> 
> Haven't analyzed this yet. Will look into the possibility of consolidation
> later.

As above. If consolidation is possible it should be take care of in
the first instance.
Sachin Kamat March 10, 2014, 9:56 a.m. UTC | #4
Hi Lee,

On 10 March 2014 15:05, Lee Jones <lee.jones@linaro.org> wrote:
>> >> Add support for S2MPA01 voltage and current regulator.
>>
>> >> +
>> >> +struct s2mpa01_info {
>> >> +     struct regulator_dev *rdev[S2MPA01_REGULATOR_MAX];
>> >
>> > Hi,
>> >
>> > It seems that s2mpa01_info->rdev is not used anywhere, except as return
>> > value of devm_regulator_register. I think you can remove it completely.
>>
>> Yes. I will send a follow up patch for this.
>
> Let's not break things and fix them up later. Fix it in this patch.

Nothing is broken in this patch. What is suggested is just a code cleanup.
I did not want to disturb the existing patch set as it is already reviewed
and ready for merging. Anyway I can re-spin with this suggested change.

>
>> > Beside that, can this driver be merged into existing s2mps11 regulator
>> > driver?
>>
>> Haven't analyzed this yet. Will look into the possibility of consolidation
>> later.
>
> As above. If consolidation is possible it should be take care of in
> the first instance.

I need to analyze and see if this is really possible and the extent of
re-usability.
If possible, this might take a while for me before I start
implementing it. Considering
that this patch set is now over 2 months old and consolidations do
happen subsequently
I request you to queue this patch set in its current form (with the
above change if you
deem it necessary to be part of current patch set).
Lee Jones March 10, 2014, 10:38 a.m. UTC | #5
> >> >> Add support for S2MPA01 voltage and current regulator.
> >>
> >> >> +
> >> >> +struct s2mpa01_info {
> >> >> +     struct regulator_dev *rdev[S2MPA01_REGULATOR_MAX];
> >> >
> >> > Hi,
> >> >
> >> > It seems that s2mpa01_info->rdev is not used anywhere, except as return
> >> > value of devm_regulator_register. I think you can remove it completely.
> >>
> >> Yes. I will send a follow up patch for this.
> >
> > Let's not break things and fix them up later. Fix it in this patch.
> 
> Nothing is broken in this patch. What is suggested is just a code cleanup.
> I did not want to disturb the existing patch set as it is already reviewed
> and ready for merging. Anyway I can re-spin with this suggested change.
> 
> >
> >> > Beside that, can this driver be merged into existing s2mps11 regulator
> >> > driver?
> >>
> >> Haven't analyzed this yet. Will look into the possibility of consolidation
> >> later.
> >
> > As above. If consolidation is possible it should be take care of in
> > the first instance.
> 
> I need to analyze and see if this is really possible and the extent of
> re-usability.
> If possible, this might take a while for me before I start
> implementing it. Considering
> that this patch set is now over 2 months old and consolidations do
> happen subsequently
> I request you to queue this patch set in its current form (with the
> above change if you
> deem it necessary to be part of current patch set).

I think the suggestion above should be fixed-up.

Whether to consider consolidation or not is Mark's decision.
Lee Jones March 10, 2014, 10:39 a.m. UTC | #6
> > >> >> Add support for S2MPA01 voltage and current regulator.
> > >>
> > >> >> +
> > >> >> +struct s2mpa01_info {
> > >> >> +     struct regulator_dev *rdev[S2MPA01_REGULATOR_MAX];
> > >> >
> > >> > Hi,
> > >> >
> > >> > It seems that s2mpa01_info->rdev is not used anywhere, except as return
> > >> > value of devm_regulator_register. I think you can remove it completely.
> > >>
> > >> Yes. I will send a follow up patch for this.
> > >
> > > Let's not break things and fix them up later. Fix it in this patch.
> > 
> > Nothing is broken in this patch. What is suggested is just a code cleanup.
> > I did not want to disturb the existing patch set as it is already reviewed
> > and ready for merging. Anyway I can re-spin with this suggested change.
> > 
> > >
> > >> > Beside that, can this driver be merged into existing s2mps11 regulator
> > >> > driver?
> > >>
> > >> Haven't analyzed this yet. Will look into the possibility of consolidation
> > >> later.
> > >
> > > As above. If consolidation is possible it should be take care of in
> > > the first instance.
> > 
> > I need to analyze and see if this is really possible and the extent of
> > re-usability.
> > If possible, this might take a while for me before I start
> > implementing it. Considering
> > that this patch set is now over 2 months old and consolidations do
> > happen subsequently
> > I request you to queue this patch set in its current form (with the
> > above change if you
> > deem it necessary to be part of current patch set).
> 
> I think the suggestion above should be fixed-up.
> 
> Whether to consider consolidation or not is Mark's decision.

Oh, Mark (the maintainer) isn't on CC? I think this is a mistake.
Sachin Kamat March 10, 2014, 10:42 a.m. UTC | #7
On 10 March 2014 16:09, Lee Jones <lee.jones@linaro.org> wrote:
>> > >> >> Add support for S2MPA01 voltage and current regulator.
>> > >>
>> > >> >> +
>> > >> >> +struct s2mpa01_info {
>> > >> >> +     struct regulator_dev *rdev[S2MPA01_REGULATOR_MAX];
>> > >> >
>> > >> > Hi,
>> > >> >
>> > >> > It seems that s2mpa01_info->rdev is not used anywhere, except as return
>> > >> > value of devm_regulator_register. I think you can remove it completely.
>> > >>
>> > >> Yes. I will send a follow up patch for this.
>> > >
>> > > Let's not break things and fix them up later. Fix it in this patch.
>> >
>> > Nothing is broken in this patch. What is suggested is just a code cleanup.
>> > I did not want to disturb the existing patch set as it is already reviewed
>> > and ready for merging. Anyway I can re-spin with this suggested change.
>> >
>> > >
>> > >> > Beside that, can this driver be merged into existing s2mps11 regulator
>> > >> > driver?
>> > >>
>> > >> Haven't analyzed this yet. Will look into the possibility of consolidation
>> > >> later.
>> > >
>> > > As above. If consolidation is possible it should be take care of in
>> > > the first instance.
>> >
>> > I need to analyze and see if this is really possible and the extent of
>> > re-usability.
>> > If possible, this might take a while for me before I start
>> > implementing it. Considering
>> > that this patch set is now over 2 months old and consolidations do
>> > happen subsequently
>> > I request you to queue this patch set in its current form (with the
>> > above change if you
>> > deem it necessary to be part of current patch set).
>>
>> I think the suggestion above should be fixed-up.
>>
>> Whether to consider consolidation or not is Mark's decision.
>
> Oh, Mark (the maintainer) isn't on CC? I think this is a mistake.

Sorry for missing. Thanks for fixing, Lee.
diff mbox

Patch

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 4ddfb6c065c7..5b08ea927870 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -425,6 +425,13 @@  config REGULATOR_RC5T583
 	  through regulator interface. The device supports multiple DCDC/LDO
 	  outputs which can be controlled by i2c communication.
 
+config REGULATOR_S2MPA01
+	tristate "Samsung S2MPA01 voltage regulator"
+	depends on MFD_SEC_CORE
+	help
+	 This driver controls Samsung S2MPA01 voltage output regulator
+	 via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs.
+
 config REGULATOR_S2MPS11
 	tristate "Samsung S2MPS11 voltage regulator"
 	depends on MFD_SEC_CORE
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index c624dbcdcc76..2d14f7580304 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -58,6 +58,7 @@  obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
+obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
new file mode 100644
index 000000000000..6ac6e8205a05
--- /dev/null
+++ b/drivers/regulator/s2mpa01.c
@@ -0,0 +1,483 @@ 
+/*
+ * Copyright (c) 2013 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/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/s2mpa01.h>
+
+#define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators)
+
+struct s2mpa01_info {
+	struct regulator_dev *rdev[S2MPA01_REGULATOR_MAX];
+
+	int ramp_delay24;
+	int ramp_delay3;
+	int ramp_delay5;
+	int ramp_delay16;
+	int ramp_delay7;
+	int ramp_delay8910;
+};
+
+static int get_ramp_delay(int ramp_delay)
+{
+	unsigned char cnt = 0;
+
+	ramp_delay /= 6250;
+
+	while (true) {
+		ramp_delay = ramp_delay >> 1;
+		if (ramp_delay == 0)
+			break;
+		cnt++;
+	}
+
+	if (cnt > 3)
+		cnt = 3;
+
+	return cnt;
+}
+
+static int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+				   unsigned int old_selector,
+				   unsigned int new_selector)
+{
+	struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
+	unsigned int ramp_delay = 0;
+	int old_volt, new_volt;
+
+	switch (rdev->desc->id) {
+	case S2MPA01_BUCK2:
+	case S2MPA01_BUCK4:
+		ramp_delay = s2mpa01->ramp_delay24;
+		break;
+	case S2MPA01_BUCK3:
+		ramp_delay = s2mpa01->ramp_delay3;
+		break;
+	case S2MPA01_BUCK5:
+		ramp_delay = s2mpa01->ramp_delay5;
+		break;
+	case S2MPA01_BUCK1:
+	case S2MPA01_BUCK6:
+		ramp_delay = s2mpa01->ramp_delay16;
+		break;
+	case S2MPA01_BUCK7:
+		ramp_delay = s2mpa01->ramp_delay7;
+		break;
+	case S2MPA01_BUCK8:
+	case S2MPA01_BUCK9:
+	case S2MPA01_BUCK10:
+		ramp_delay = s2mpa01->ramp_delay8910;
+		break;
+	}
+
+	if (ramp_delay == 0)
+		ramp_delay = rdev->desc->ramp_delay;
+
+	old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector);
+	new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector);
+
+	return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+}
+
+static int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+	struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);
+	unsigned int ramp_val, ramp_shift, ramp_reg = S2MPA01_REG_RAMP2;
+	unsigned int ramp_enable = 1, enable_shift = 0;
+	int ret;
+
+	switch (rdev->desc->id) {
+	case S2MPA01_BUCK1:
+		enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT;
+		if (!ramp_delay) {
+			ramp_enable = 0;
+			break;
+		}
+
+		if (ramp_delay > s2mpa01->ramp_delay16)
+			s2mpa01->ramp_delay16 = ramp_delay;
+		else
+			ramp_delay = s2mpa01->ramp_delay16;
+
+		ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
+		ramp_reg = S2MPA01_REG_RAMP1;
+		break;
+	case S2MPA01_BUCK2:
+		enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT;
+		if (!ramp_delay) {
+			ramp_enable = 0;
+			break;
+		}
+
+		if (ramp_delay > s2mpa01->ramp_delay24)
+			s2mpa01->ramp_delay24 = ramp_delay;
+		else
+			ramp_delay = s2mpa01->ramp_delay24;
+
+		ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
+		ramp_reg = S2MPA01_REG_RAMP1;
+		break;
+	case S2MPA01_BUCK3:
+		enable_shift = S2MPA01_BUCK3_RAMP_EN_SHIFT;
+		if (!ramp_delay) {
+			ramp_enable = 0;
+			break;
+		}
+
+		s2mpa01->ramp_delay3 = ramp_delay;
+		ramp_shift = S2MPA01_BUCK3_RAMP_SHIFT;
+		ramp_reg = S2MPA01_REG_RAMP1;
+		break;
+	case S2MPA01_BUCK4:
+		enable_shift = S2MPA01_BUCK4_RAMP_EN_SHIFT;
+		if (!ramp_delay) {
+			ramp_enable = 0;
+			break;
+		}
+
+		if (ramp_delay > s2mpa01->ramp_delay24)
+			s2mpa01->ramp_delay24 = ramp_delay;
+		else
+			ramp_delay = s2mpa01->ramp_delay24;
+
+		ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;
+		ramp_reg = S2MPA01_REG_RAMP1;
+		break;
+	case S2MPA01_BUCK5:
+		s2mpa01->ramp_delay5 = ramp_delay;
+		ramp_shift = S2MPA01_BUCK5_RAMP_SHIFT;
+		break;
+	case S2MPA01_BUCK6:
+		if (ramp_delay > s2mpa01->ramp_delay16)
+			s2mpa01->ramp_delay16 = ramp_delay;
+		else
+			ramp_delay = s2mpa01->ramp_delay16;
+
+		ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;
+		break;
+	case S2MPA01_BUCK7:
+		s2mpa01->ramp_delay7 = ramp_delay;
+		ramp_shift = S2MPA01_BUCK7_RAMP_SHIFT;
+		break;
+	case S2MPA01_BUCK8:
+	case S2MPA01_BUCK9:
+	case S2MPA01_BUCK10:
+		if (ramp_delay > s2mpa01->ramp_delay8910)
+			s2mpa01->ramp_delay8910 = ramp_delay;
+		else
+			ramp_delay = s2mpa01->ramp_delay8910;
+
+		ramp_shift = S2MPA01_BUCK8910_RAMP_SHIFT;
+		break;
+	default:
+		return 0;
+	}
+
+	if (!ramp_enable)
+		goto ramp_disable;
+
+	if (enable_shift) {
+		ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
+					1 << enable_shift, 1 << enable_shift);
+		if (ret) {
+			dev_err(&rdev->dev, "failed to enable ramp rate\n");
+			return ret;
+		}
+	}
+
+	ramp_val = get_ramp_delay(ramp_delay);
+
+	return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift,
+				  ramp_val << ramp_shift);
+
+ramp_disable:
+	return regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
+				  1 << enable_shift, 0);
+}
+
+static struct regulator_ops s2mpa01_ldo_ops = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops s2mpa01_buck_ops = {
+	.list_voltage		= regulator_list_voltage_linear,
+	.map_voltage		= regulator_map_voltage_linear,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.set_voltage_time_sel	= s2mpa01_regulator_set_voltage_time_sel,
+	.set_ramp_delay		= s2mpa01_set_ramp_delay,
+};
+
+#define regulator_desc_ldo1(num)	{		\
+	.name		= "LDO"#num,			\
+	.id		= S2MPA01_LDO##num,		\
+	.ops		= &s2mpa01_ldo_ops,		\
+	.type		= REGULATOR_VOLTAGE,		\
+	.owner		= THIS_MODULE,			\
+	.min_uV		= S2MPA01_LDO_MIN,		\
+	.uV_step	= S2MPA01_LDO_STEP1,		\
+	.n_voltages	= S2MPA01_LDO_N_VOLTAGES,	\
+	.vsel_reg	= S2MPA01_REG_L1CTRL + num - 1,	\
+	.vsel_mask	= S2MPA01_LDO_VSEL_MASK,	\
+	.enable_reg	= S2MPA01_REG_L1CTRL + num - 1,	\
+	.enable_mask	= S2MPA01_ENABLE_MASK		\
+}
+#define regulator_desc_ldo2(num)	{		\
+	.name		= "LDO"#num,			\
+	.id		= S2MPA01_LDO##num,		\
+	.ops		= &s2mpa01_ldo_ops,		\
+	.type		= REGULATOR_VOLTAGE,		\
+	.owner		= THIS_MODULE,			\
+	.min_uV		= S2MPA01_LDO_MIN,		\
+	.uV_step	= S2MPA01_LDO_STEP2,		\
+	.n_voltages	= S2MPA01_LDO_N_VOLTAGES,	\
+	.vsel_reg	= S2MPA01_REG_L1CTRL + num - 1,	\
+	.vsel_mask	= S2MPA01_LDO_VSEL_MASK,	\
+	.enable_reg	= S2MPA01_REG_L1CTRL + num - 1,	\
+	.enable_mask	= S2MPA01_ENABLE_MASK		\
+}
+
+#define regulator_desc_buck1_4(num)	{			\
+	.name		= "BUCK"#num,				\
+	.id		= S2MPA01_BUCK##num,			\
+	.ops		= &s2mpa01_buck_ops,			\
+	.type		= REGULATOR_VOLTAGE,			\
+	.owner		= THIS_MODULE,				\
+	.min_uV		= S2MPA01_BUCK_MIN1,			\
+	.uV_step	= S2MPA01_BUCK_STEP1,			\
+	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\
+	.ramp_delay	= S2MPA01_RAMP_DELAY,			\
+	.vsel_reg	= S2MPA01_REG_B1CTRL2 + (num - 1) * 2,	\
+	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\
+	.enable_reg	= S2MPA01_REG_B1CTRL1 + (num - 1) * 2,	\
+	.enable_mask	= S2MPA01_ENABLE_MASK			\
+}
+
+#define regulator_desc_buck5	{				\
+	.name		= "BUCK5",				\
+	.id		= S2MPA01_BUCK5,			\
+	.ops		= &s2mpa01_buck_ops,			\
+	.type		= REGULATOR_VOLTAGE,			\
+	.owner		= THIS_MODULE,				\
+	.min_uV		= S2MPA01_BUCK_MIN2,			\
+	.uV_step	= S2MPA01_BUCK_STEP1,			\
+	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\
+	.ramp_delay	= S2MPA01_RAMP_DELAY,			\
+	.vsel_reg	= S2MPA01_REG_B5CTRL2,			\
+	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\
+	.enable_reg	= S2MPA01_REG_B5CTRL1,			\
+	.enable_mask	= S2MPA01_ENABLE_MASK			\
+}
+
+#define regulator_desc_buck6_7(num)	{			\
+	.name		= "BUCK"#num,				\
+	.id		= S2MPA01_BUCK##num,			\
+	.ops		= &s2mpa01_buck_ops,			\
+	.type		= REGULATOR_VOLTAGE,			\
+	.owner		= THIS_MODULE,				\
+	.min_uV		= S2MPA01_BUCK_MIN1,			\
+	.uV_step	= S2MPA01_BUCK_STEP1,			\
+	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\
+	.ramp_delay	= S2MPA01_RAMP_DELAY,			\
+	.vsel_reg	= S2MPA01_REG_B6CTRL2 + (num - 6) * 2,	\
+	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\
+	.enable_reg	= S2MPA01_REG_B6CTRL1 + (num - 6) * 2,	\
+	.enable_mask	= S2MPA01_ENABLE_MASK			\
+}
+
+#define regulator_desc_buck8	{				\
+	.name		= "BUCK8",				\
+	.id		= S2MPA01_BUCK8,			\
+	.ops		= &s2mpa01_buck_ops,			\
+	.type		= REGULATOR_VOLTAGE,			\
+	.owner		= THIS_MODULE,				\
+	.min_uV		= S2MPA01_BUCK_MIN2,			\
+	.uV_step	= S2MPA01_BUCK_STEP2,			\
+	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\
+	.ramp_delay	= S2MPA01_RAMP_DELAY,			\
+	.vsel_reg	= S2MPA01_REG_B8CTRL2,			\
+	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\
+	.enable_reg	= S2MPA01_REG_B8CTRL1,			\
+	.enable_mask	= S2MPA01_ENABLE_MASK			\
+}
+
+#define regulator_desc_buck9	{				\
+	.name		= "BUCK9",				\
+	.id		= S2MPA01_BUCK9,			\
+	.ops		= &s2mpa01_buck_ops,			\
+	.type		= REGULATOR_VOLTAGE,			\
+	.owner		= THIS_MODULE,				\
+	.min_uV		= S2MPA01_BUCK_MIN4,			\
+	.uV_step	= S2MPA01_BUCK_STEP2,			\
+	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\
+	.ramp_delay	= S2MPA01_RAMP_DELAY,			\
+	.vsel_reg	= S2MPA01_REG_B9CTRL2,			\
+	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\
+	.enable_reg	= S2MPA01_REG_B9CTRL1,			\
+	.enable_mask	= S2MPA01_ENABLE_MASK			\
+}
+
+#define regulator_desc_buck10	{				\
+	.name		= "BUCK10",				\
+	.id		= S2MPA01_BUCK10,			\
+	.ops		= &s2mpa01_buck_ops,			\
+	.type		= REGULATOR_VOLTAGE,			\
+	.owner		= THIS_MODULE,				\
+	.min_uV		= S2MPA01_BUCK_MIN3,			\
+	.uV_step	= S2MPA01_BUCK_STEP2,			\
+	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\
+	.ramp_delay	= S2MPA01_RAMP_DELAY,			\
+	.vsel_reg	= S2MPA01_REG_B10CTRL2,			\
+	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\
+	.enable_reg	= S2MPA01_REG_B10CTRL1,			\
+	.enable_mask	= S2MPA01_ENABLE_MASK			\
+}
+
+static struct regulator_desc regulators[] = {
+	regulator_desc_ldo2(1),
+	regulator_desc_ldo1(2),
+	regulator_desc_ldo1(3),
+	regulator_desc_ldo1(4),
+	regulator_desc_ldo1(5),
+	regulator_desc_ldo2(6),
+	regulator_desc_ldo1(7),
+	regulator_desc_ldo1(8),
+	regulator_desc_ldo1(9),
+	regulator_desc_ldo1(10),
+	regulator_desc_ldo2(11),
+	regulator_desc_ldo1(12),
+	regulator_desc_ldo1(13),
+	regulator_desc_ldo1(14),
+	regulator_desc_ldo1(15),
+	regulator_desc_ldo1(16),
+	regulator_desc_ldo1(17),
+	regulator_desc_ldo1(18),
+	regulator_desc_ldo1(19),
+	regulator_desc_ldo1(20),
+	regulator_desc_ldo1(21),
+	regulator_desc_ldo2(22),
+	regulator_desc_ldo2(23),
+	regulator_desc_ldo1(24),
+	regulator_desc_ldo1(25),
+	regulator_desc_ldo1(26),
+	regulator_desc_buck1_4(1),
+	regulator_desc_buck1_4(2),
+	regulator_desc_buck1_4(3),
+	regulator_desc_buck1_4(4),
+	regulator_desc_buck5,
+	regulator_desc_buck6_7(6),
+	regulator_desc_buck6_7(7),
+	regulator_desc_buck8,
+	regulator_desc_buck9,
+	regulator_desc_buck10,
+};
+
+static int s2mpa01_pmic_probe(struct platform_device *pdev)
+{
+	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX];
+	struct device_node *reg_np = NULL;
+	struct regulator_config config = { };
+	struct s2mpa01_info *s2mpa01;
+	int i, ret;
+
+	s2mpa01 = devm_kzalloc(&pdev->dev, sizeof(*s2mpa01), GFP_KERNEL);
+	if (!s2mpa01)
+		return -ENOMEM;
+
+	for (i = 0; i < S2MPA01_REGULATOR_CNT; i++)
+		rdata[i].name = regulators[i].name;
+
+	if (iodev->dev->of_node) {
+		reg_np = of_get_child_by_name(iodev->dev->of_node,
+							"regulators");
+			if (!reg_np) {
+				dev_err(&pdev->dev,
+					"could not find regulators sub-node\n");
+				return -EINVAL;
+			}
+
+		of_regulator_match(&pdev->dev, reg_np, rdata,
+						S2MPA01_REGULATOR_MAX);
+		of_node_put(reg_np);
+	}
+
+	platform_set_drvdata(pdev, s2mpa01);
+
+	config.dev = &pdev->dev;
+	config.regmap = iodev->regmap_pmic;
+	config.driver_data = s2mpa01;
+
+	for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) {
+		if (pdata)
+			config.init_data = pdata->regulators[i].initdata;
+		else
+			config.init_data = rdata[i].init_data;
+
+		if (reg_np)
+			config.of_node = rdata[i].of_node;
+
+		s2mpa01->rdev[i] = devm_regulator_register(&pdev->dev,
+						&regulators[i], &config);
+		if (IS_ERR(s2mpa01->rdev[i])) {
+			ret = PTR_ERR(s2mpa01->rdev[i]);
+			dev_err(&pdev->dev, "regulator init failed for %d\n",
+				i);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id s2mpa01_pmic_id[] = {
+	{ "s2mpa01-pmic", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id);
+
+static struct platform_driver s2mpa01_pmic_driver = {
+	.driver = {
+		.name = "s2mpa01-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = s2mpa01_pmic_probe,
+	.id_table = s2mpa01_pmic_id,
+};
+
+module_platform_driver(s2mpa01_pmic_driver);
+
+/* Module information */
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_AUTHOR("Sachin Kamat <sachin.kamat@samsung.com>");
+MODULE_DESCRIPTION("SAMSUNG S2MPA01 Regulator Driver");
+MODULE_LICENSE("GPL");