diff mbox

[v7,3/7] regulator: add pbias regulator support

Message ID 1387560955-6547-4-git-send-email-balajitk@ti.com
State Superseded, archived
Headers show

Commit Message

balajitk@ti.com Dec. 20, 2013, 5:35 p.m. UTC
pbias register controls internal power supply to sd card i/o pads
in most OMAPs (OMAP2-5, DRA7).
Control bits for selecting voltage level and
enabling/disabling are in the same PBIAS register.

Signed-off-by: Balaji T K <balajitk@ti.com>
---
 .../bindings/regulator/pbias-regulator.txt         |   16 ++
 drivers/regulator/Kconfig                          |    9 +
 drivers/regulator/Makefile                         |    1 +
 drivers/regulator/pbias-regulator.c                |  261 ++++++++++++++++++++
 4 files changed, 287 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/regulator/pbias-regulator.txt
 create mode 100644 drivers/regulator/pbias-regulator.c

Comments

Tony Lindgren Dec. 20, 2013, 11:39 p.m. UTC | #1
* Balaji T K <balajitk@ti.com> [131220 09:37]:
> +static const struct pbias_reg_info pbias_mmc_omap2430 = {
> +	.enable = BIT(1),
> +	.enable_mask = BIT(1),
> +	.vmode = BIT(0),
> +	.enable_time = 100,
> +	.name = "pbias_mmc_omap2430"
> +};
> +
> +static const struct pbias_reg_info pbias_sim_omap3 = {
> +	.enable = BIT(9),
> +	.enable_mask = BIT(9),
> +	.vmode = BIT(8),
> +	.enable_time = 100,
> +	.name = "pbias_sim_omap3"
> +};
> +
> +static const struct pbias_reg_info pbias_mmc_omap4 = {
> +	.enable = BIT(26) | BIT(22),
> +	.enable_mask = BIT(26) | BIT(25) | BIT(22),
> +	.vmode = BIT(21),
> +	.enable_time = 10,
> +	.name = "pbias_mmc_omap4"
> +};
> +
> +static const struct pbias_reg_info pbias_mmc_omap5 = {
> +	.enable = BIT(27) | BIT(26),
> +	.enable_mask = BIT(27) | BIT(25) | BIT(26),
> +	.vmode = BIT(21),
> +	.enable_time = 100,
> +	.name = "pbias_mmc_omap5"
> +};

Should the enable_time be 100 for omap4 like for the others?

Other than that:

Acked-by: Tony Lindgren <tony@atomide.com>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
balajitk@ti.com Dec. 24, 2013, 4:11 p.m. UTC | #2
On Saturday 21 December 2013 05:09 AM, Tony Lindgren wrote:
> * Balaji T K <balajitk@ti.com> [131220 09:37]:
>> +static const struct pbias_reg_info pbias_mmc_omap2430 = {
>> +	.enable = BIT(1),
>> +	.enable_mask = BIT(1),
>> +	.vmode = BIT(0),
>> +	.enable_time = 100,
>> +	.name = "pbias_mmc_omap2430"
>> +};
>> +
>> +static const struct pbias_reg_info pbias_sim_omap3 = {
>> +	.enable = BIT(9),
>> +	.enable_mask = BIT(9),
>> +	.vmode = BIT(8),
>> +	.enable_time = 100,
>> +	.name = "pbias_sim_omap3"
>> +};
>> +
>> +static const struct pbias_reg_info pbias_mmc_omap4 = {
>> +	.enable = BIT(26) | BIT(22),
>> +	.enable_mask = BIT(26) | BIT(25) | BIT(22),
>> +	.vmode = BIT(21),
>> +	.enable_time = 10,
>> +	.name = "pbias_mmc_omap4"
>> +};
>> +
>> +static const struct pbias_reg_info pbias_mmc_omap5 = {
>> +	.enable = BIT(27) | BIT(26),
>> +	.enable_mask = BIT(27) | BIT(25) | BIT(26),
>> +	.vmode = BIT(21),
>> +	.enable_time = 100,
>> +	.name = "pbias_mmc_omap5"
>> +};
>
> Should the enable_time be 100 for omap4 like for the others?
>

enable_time of 10 is fine for omap4

> Other than that:
>
> Acked-by: Tony Lindgren <tony@atomide.com>
>

Thanks Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Rutland Jan. 6, 2014, 6:16 p.m. UTC | #3
On Fri, Dec 20, 2013 at 05:35:51PM +0000, Balaji T K wrote:
> pbias register controls internal power supply to sd card i/o pads
> in most OMAPs (OMAP2-5, DRA7).
> Control bits for selecting voltage level and
> enabling/disabling are in the same PBIAS register.
> 
> Signed-off-by: Balaji T K <balajitk@ti.com>
> ---
>  .../bindings/regulator/pbias-regulator.txt         |   16 ++
>  drivers/regulator/Kconfig                          |    9 +
>  drivers/regulator/Makefile                         |    1 +
>  drivers/regulator/pbias-regulator.c                |  261 ++++++++++++++++++++
>  4 files changed, 287 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/regulator/pbias-regulator.txt
>  create mode 100644 drivers/regulator/pbias-regulator.c
> 
> diff --git a/Documentation/devicetree/bindings/regulator/pbias-regulator.txt b/Documentation/devicetree/bindings/regulator/pbias-regulator.txt
> new file mode 100644
> index 0000000..359d3f9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/pbias-regulator.txt
> @@ -0,0 +1,16 @@
> +PBIAS internal regulator for SD card dual voltage i/o pads on OMAP SoCs.
> +
> +Required properties:
> +- compatible:
> +  - "ti,pbias-omap" for OMAP2, OMAP3, OMAP4, OMAP5, DRA7
> +
> +Optional properties:
> +- Any optional property defined in bindings/regulator/regulator.txt
> +
> +Example:
> +
> +		pbias_regulator: pbias_regulator {
> +			regulator-name = "pbias_mmc_omap4";
> +			regulator-min-microvolt = <1800000>;
> +			regulator-max-microvolt = <3000000>;
> +	};

This doesn't look like a full example. I don't see the required
compatible string.

[...]

> +static struct of_regulator_match pbias_matches[] = {
> +	{ .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430},
> +	{ .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3},
> +	{ .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4},
> +	{ .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5},
> +};

These weren't documented.

[...]

> +static int pbias_regulator_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device_node *dev_node;
> +	struct pbias_regulator_data *drvdata;
> +	struct resource *res;
> +	struct regulator_config cfg = { };
> +	struct regmap *syscon;
> +	const struct pbias_reg_info *info;
> +	int ret = 0;
> +	int count, idx, data_idx = 0;
> +
> +	count = of_regulator_match(&pdev->dev, np, pbias_matches,
> +						PBIAS_NUM_REGS);
> +	if (count < 0)
> +		return count;
> +
> +	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data)
> +			       * count, GFP_KERNEL);
> +	if (drvdata == NULL) {
> +		dev_err(&pdev->dev, "Failed to allocate device data\n");
> +		return -ENOMEM;
> +	}
> +
> +	dev_node = of_get_parent(np);
> +	if (!dev_node)
> +		return -ENODEV;
> +
> +	syscon = syscon_node_to_regmap(dev_node);

If we're relying on a particular parent node, that _must_ be described
in the binding.

> +	of_node_put(dev_node);
> +	if (IS_ERR(syscon))
> +		return PTR_ERR(syscon);
> +
> +	cfg.dev = &pdev->dev;
> +
> +	for (idx = 0; idx < PBIAS_NUM_REGS, data_idx < count; idx++) {
> +		if (!pbias_matches[idx].init_data ||
> +			!pbias_matches[idx].of_node)
> +			continue;
> +
> +		info = pbias_matches[idx].driver_data;
> +		if (!info)
> +			return -ENODEV;
> +
> +		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

A reg entry was not mentioned in the binding.

Why is this inside the loop? It's grabbing the reg from the parent, not
each of the children it's walking over.

Thanks,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
balajitk@ti.com Jan. 7, 2014, 10:09 a.m. UTC | #4
On Monday 06 January 2014 11:46 PM, Mark Rutland wrote:
> On Fri, Dec 20, 2013 at 05:35:51PM +0000, Balaji T K wrote:
>> pbias register controls internal power supply to sd card i/o pads
>> in most OMAPs (OMAP2-5, DRA7).
>> Control bits for selecting voltage level and
>> enabling/disabling are in the same PBIAS register.
>>
>> Signed-off-by: Balaji T K <balajitk@ti.com>
>> ---
>>   .../bindings/regulator/pbias-regulator.txt         |   16 ++
>>   drivers/regulator/Kconfig                          |    9 +
>>   drivers/regulator/Makefile                         |    1 +
>>   drivers/regulator/pbias-regulator.c                |  261 ++++++++++++++++++++
>>   4 files changed, 287 insertions(+), 0 deletions(-)
>>   create mode 100644 Documentation/devicetree/bindings/regulator/pbias-regulator.txt
>>   create mode 100644 drivers/regulator/pbias-regulator.c
>>
>> diff --git a/Documentation/devicetree/bindings/regulator/pbias-regulator.txt b/Documentation/devicetree/bindings/regulator/pbias-regulator.txt
>> new file mode 100644
>> index 0000000..359d3f9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/regulator/pbias-regulator.txt
>> @@ -0,0 +1,16 @@
>> +PBIAS internal regulator for SD card dual voltage i/o pads on OMAP SoCs.
>> +
>> +Required properties:
>> +- compatible:
>> +  - "ti,pbias-omap" for OMAP2, OMAP3, OMAP4, OMAP5, DRA7
>> +
>> +Optional properties:
>> +- Any optional property defined in bindings/regulator/regulator.txt
>> +
>> +Example:
>> +
>> +		pbias_regulator: pbias_regulator {
>> +			regulator-name = "pbias_mmc_omap4";
>> +			regulator-min-microvolt = <1800000>;
>> +			regulator-max-microvolt = <3000000>;
>> +	};
>
> This doesn't look like a full example. I don't see the required
> compatible string.
>

Thanks for pointing, I missed it, will add to example.

> [...]
>
>> +static struct of_regulator_match pbias_matches[] = {
>> +	{ .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430},
>> +	{ .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3},
>> +	{ .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4},
>> +	{ .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5},
>> +};
>
> These weren't documented.

Ok, will add it

>
> [...]
>
>> +static int pbias_regulator_probe(struct platform_device *pdev)
>> +{
>> +	struct device_node *np = pdev->dev.of_node;
>> +	struct device_node *dev_node;
>> +	struct pbias_regulator_data *drvdata;
>> +	struct resource *res;
>> +	struct regulator_config cfg = { };
>> +	struct regmap *syscon;
>> +	const struct pbias_reg_info *info;
>> +	int ret = 0;
>> +	int count, idx, data_idx = 0;
>> +
>> +	count = of_regulator_match(&pdev->dev, np, pbias_matches,
>> +						PBIAS_NUM_REGS);
>> +	if (count < 0)
>> +		return count;
>> +
>> +	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data)
>> +			       * count, GFP_KERNEL);
>> +	if (drvdata == NULL) {
>> +		dev_err(&pdev->dev, "Failed to allocate device data\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	dev_node = of_get_parent(np);
>> +	if (!dev_node)
>> +		return -ENODEV;
>> +
>> +	syscon = syscon_node_to_regmap(dev_node);
>
> If we're relying on a particular parent node, that _must_ be described
> in the binding.

Ok
>
>> +	of_node_put(dev_node);
>> +	if (IS_ERR(syscon))
>> +		return PTR_ERR(syscon);
>> +
>> +	cfg.dev = &pdev->dev;
>> +
>> +	for (idx = 0; idx < PBIAS_NUM_REGS, data_idx < count; idx++) {
>> +		if (!pbias_matches[idx].init_data ||
>> +			!pbias_matches[idx].of_node)
>> +			continue;
>> +
>> +		info = pbias_matches[idx].driver_data;
>> +		if (!info)
>> +			return -ENODEV;
>> +
>> +		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>
> A reg entry was not mentioned in the binding.

Ok, will add it

>
> Why is this inside the loop? It's grabbing the reg from the parent, not
> each of the children it's walking over.
>

The reg property is same for each children and is needed for each regulator.
It is for the case where a single register can control 2
regulators as in OMAP3 (mmc and sim). In other SoCs, only one regulator
of "ti,pbias-omap" compatible exists in the pbias register.

> Thanks,
> Mark.
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/regulator/pbias-regulator.txt b/Documentation/devicetree/bindings/regulator/pbias-regulator.txt
new file mode 100644
index 0000000..359d3f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/pbias-regulator.txt
@@ -0,0 +1,16 @@ 
+PBIAS internal regulator for SD card dual voltage i/o pads on OMAP SoCs.
+
+Required properties:
+- compatible:
+  - "ti,pbias-omap" for OMAP2, OMAP3, OMAP4, OMAP5, DRA7
+
+Optional properties:
+- Any optional property defined in bindings/regulator/regulator.txt
+
+Example:
+
+		pbias_regulator: pbias_regulator {
+			regulator-name = "pbias_mmc_omap4";
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <3000000>;
+	};
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index ce785f4..741e8fb 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -369,6 +369,15 @@  config REGULATOR_PALMAS
 	  on the muxing. This is handled automatically in the driver by
 	  reading the mux info from OTP.
 
+config REGULATOR_PBIAS
+	tristate "PBIAS OMAP regulator driver"
+	depends on (ARCH_OMAP || COMPILE_TEST) && MFD_SYSCON
+	help
+	 Say y here to support pbias regulator for mmc1:SD card i/o
+	 on OMAP SoCs.
+	 This driver provides support for OMAP pbias modelled
+	 regulators.
+
 config REGULATOR_PCAP
 	tristate "Motorola PCAP2 regulator driver"
 	depends on EZX_PCAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 01c597e..16000fa 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -52,6 +52,7 @@  obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
 obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
 obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
+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
diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c
new file mode 100644
index 0000000..992ec09
--- /dev/null
+++ b/drivers/regulator/pbias-regulator.c
@@ -0,0 +1,261 @@ 
+/*
+ * pbias-regulator.c
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Balaji T K <balajitk@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/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+struct pbias_reg_info {
+	u32 enable;
+	u32 enable_mask;
+	u32 vmode;
+	unsigned int enable_time;
+	char *name;
+};
+
+struct pbias_regulator_data {
+	struct regulator_desc desc;
+	void __iomem *pbias_addr;
+	unsigned int pbias_reg;
+	struct regulator_dev *dev;
+	struct regmap *syscon;
+	const struct pbias_reg_info *info;
+	int voltage;
+};
+
+static int pbias_regulator_set_voltage(struct regulator_dev *dev,
+			int min_uV, int max_uV, unsigned *selector)
+{
+	struct pbias_regulator_data *data = rdev_get_drvdata(dev);
+	const struct pbias_reg_info *info = data->info;
+	int ret, vmode;
+
+	if (min_uV <= 1800000)
+		vmode = 0;
+	else if (min_uV > 1800000)
+		vmode = info->vmode;
+
+	ret = regmap_update_bits(data->syscon, data->pbias_reg,
+						info->vmode, vmode);
+
+	return ret;
+}
+
+static int pbias_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+	const struct pbias_reg_info *info = data->info;
+	int value, voltage;
+
+	regmap_read(data->syscon, data->pbias_reg, &value);
+	value &= info->vmode;
+
+	voltage = value ? 3000000 : 1800000;
+
+	return voltage;
+}
+
+static int pbias_regulator_enable(struct regulator_dev *rdev)
+{
+	struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+	const struct pbias_reg_info *info = data->info;
+	int ret;
+
+	ret = regmap_update_bits(data->syscon, data->pbias_reg,
+					info->enable_mask, info->enable);
+
+	return ret;
+}
+
+static int pbias_regulator_disable(struct regulator_dev *rdev)
+{
+	struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+	const struct pbias_reg_info *info = data->info;
+	int ret;
+
+	ret = regmap_update_bits(data->syscon, data->pbias_reg,
+						info->enable_mask, 0);
+	return ret;
+}
+
+static int pbias_regulator_is_enable(struct regulator_dev *rdev)
+{
+	struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+	const struct pbias_reg_info *info = data->info;
+	int value;
+
+	regmap_read(data->syscon, data->pbias_reg, &value);
+
+	return (value & info->enable_mask) == info->enable_mask;
+}
+
+static struct regulator_ops pbias_regulator_voltage_ops = {
+	.set_voltage	= pbias_regulator_set_voltage,
+	.get_voltage	= pbias_regulator_get_voltage,
+	.enable		= pbias_regulator_enable,
+	.disable	= pbias_regulator_disable,
+	.is_enabled	= pbias_regulator_is_enable,
+};
+
+static const struct pbias_reg_info pbias_mmc_omap2430 = {
+	.enable = BIT(1),
+	.enable_mask = BIT(1),
+	.vmode = BIT(0),
+	.enable_time = 100,
+	.name = "pbias_mmc_omap2430"
+};
+
+static const struct pbias_reg_info pbias_sim_omap3 = {
+	.enable = BIT(9),
+	.enable_mask = BIT(9),
+	.vmode = BIT(8),
+	.enable_time = 100,
+	.name = "pbias_sim_omap3"
+};
+
+static const struct pbias_reg_info pbias_mmc_omap4 = {
+	.enable = BIT(26) | BIT(22),
+	.enable_mask = BIT(26) | BIT(25) | BIT(22),
+	.vmode = BIT(21),
+	.enable_time = 10,
+	.name = "pbias_mmc_omap4"
+};
+
+static const struct pbias_reg_info pbias_mmc_omap5 = {
+	.enable = BIT(27) | BIT(26),
+	.enable_mask = BIT(27) | BIT(25) | BIT(26),
+	.vmode = BIT(21),
+	.enable_time = 100,
+	.name = "pbias_mmc_omap5"
+};
+
+static struct of_regulator_match pbias_matches[] = {
+	{ .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430},
+	{ .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3},
+	{ .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4},
+	{ .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5},
+};
+#define PBIAS_NUM_REGS	ARRAY_SIZE(pbias_matches)
+
+static const struct of_device_id pbias_of_match[] = {
+	{ .compatible = "ti,pbias-omap", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, pbias_of_match);
+
+static int pbias_regulator_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *dev_node;
+	struct pbias_regulator_data *drvdata;
+	struct resource *res;
+	struct regulator_config cfg = { };
+	struct regmap *syscon;
+	const struct pbias_reg_info *info;
+	int ret = 0;
+	int count, idx, data_idx = 0;
+
+	count = of_regulator_match(&pdev->dev, np, pbias_matches,
+						PBIAS_NUM_REGS);
+	if (count < 0)
+		return count;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data)
+			       * count, GFP_KERNEL);
+	if (drvdata == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate device data\n");
+		return -ENOMEM;
+	}
+
+	dev_node = of_get_parent(np);
+	if (!dev_node)
+		return -ENODEV;
+
+	syscon = syscon_node_to_regmap(dev_node);
+	of_node_put(dev_node);
+	if (IS_ERR(syscon))
+		return PTR_ERR(syscon);
+
+	cfg.dev = &pdev->dev;
+
+	for (idx = 0; idx < PBIAS_NUM_REGS, data_idx < count; idx++) {
+		if (!pbias_matches[idx].init_data ||
+			!pbias_matches[idx].of_node)
+			continue;
+
+		info = pbias_matches[idx].driver_data;
+		if (!info)
+			return -ENODEV;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!res)
+			return -EINVAL;
+
+		drvdata[data_idx].pbias_reg = res->start;
+		drvdata[data_idx].syscon = syscon;
+		drvdata[data_idx].info = info;
+		drvdata[data_idx].desc.name = info->name;
+		drvdata[data_idx].desc.owner = THIS_MODULE;
+		drvdata[data_idx].desc.type = REGULATOR_VOLTAGE;
+		drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops;
+		drvdata[data_idx].desc.n_voltages = 2;
+		drvdata[data_idx].desc.enable_time = info->enable_time;
+
+		cfg.init_data = pbias_matches[idx].init_data;
+		cfg.driver_data = &drvdata[data_idx];
+		cfg.of_node = pbias_matches[idx].of_node;
+
+		drvdata[data_idx].dev = devm_regulator_register(&pdev->dev,
+					&drvdata[data_idx].desc, &cfg);
+		if (IS_ERR(drvdata[data_idx].dev)) {
+			ret = PTR_ERR(drvdata[data_idx].dev);
+			dev_err(&pdev->dev,
+				"Failed to register regulator: %d\n", ret);
+			goto err_regulator;
+		}
+		data_idx++;
+	}
+
+	platform_set_drvdata(pdev, drvdata);
+
+err_regulator:
+	return ret;
+}
+
+static struct platform_driver pbias_regulator_driver = {
+	.probe		= pbias_regulator_probe,
+	.driver		= {
+		.name		= "pbias-regulator",
+		.owner		= THIS_MODULE,
+		.of_match_table = of_match_ptr(pbias_of_match),
+	},
+};
+
+module_platform_driver(pbias_regulator_driver);
+
+MODULE_AUTHOR("Balaji T K <balajitk@ti.com>");
+MODULE_DESCRIPTION("pbias voltage regulator");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pbias-regulator");