
Simon,
On Monday 26 September 2016 10:05 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 Reviewed-by: Tom Rini trini@konsulko.com
drivers/power/regulator/Kconfig | 8 + drivers/power/regulator/Makefile | 1 + drivers/power/regulator/palmas_regulator.c | 457 +++++++++++++++++++++++++++++ 3 files changed, 466 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..14bc701 --- /dev/null +++ b/drivers/power/regulator/palmas_regulator.c @@ -0,0 +1,457 @@ +/*
- (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;
- ret = dm_i2c_u8_read(dev->parent, adr, &val);
if (ret < 0)
return ret;
- 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);
ret = dm_i2c_u8_write(dev->parent, adr, &val);
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;
- u8 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;
- ret = dm_i2c_u8_read(dev->parent, adr, &val);
- if (ret)
return ret;
- 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;
- return dm_i2c_u8_write(dev->parent, adr, &val);
+}
+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;
- ret = dm_i2c_u8_read(dev->parent, adr, &val);
if (ret)
return ret;
- 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);
ret = dm_i2c_u8_write(dev->parent, adr, &val);
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;
- u8 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;
- ret = dm_i2c_u8_read(dev->parent, adr, &val);
- if (ret)
return ret;
- 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;
- return dm_i2c_u8_write(dev->parent, adr, &val);
I guess this and other direct i2c calls are unacceptable even from here. So i will rework this as well. Based on the feedback given on lp873x regulator driver.
+}
+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,
+};