diff mbox

[U-Boot,v2,3/5] power: regulator: palmas: Add regulator support

Message ID 1474257085-28096-4-git-send-email-j-keerthy@ti.com
State Superseded
Headers show

Commit Message

J, KEERTHY Sept. 19, 2016, 3:51 a.m. UTC
The driver provides regulator set/get voltage
enable/disable functions for palmas family of PMICs.

Signed-off-by: Keerthy <j-keerthy@ti.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---

Changes in v2:

  * Converted all dm_i2c_reg to dm_i2c_read_reg
  * Removed an instance of double blank lines.
  * Added Simon's Reviewed-by.

 drivers/power/regulator/Kconfig            |   8 +
 drivers/power/regulator/Makefile           |   1 +
 drivers/power/regulator/palmas_regulator.c | 459 +++++++++++++++++++++++++++++
 3 files changed, 468 insertions(+)
 create mode 100644 drivers/power/regulator/palmas_regulator.c

Comments

Keerthy Sept. 19, 2016, 5:37 a.m. UTC | #1
On Monday 19 September 2016 09:21 AM, Keerthy wrote:
> The driver provides regulator set/get voltage
> enable/disable functions for palmas family of PMICs.
>
> Signed-off-by: Keerthy <j-keerthy@ti.com>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> ---
>
> Changes in v2:
>
>   * Converted all dm_i2c_reg to dm_i2c_read_reg
>   * Removed an instance of double blank lines.
>   * Added Simon's Reviewed-by.
>
>  drivers/power/regulator/Kconfig            |   8 +
>  drivers/power/regulator/Makefile           |   1 +
>  drivers/power/regulator/palmas_regulator.c | 459 +++++++++++++++++++++++++++++
>  3 files changed, 468 insertions(+)
>  create mode 100644 drivers/power/regulator/palmas_regulator.c
>
> diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
> index 17f22dd..adb710a 100644
> --- a/drivers/power/regulator/Kconfig
> +++ b/drivers/power/regulator/Kconfig
> @@ -115,3 +115,11 @@ config REGULATOR_TPS65090
>  	regulators, one for each FET. The standard regulator interface is
>  	supported, but it is only possible to turn the regulators on or off.
>  	There is no voltage/current control.
> +
> +config DM_REGULATOR_PALMAS
> +	bool "Enable driver for PALMAS PMIC regulators"
> +       depends on PMIC_PALMAS
> +	---help---
> +	This enables implementation of driver-model regulator uclass
> +	features for REGULATOR PALMAS and the family of PALMAS PMICs.
> +	The driver implements get/set api for: value and enable.
> diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
> index 1590d85..75080d4 100644
> --- a/drivers/power/regulator/Makefile
> +++ b/drivers/power/regulator/Makefile
> @@ -14,3 +14,4 @@ obj-$(CONFIG_REGULATOR_RK808) += rk808.o
>  obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
>  obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
>  obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
> +obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o
> diff --git a/drivers/power/regulator/palmas_regulator.c b/drivers/power/regulator/palmas_regulator.c
> new file mode 100644
> index 0000000..8212bf2
> --- /dev/null
> +++ b/drivers/power/regulator/palmas_regulator.c
> @@ -0,0 +1,459 @@
> +/*
> + * (C) Copyright 2016
> + * Texas Instruments Incorporated, <www.ti.com>
> + *
> + * Keerthy <j-keerthy@ti.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <fdtdec.h>
> +#include <errno.h>
> +#include <dm.h>
> +#include <i2c.h>
> +#include <power/pmic.h>
> +#include <power/regulator.h>
> +#include <power/palmas.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +#define	REGULATOR_ON		0x1
> +#define	REGULATOR_OFF		0x0
> +
> +#define	SMPS_MODE_MASK		0x3
> +#define	SMPS_MODE_SHIFT		0x0
> +#define	LDO_MODE_MASK		0x1
> +#define	LDO_MODE_SHIFT		0x0
> +
> +static const char palmas_smps_ctrl[][PALMAS_SMPS_NUM] = {
> +	{0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c},
> +	{0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38},
> +	{0x20, 0x24, 0x2c, 0x30, 0x38},
> +};
> +
> +static const char palmas_smps_volt[][PALMAS_SMPS_NUM] = {
> +	{0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b, 0x3c},
> +	{0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b},
> +	{0x23, 0x27, 0x2f, 0x33, 0x3B}
> +};
> +
> +static const char palmas_ldo_ctrl[][PALMAS_LDO_NUM] = {
> +	{0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
> +	{0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
> +	{0x50, 0x52, 0x54, 0x5e, 0x62}
> +};
> +
> +static const char palmas_ldo_volt[][PALMAS_LDO_NUM] = {
> +	{0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
> +	{0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
> +	{0x51, 0x53, 0x55, 0x5f, 0x63}
> +};
> +
> +static int palmas_smps_enable(struct udevice *dev, int op, bool *enable)
> +{
> +	int ret;
> +	uint8_t val;
> +	unsigned int adr;
> +	struct dm_regulator_uclass_platdata *uc_pdata;
> +
> +	uc_pdata = dev_get_uclass_platdata(dev);
> +	adr = uc_pdata->ctrl_reg;
> +
> +	val = dm_i2c_reg_read(dev->parent, adr);
> +		if (val < 0)
> +			return val;
> +
> +	if (op == PMIC_OP_GET) {
> +		val &= PALMAS_SMPS_STATUS_MASK;
> +
> +		if (val)
> +			*enable = true;
> +		else
> +			*enable = false;
> +
> +		return 0;
> +	} else if (op == PMIC_OP_SET) {
> +		if (*enable)
> +			val |= PALMAS_SMPS_MODE_MASK;
> +		else
> +			val &= ~(PALMAS_SMPS_MODE_MASK);
> +
> +		dm_i2c_write(dev->parent, adr, &val, 1);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int palmas_smps_volt2hex(int uV)
> +{
> +	if (uV > PALMAS_LDO_VOLT_MAX)
> +		return -EINVAL;
> +
> +	if (uV > 1650000)
> +		return (uV - 1000000) / 20000 + 0x6;
> +
> +	if (uV == 500000)
> +		return 0x6;
> +	else
> +		return 0x6 + ((uV - 500000) / 10000);
> +}
> +
> +static int palmas_smps_hex2volt(int hex, bool range)
> +{
> +	unsigned int uV = 0;
> +
> +	if (hex > PALMAS_SMPS_VOLT_MAX_HEX)
> +		return -EINVAL;
> +
> +	if (hex < 0x7)
> +		uV = 500000;
> +	else
> +		uV = 500000 + (hex - 0x6) * 10000;
> +
> +	if (range)
> +		uV *= 2;
> +
> +	return uV;
> +}
> +
> +static int palmas_smps_val(struct udevice *dev, int op, int *uV)
> +{
> +	unsigned int hex, adr;
> +	unsigned char val;
> +	int ret;
> +	bool range;
> +	struct dm_regulator_uclass_platdata *uc_pdata;
> +
> +	uc_pdata = dev_get_uclass_platdata(dev);
> +
> +	if (op == PMIC_OP_GET)
> +		*uV = 0;
> +
> +	adr = uc_pdata->volt_reg;
> +
> +	val = dm_i2c_reg_read(dev->parent, adr);

Simon,

I see a kind of issue in the current implementation of
int dm_i2c_reg_read(struct udevice *dev, uint offset)
int dm_i2c_reg_write(struct udevice *dev, uint offset, uint value)

In the current set up my need is to read and then write a 1 byte I2C 
register. It is best to have consistency with read and write.

In the current case i read an integer and now when i want to write i 
need to convert it to an unsigned integer.

Instead of all this why can we have:

int dm_i2c_reg_read(struct udevice *dev, uint offset, u8 *val)

returns error/success with the return value and value is passed by 
reference in val variable.

int dm_i2c_reg_write(struct udevice *dev, uint offset, u8 *val)
returns error/success using the return value and the value to be written 
is sent in val.

Please let me know your thoughts on this. I propose to drop this series 
as i will fix the above and send another version but before that i would 
need your inputs.

- Keerthy

> +	if (val < 0)
> +		return val;
> +
> +	if (op == PMIC_OP_GET) {
> +		if (val & PALMAS_SMPS_RANGE_MASK)
> +			range =  true;
> +		else
> +			range = false;
> +
> +		val &= PALMAS_SMPS_VOLT_MASK;
> +		ret = palmas_smps_hex2volt(val, range);
> +		if (ret < 0)
> +			return ret;
> +		*uV = ret;
> +
> +		return 0;
> +	}
> +
> +	hex = palmas_smps_volt2hex(*uV);
> +	if (hex < 0)
> +		return hex;
> +
> +	val &= ~PALMAS_SMPS_VOLT_MASK;
> +	val |= hex;
> +	if (*uV > 1650000)
> +		val |= PALMAS_SMPS_RANGE_MASK;
> +	ret = dm_i2c_write(dev->parent, adr, &val, 1);
> +
> +	return ret;
> +}
> +
> +static int palmas_ldo_enable(struct udevice *dev, int op, bool *enable)
> +{
> +	int ret;
> +	uint8_t val;
> +	unsigned int adr;
> +	struct dm_regulator_uclass_platdata *uc_pdata;
> +
> +	uc_pdata = dev_get_uclass_platdata(dev);
> +	adr = uc_pdata->ctrl_reg;
> +
> +	val = dm_i2c_reg_read(dev->parent, adr);
> +		if (val < 0)
> +			return val;
> +
> +	if (op == PMIC_OP_GET) {
> +		val &= PALMAS_LDO_STATUS_MASK;
> +
> +		if (val)
> +			*enable = true;
> +		else
> +			*enable = false;
> +
> +		return 0;
> +	} else if (op == PMIC_OP_SET) {
> +		if (*enable)
> +			val |= PALMAS_LDO_MODE_MASK;
> +		else
> +			val &= ~(PALMAS_LDO_MODE_MASK);
> +
> +		dm_i2c_write(dev->parent, adr, &val, 1);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int palmas_ldo_volt2hex(int uV)
> +{
> +	if (uV > PALMAS_LDO_VOLT_MAX)
> +		return -EINVAL;
> +
> +	return (uV - 850000) / 50000;
> +}
> +
> +static int palmas_ldo_hex2volt(int hex)
> +{
> +	if (hex > PALMAS_LDO_VOLT_MAX_HEX)
> +		return -EINVAL;
> +
> +	if (!hex)
> +		return 0;
> +
> +	return (hex * 50000) + 850000;
> +}
> +
> +static int palmas_ldo_val(struct udevice *dev, int op, int *uV)
> +{
> +	unsigned int hex, adr;
> +	unsigned char val;
> +	int ret;
> +
> +	struct dm_regulator_uclass_platdata *uc_pdata;
> +
> +	if (op == PMIC_OP_GET)
> +		*uV = 0;
> +
> +	uc_pdata = dev_get_uclass_platdata(dev);
> +
> +	adr = uc_pdata->volt_reg;
> +
> +	val = dm_i2c_reg_read(dev->parent, adr);
> +	if (val < 0)
> +		return val;
> +
> +	if (op == PMIC_OP_GET) {
> +		val &= PALMAS_LDO_VOLT_MASK;
> +		ret = palmas_ldo_hex2volt(val);
> +		if (ret < 0)
> +			return ret;
> +		*uV = ret;
> +		return 0;
> +	}
> +
> +	hex = palmas_ldo_volt2hex(*uV);
> +	if (hex < 0)
> +		return hex;
> +
> +	val &= ~PALMAS_LDO_VOLT_MASK;
> +	val |= hex;
> +	if (*uV > 1650000)
> +		val |= 0x80;
> +	ret = dm_i2c_write(dev->parent, adr, &val, 1);
> +
> +	return ret;
> +}
> +
> +static int palmas_ldo_probe(struct udevice *dev)
> +{
> +	struct dm_regulator_uclass_platdata *uc_pdata;
> +	struct udevice *parent;
> +
> +	uc_pdata = dev_get_uclass_platdata(dev);
> +
> +	parent = dev_get_parent(dev);
> +	int type = dev_get_driver_data(parent);
> +
> +	uc_pdata->type = REGULATOR_TYPE_LDO;
> +
> +	if (dev->driver_data) {
> +		u8 idx = dev->driver_data - 1;
> +		uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][idx];
> +		uc_pdata->volt_reg = palmas_ldo_volt[type][idx];
> +	} else {
> +		/* check for ldoln and ldousb cases */
> +		if (!strcmp("ldoln", dev->name)) {
> +			uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9];
> +			uc_pdata->volt_reg = palmas_ldo_volt[type][9];
> +		} else if (!strcmp("ldousb", dev->name)) {
> +			uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10];
> +			uc_pdata->volt_reg = palmas_ldo_volt[type][10];
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int ldo_get_value(struct udevice *dev)
> +{
> +	int uV;
> +	int ret;
> +
> +	ret = palmas_ldo_val(dev, PMIC_OP_GET, &uV);
> +	if (ret)
> +		return ret;
> +
> +	return uV;
> +}
> +
> +static int ldo_set_value(struct udevice *dev, int uV)
> +{
> +	return palmas_ldo_val(dev, PMIC_OP_SET, &uV);
> +}
> +
> +static bool ldo_get_enable(struct udevice *dev)
> +{
> +	bool enable = false;
> +	int ret;
> +
> +	ret = palmas_ldo_enable(dev, PMIC_OP_GET, &enable);
> +	if (ret)
> +		return ret;
> +
> +	return enable;
> +}
> +
> +static int ldo_set_enable(struct udevice *dev, bool enable)
> +{
> +	return palmas_ldo_enable(dev, PMIC_OP_SET, &enable);
> +}
> +
> +static int palmas_smps_probe(struct udevice *dev)
> +{
> +	struct dm_regulator_uclass_platdata *uc_pdata;
> +	struct udevice *parent;
> +	int idx;
> +
> +	uc_pdata = dev_get_uclass_platdata(dev);
> +
> +	parent = dev_get_parent(dev);
> +	int type = dev_get_driver_data(parent);
> +
> +	uc_pdata->type = REGULATOR_TYPE_BUCK;
> +
> +	switch (type) {
> +	case PALMAS:
> +	case TPS659038:
> +		switch (dev->driver_data) {
> +		case 123:
> +		case 12:
> +			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][0];
> +			uc_pdata->volt_reg = palmas_smps_volt[type][0];
> +			break;
> +		case 3:
> +			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][1];
> +			uc_pdata->volt_reg = palmas_smps_volt[type][1];
> +			break;
> +		case 45:
> +			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][2];
> +			uc_pdata->volt_reg = palmas_smps_volt[type][2];
> +			break;
> +		case 6:
> +		case 7:
> +		case 8:
> +		case 9:
> +		case 10:
> +			idx = dev->driver_data - 4;
> +			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
> +			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
> +			break;
> +
> +		default:
> +			printf("Wrong ID for regulator\n");
> +		}
> +		break;
> +
> +	case TPS65917:
> +		switch (dev->driver_data) {
> +		case 1:
> +		case 2:
> +		case 3:
> +		case 4:
> +		case 5:
> +			idx = dev->driver_data - 1;
> +			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
> +			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
> +			break;
> +
> +		default:
> +			printf("Wrong ID for regulator\n");
> +		}
> +		break;
> +
> +	default:
> +			printf("Invalid PMIC ID\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static int smps_get_value(struct udevice *dev)
> +{
> +	int uV;
> +	int ret;
> +
> +	ret = palmas_smps_val(dev, PMIC_OP_GET, &uV);
> +	if (ret)
> +		return ret;
> +
> +	return uV;
> +}
> +
> +static int smps_set_value(struct udevice *dev, int uV)
> +{
> +	return palmas_smps_val(dev, PMIC_OP_SET, &uV);
> +}
> +
> +static bool smps_get_enable(struct udevice *dev)
> +{
> +	bool enable = false;
> +	int ret;
> +
> +	ret = palmas_smps_enable(dev, PMIC_OP_GET, &enable);
> +	if (ret)
> +		return ret;
> +
> +	return enable;
> +}
> +
> +static int smps_set_enable(struct udevice *dev, bool enable)
> +{
> +	return palmas_smps_enable(dev, PMIC_OP_SET, &enable);
> +}
> +
> +static const struct dm_regulator_ops palmas_ldo_ops = {
> +	.get_value  = ldo_get_value,
> +	.set_value  = ldo_set_value,
> +	.get_enable = ldo_get_enable,
> +	.set_enable = ldo_set_enable,
> +};
> +
> +U_BOOT_DRIVER(palmas_ldo) = {
> +	.name = PALMAS_LDO_DRIVER,
> +	.id = UCLASS_REGULATOR,
> +	.ops = &palmas_ldo_ops,
> +	.probe = palmas_ldo_probe,
> +};
> +
> +static const struct dm_regulator_ops palmas_smps_ops = {
> +	.get_value  = smps_get_value,
> +	.set_value  = smps_set_value,
> +	.get_enable = smps_get_enable,
> +	.set_enable = smps_set_enable,
> +};
> +
> +U_BOOT_DRIVER(palmas_smps) = {
> +	.name = PALMAS_SMPS_DRIVER,
> +	.id = UCLASS_REGULATOR,
> +	.ops = &palmas_smps_ops,
> +	.probe = palmas_smps_probe,
> +};
>
diff mbox

Patch

diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 17f22dd..adb710a 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -115,3 +115,11 @@  config REGULATOR_TPS65090
 	regulators, one for each FET. The standard regulator interface is
 	supported, but it is only possible to turn the regulators on or off.
 	There is no voltage/current control.
+
+config DM_REGULATOR_PALMAS
+	bool "Enable driver for PALMAS PMIC regulators"
+       depends on PMIC_PALMAS
+	---help---
+	This enables implementation of driver-model regulator uclass
+	features for REGULATOR PALMAS and the family of PALMAS PMICs.
+	The driver implements get/set api for: value and enable.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 1590d85..75080d4 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -14,3 +14,4 @@  obj-$(CONFIG_REGULATOR_RK808) += rk808.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
 obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
+obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o
diff --git a/drivers/power/regulator/palmas_regulator.c b/drivers/power/regulator/palmas_regulator.c
new file mode 100644
index 0000000..8212bf2
--- /dev/null
+++ b/drivers/power/regulator/palmas_regulator.c
@@ -0,0 +1,459 @@ 
+/*
+ * (C) Copyright 2016
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Keerthy <j-keerthy@ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/palmas.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define	REGULATOR_ON		0x1
+#define	REGULATOR_OFF		0x0
+
+#define	SMPS_MODE_MASK		0x3
+#define	SMPS_MODE_SHIFT		0x0
+#define	LDO_MODE_MASK		0x1
+#define	LDO_MODE_SHIFT		0x0
+
+static const char palmas_smps_ctrl[][PALMAS_SMPS_NUM] = {
+	{0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c},
+	{0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38},
+	{0x20, 0x24, 0x2c, 0x30, 0x38},
+};
+
+static const char palmas_smps_volt[][PALMAS_SMPS_NUM] = {
+	{0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b, 0x3c},
+	{0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b},
+	{0x23, 0x27, 0x2f, 0x33, 0x3B}
+};
+
+static const char palmas_ldo_ctrl[][PALMAS_LDO_NUM] = {
+	{0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
+	{0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
+	{0x50, 0x52, 0x54, 0x5e, 0x62}
+};
+
+static const char palmas_ldo_volt[][PALMAS_LDO_NUM] = {
+	{0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
+	{0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
+	{0x51, 0x53, 0x55, 0x5f, 0x63}
+};
+
+static int palmas_smps_enable(struct udevice *dev, int op, bool *enable)
+{
+	int ret;
+	uint8_t val;
+	unsigned int adr;
+	struct dm_regulator_uclass_platdata *uc_pdata;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+	adr = uc_pdata->ctrl_reg;
+
+	val = dm_i2c_reg_read(dev->parent, adr);
+		if (val < 0)
+			return val;
+
+	if (op == PMIC_OP_GET) {
+		val &= PALMAS_SMPS_STATUS_MASK;
+
+		if (val)
+			*enable = true;
+		else
+			*enable = false;
+
+		return 0;
+	} else if (op == PMIC_OP_SET) {
+		if (*enable)
+			val |= PALMAS_SMPS_MODE_MASK;
+		else
+			val &= ~(PALMAS_SMPS_MODE_MASK);
+
+		dm_i2c_write(dev->parent, adr, &val, 1);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int palmas_smps_volt2hex(int uV)
+{
+	if (uV > PALMAS_LDO_VOLT_MAX)
+		return -EINVAL;
+
+	if (uV > 1650000)
+		return (uV - 1000000) / 20000 + 0x6;
+
+	if (uV == 500000)
+		return 0x6;
+	else
+		return 0x6 + ((uV - 500000) / 10000);
+}
+
+static int palmas_smps_hex2volt(int hex, bool range)
+{
+	unsigned int uV = 0;
+
+	if (hex > PALMAS_SMPS_VOLT_MAX_HEX)
+		return -EINVAL;
+
+	if (hex < 0x7)
+		uV = 500000;
+	else
+		uV = 500000 + (hex - 0x6) * 10000;
+
+	if (range)
+		uV *= 2;
+
+	return uV;
+}
+
+static int palmas_smps_val(struct udevice *dev, int op, int *uV)
+{
+	unsigned int hex, adr;
+	unsigned char val;
+	int ret;
+	bool range;
+	struct dm_regulator_uclass_platdata *uc_pdata;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+
+	if (op == PMIC_OP_GET)
+		*uV = 0;
+
+	adr = uc_pdata->volt_reg;
+
+	val = dm_i2c_reg_read(dev->parent, adr);
+	if (val < 0)
+		return val;
+
+	if (op == PMIC_OP_GET) {
+		if (val & PALMAS_SMPS_RANGE_MASK)
+			range =  true;
+		else
+			range = false;
+
+		val &= PALMAS_SMPS_VOLT_MASK;
+		ret = palmas_smps_hex2volt(val, range);
+		if (ret < 0)
+			return ret;
+		*uV = ret;
+
+		return 0;
+	}
+
+	hex = palmas_smps_volt2hex(*uV);
+	if (hex < 0)
+		return hex;
+
+	val &= ~PALMAS_SMPS_VOLT_MASK;
+	val |= hex;
+	if (*uV > 1650000)
+		val |= PALMAS_SMPS_RANGE_MASK;
+	ret = dm_i2c_write(dev->parent, adr, &val, 1);
+
+	return ret;
+}
+
+static int palmas_ldo_enable(struct udevice *dev, int op, bool *enable)
+{
+	int ret;
+	uint8_t val;
+	unsigned int adr;
+	struct dm_regulator_uclass_platdata *uc_pdata;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+	adr = uc_pdata->ctrl_reg;
+
+	val = dm_i2c_reg_read(dev->parent, adr);
+		if (val < 0)
+			return val;
+
+	if (op == PMIC_OP_GET) {
+		val &= PALMAS_LDO_STATUS_MASK;
+
+		if (val)
+			*enable = true;
+		else
+			*enable = false;
+
+		return 0;
+	} else if (op == PMIC_OP_SET) {
+		if (*enable)
+			val |= PALMAS_LDO_MODE_MASK;
+		else
+			val &= ~(PALMAS_LDO_MODE_MASK);
+
+		dm_i2c_write(dev->parent, adr, &val, 1);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int palmas_ldo_volt2hex(int uV)
+{
+	if (uV > PALMAS_LDO_VOLT_MAX)
+		return -EINVAL;
+
+	return (uV - 850000) / 50000;
+}
+
+static int palmas_ldo_hex2volt(int hex)
+{
+	if (hex > PALMAS_LDO_VOLT_MAX_HEX)
+		return -EINVAL;
+
+	if (!hex)
+		return 0;
+
+	return (hex * 50000) + 850000;
+}
+
+static int palmas_ldo_val(struct udevice *dev, int op, int *uV)
+{
+	unsigned int hex, adr;
+	unsigned char val;
+	int ret;
+
+	struct dm_regulator_uclass_platdata *uc_pdata;
+
+	if (op == PMIC_OP_GET)
+		*uV = 0;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+
+	adr = uc_pdata->volt_reg;
+
+	val = dm_i2c_reg_read(dev->parent, adr);
+	if (val < 0)
+		return val;
+
+	if (op == PMIC_OP_GET) {
+		val &= PALMAS_LDO_VOLT_MASK;
+		ret = palmas_ldo_hex2volt(val);
+		if (ret < 0)
+			return ret;
+		*uV = ret;
+		return 0;
+	}
+
+	hex = palmas_ldo_volt2hex(*uV);
+	if (hex < 0)
+		return hex;
+
+	val &= ~PALMAS_LDO_VOLT_MASK;
+	val |= hex;
+	if (*uV > 1650000)
+		val |= 0x80;
+	ret = dm_i2c_write(dev->parent, adr, &val, 1);
+
+	return ret;
+}
+
+static int palmas_ldo_probe(struct udevice *dev)
+{
+	struct dm_regulator_uclass_platdata *uc_pdata;
+	struct udevice *parent;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+
+	parent = dev_get_parent(dev);
+	int type = dev_get_driver_data(parent);
+
+	uc_pdata->type = REGULATOR_TYPE_LDO;
+
+	if (dev->driver_data) {
+		u8 idx = dev->driver_data - 1;
+		uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][idx];
+		uc_pdata->volt_reg = palmas_ldo_volt[type][idx];
+	} else {
+		/* check for ldoln and ldousb cases */
+		if (!strcmp("ldoln", dev->name)) {
+			uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9];
+			uc_pdata->volt_reg = palmas_ldo_volt[type][9];
+		} else if (!strcmp("ldousb", dev->name)) {
+			uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10];
+			uc_pdata->volt_reg = palmas_ldo_volt[type][10];
+		}
+	}
+
+	return 0;
+}
+
+static int ldo_get_value(struct udevice *dev)
+{
+	int uV;
+	int ret;
+
+	ret = palmas_ldo_val(dev, PMIC_OP_GET, &uV);
+	if (ret)
+		return ret;
+
+	return uV;
+}
+
+static int ldo_set_value(struct udevice *dev, int uV)
+{
+	return palmas_ldo_val(dev, PMIC_OP_SET, &uV);
+}
+
+static bool ldo_get_enable(struct udevice *dev)
+{
+	bool enable = false;
+	int ret;
+
+	ret = palmas_ldo_enable(dev, PMIC_OP_GET, &enable);
+	if (ret)
+		return ret;
+
+	return enable;
+}
+
+static int ldo_set_enable(struct udevice *dev, bool enable)
+{
+	return palmas_ldo_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static int palmas_smps_probe(struct udevice *dev)
+{
+	struct dm_regulator_uclass_platdata *uc_pdata;
+	struct udevice *parent;
+	int idx;
+
+	uc_pdata = dev_get_uclass_platdata(dev);
+
+	parent = dev_get_parent(dev);
+	int type = dev_get_driver_data(parent);
+
+	uc_pdata->type = REGULATOR_TYPE_BUCK;
+
+	switch (type) {
+	case PALMAS:
+	case TPS659038:
+		switch (dev->driver_data) {
+		case 123:
+		case 12:
+			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][0];
+			uc_pdata->volt_reg = palmas_smps_volt[type][0];
+			break;
+		case 3:
+			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][1];
+			uc_pdata->volt_reg = palmas_smps_volt[type][1];
+			break;
+		case 45:
+			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][2];
+			uc_pdata->volt_reg = palmas_smps_volt[type][2];
+			break;
+		case 6:
+		case 7:
+		case 8:
+		case 9:
+		case 10:
+			idx = dev->driver_data - 4;
+			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
+			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
+			break;
+
+		default:
+			printf("Wrong ID for regulator\n");
+		}
+		break;
+
+	case TPS65917:
+		switch (dev->driver_data) {
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+		case 5:
+			idx = dev->driver_data - 1;
+			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
+			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
+			break;
+
+		default:
+			printf("Wrong ID for regulator\n");
+		}
+		break;
+
+	default:
+			printf("Invalid PMIC ID\n");
+	}
+
+	return 0;
+}
+
+static int smps_get_value(struct udevice *dev)
+{
+	int uV;
+	int ret;
+
+	ret = palmas_smps_val(dev, PMIC_OP_GET, &uV);
+	if (ret)
+		return ret;
+
+	return uV;
+}
+
+static int smps_set_value(struct udevice *dev, int uV)
+{
+	return palmas_smps_val(dev, PMIC_OP_SET, &uV);
+}
+
+static bool smps_get_enable(struct udevice *dev)
+{
+	bool enable = false;
+	int ret;
+
+	ret = palmas_smps_enable(dev, PMIC_OP_GET, &enable);
+	if (ret)
+		return ret;
+
+	return enable;
+}
+
+static int smps_set_enable(struct udevice *dev, bool enable)
+{
+	return palmas_smps_enable(dev, PMIC_OP_SET, &enable);
+}
+
+static const struct dm_regulator_ops palmas_ldo_ops = {
+	.get_value  = ldo_get_value,
+	.set_value  = ldo_set_value,
+	.get_enable = ldo_get_enable,
+	.set_enable = ldo_set_enable,
+};
+
+U_BOOT_DRIVER(palmas_ldo) = {
+	.name = PALMAS_LDO_DRIVER,
+	.id = UCLASS_REGULATOR,
+	.ops = &palmas_ldo_ops,
+	.probe = palmas_ldo_probe,
+};
+
+static const struct dm_regulator_ops palmas_smps_ops = {
+	.get_value  = smps_get_value,
+	.set_value  = smps_set_value,
+	.get_enable = smps_get_enable,
+	.set_enable = smps_set_enable,
+};
+
+U_BOOT_DRIVER(palmas_smps) = {
+	.name = PALMAS_SMPS_DRIVER,
+	.id = UCLASS_REGULATOR,
+	.ops = &palmas_smps_ops,
+	.probe = palmas_smps_probe,
+};