diff options
Diffstat (limited to 'drivers/power/regulator')
-rw-r--r-- | drivers/power/regulator/Kconfig | 18 | ||||
-rw-r--r-- | drivers/power/regulator/Makefile | 5 | ||||
-rw-r--r-- | drivers/power/regulator/regulator-uclass.c | 4 | ||||
-rw-r--r-- | drivers/power/regulator/rk808.c | 301 |
4 files changed, 325 insertions, 3 deletions
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 434dd029b5..465ff3fda6 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -16,6 +16,15 @@ config DM_REGULATOR for this purpose if PMIC I/O driver is implemented or dm_scan_fdt_node() otherwise. Detailed information can be found in the header file. +config SPL_DM_REGULATOR + bool "Enable regulators for SPL" + depends on DM_REGULATOR + ---help--- + Regulators are seldom needed in SPL. Even if they are accessed, some + code space can be saved by accessing the PMIC registers directly. + Enable this option if you need regulators in SPL and can cope with + the extra code size. + config REGULATOR_ACT8846 bool "Enable driver for ACT8846 regulator" depends on DM_REGULATOR && PMIC_ACT8846 @@ -49,6 +58,15 @@ config DM_REGULATOR_FIXED features for fixed value regulators. The driver implements get/set api for enable and get only for voltage value. +config REGULATOR_RK808 + bool "Enable driver for RK808 regulators" + depends on DM_REGULATOR && PMIC_RK808 + ---help--- + Enable support for the regulator functions of the RK808 PMIC. The + driver implements get/set api for the various BUCKS and LDOs supported + by the PMIC device. This driver is controlled by a device tree node + which includes voltage limits. + config REGULATOR_S5M8767 bool "Enable support for S5M8767 regulator" depends on DM_REGULATOR && PMIC_S5M8767 diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index c85978e024..1590d8557e 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -5,11 +5,12 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR) += regulator-uclass.o obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_PFUZE100) += pfuze100.o -obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o +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 diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 4241a4c7f2..9fe07f2f73 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -178,7 +178,7 @@ static void regulator_show(struct udevice *dev, int ret) printf("; set %d uA", uc_pdata->min_uA); printf("; enabling"); if (ret) - printf(" (ret: %d)\n", ret); + printf(" (ret: %d)", ret); printf("\n"); } @@ -334,6 +334,8 @@ int regulators_enable_boot_on(bool verbose) } if (verbose) regulator_show(dev, ret); + if (ret == -ENOSYS) + ret = 0; } return ret; diff --git a/drivers/power/regulator/rk808.c b/drivers/power/regulator/rk808.c new file mode 100644 index 0000000000..adef8f57f2 --- /dev/null +++ b/drivers/power/regulator/rk808.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * Based on Rockchip's drivers/power/pmic/pmic_rk808.c: + * Copyright (C) 2012 rockchips + * zyw <zyw@rock-chips.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <power/rk808_pmic.h> +#include <power/pmic.h> +#include <power/regulator.h> + +#ifndef CONFIG_SPL_BUILD +#define ENABLE_DRIVER +#endif + +struct rk808_reg_info { + uint min_uv; + uint step_uv; + s8 vsel_reg; + u8 vsel_bits; +}; + +static const struct rk808_reg_info rk808_buck[] = { + { 712500, 12500, REG_BUCK1_ON_VSEL, 6, }, + { 712500, 12500, REG_BUCK2_ON_VSEL, 6, }, + { 712500, 12500, -1, 6, }, + { 1800000, 100000, REG_BUCK4_ON_VSEL, 4, }, +}; + +static const struct rk808_reg_info rk808_ldo[] = { + { 1800000, 100000, LDO1_ON_VSEL, 5, }, + { 1800000, 100000, LDO2_ON_VSEL, 5, }, + { 800000, 100000, LDO3_ON_VSEL, 4, }, + { 1800000, 100000, LDO4_ON_VSEL, 5, }, + { 1800000, 100000, LDO5_ON_VSEL, 5, }, + { 800000, 100000, LDO6_ON_VSEL, 5, }, + { 800000, 100000, LDO7_ON_VSEL, 5, }, + { 1800000, 100000, LDO8_ON_VSEL, 5, }, +}; + + +static int _buck_set_value(struct udevice *pmic, int buck, int uvolt) +{ + const struct rk808_reg_info *info = &rk808_buck[buck - 1]; + int mask = (1 << info->vsel_bits) - 1; + int val; + + if (info->vsel_reg == -1) + return -ENOSYS; + val = (uvolt - info->min_uv) / info->step_uv; + debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask, + val); + + return pmic_clrsetbits(pmic, info->vsel_reg, mask, val); +} + +static int _buck_set_enable(struct udevice *pmic, int buck, bool enable) +{ + uint mask; + int ret; + + buck--; + mask = 1 << buck; + if (enable) { + ret = pmic_clrsetbits(pmic, DCDC_ILMAX, 0, 3 << (buck * 2)); + if (ret) + return ret; + ret = pmic_clrsetbits(pmic, REG_DCDC_UV_ACT, 1 << buck, 0); + if (ret) + return ret; + } + + return pmic_clrsetbits(pmic, REG_DCDC_EN, mask, enable ? mask : 0); +} + +#ifdef ENABLE_DRIVER +static int buck_get_value(struct udevice *dev) +{ + int buck = dev->driver_data - 1; + const struct rk808_reg_info *info = &rk808_buck[buck]; + int mask = (1 << info->vsel_bits) - 1; + int ret, val; + + if (info->vsel_reg == -1) + return -ENOSYS; + ret = pmic_reg_read(dev->parent, info->vsel_reg); + if (ret < 0) + return ret; + val = ret & mask; + + return info->min_uv + val * info->step_uv; +} + +static int buck_set_value(struct udevice *dev, int uvolt) +{ + int buck = dev->driver_data; + + return _buck_set_value(dev->parent, buck, uvolt); +} + +static int buck_set_enable(struct udevice *dev, bool enable) +{ + int buck = dev->driver_data; + + return _buck_set_enable(dev->parent, buck, enable); +} + +static bool buck_get_enable(struct udevice *dev) +{ + int buck = dev->driver_data - 1; + int ret; + uint mask; + + mask = 1 << buck; + + ret = pmic_reg_read(dev->parent, REG_DCDC_EN); + if (ret < 0) + return ret; + + return ret & mask ? true : false; +} + +static int ldo_get_value(struct udevice *dev) +{ + int ldo = dev->driver_data - 1; + const struct rk808_reg_info *info = &rk808_ldo[ldo]; + int mask = (1 << info->vsel_bits) - 1; + int ret, val; + + if (info->vsel_reg == -1) + return -ENOSYS; + ret = pmic_reg_read(dev->parent, info->vsel_reg); + if (ret < 0) + return ret; + val = ret & mask; + + return info->min_uv + val * info->step_uv; +} + +static int ldo_set_value(struct udevice *dev, int uvolt) +{ + int ldo = dev->driver_data - 1; + const struct rk808_reg_info *info = &rk808_ldo[ldo]; + int mask = (1 << info->vsel_bits) - 1; + int val; + + if (info->vsel_reg == -1) + return -ENOSYS; + val = (uvolt - info->min_uv) / info->step_uv; + debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask, + val); + + return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val); +} + +static int ldo_set_enable(struct udevice *dev, bool enable) +{ + int ldo = dev->driver_data - 1; + uint mask; + + mask = 1 << ldo; + + return pmic_clrsetbits(dev->parent, REG_LDO_EN, mask, + enable ? mask : 0); +} + +static bool ldo_get_enable(struct udevice *dev) +{ + int ldo = dev->driver_data - 1; + int ret; + uint mask; + + mask = 1 << ldo; + + ret = pmic_reg_read(dev->parent, REG_LDO_EN); + if (ret < 0) + return ret; + + return ret & mask ? true : false; +} + +static int switch_set_enable(struct udevice *dev, bool enable) +{ + int sw = dev->driver_data - 1; + uint mask; + + mask = 1 << (sw + 5); + + return pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask, + enable ? mask : 0); +} + +static bool switch_get_enable(struct udevice *dev) +{ + int sw = dev->driver_data - 1; + int ret; + uint mask; + + mask = 1 << (sw + 5); + + ret = pmic_reg_read(dev->parent, REG_DCDC_EN); + if (ret < 0) + return ret; + + return ret & mask ? true : false; +} + +static int rk808_buck_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_BUCK; + uc_pdata->mode_count = 0; + + return 0; +} + +static int rk808_ldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_LDO; + uc_pdata->mode_count = 0; + + return 0; +} + +static int rk808_switch_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_FIXED; + uc_pdata->mode_count = 0; + + return 0; +} + +static const struct dm_regulator_ops rk808_buck_ops = { + .get_value = buck_get_value, + .set_value = buck_set_value, + .get_enable = buck_get_enable, + .set_enable = buck_set_enable, +}; + +static const struct dm_regulator_ops rk808_ldo_ops = { + .get_value = ldo_get_value, + .set_value = ldo_set_value, + .get_enable = ldo_get_enable, + .set_enable = ldo_set_enable, +}; + +static const struct dm_regulator_ops rk808_switch_ops = { + .get_enable = switch_get_enable, + .set_enable = switch_set_enable, +}; + +U_BOOT_DRIVER(rk808_buck) = { + .name = "rk808_buck", + .id = UCLASS_REGULATOR, + .ops = &rk808_buck_ops, + .probe = rk808_buck_probe, +}; + +U_BOOT_DRIVER(rk808_ldo) = { + .name = "rk808_ldo", + .id = UCLASS_REGULATOR, + .ops = &rk808_ldo_ops, + .probe = rk808_ldo_probe, +}; + +U_BOOT_DRIVER(rk808_switch) = { + .name = "rk808_switch", + .id = UCLASS_REGULATOR, + .ops = &rk808_switch_ops, + .probe = rk808_switch_probe, +}; +#endif + +int rk808_spl_configure_buck(struct udevice *pmic, int buck, int uvolt) +{ + int ret; + + ret = _buck_set_value(pmic, buck, uvolt); + if (ret) + return ret; + + return _buck_set_enable(pmic, buck, true); +} |