From e54cf6dba77ac6d2c1d495ebf95f5396402d3106 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Tue, 18 Dec 2018 10:11:41 +0800 Subject: [PATCH] power: regulator: add fan53555 regulator add driver support for fan53555\syr82x\tcs452x dcdc. Change-Id: Ib6132d7063ba8bda9631b45e128df1d278222dad Signed-off-by: Elaine Zhang --- drivers/power/regulator/Kconfig | 8 + drivers/power/regulator/Makefile | 1 + drivers/power/regulator/fan53555_regulator.c | 506 +++++++++++++++++++ 3 files changed, 515 insertions(+) create mode 100644 drivers/power/regulator/fan53555_regulator.c diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index a11408ff2e..5b4605f5a2 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -51,6 +51,14 @@ config DM_REGULATOR_PFUZE100 features for REGULATOR PFUZE100. The driver implements get/set api for: value, enable and mode. +config REGULATOR_FAN53555 + bool "Enable driver for fan53555 regulators" + depends on DM_REGULATOR + ---help--- + Enable support for the regulator functions of the fan53555 DCDC. The + driver implements get/set api for the various BUCK.This driver is + controlled by a device tree node which includes voltage limits. + config REGULATOR_PWM bool "Enable driver for PWM regulators" depends on DM_REGULATOR diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 18fb870e43..d582ee1bc2 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_PFUZE100) += pfuze100.o obj-$(CONFIG_REGULATOR_PWM) += pwm_regulator.o +obj-$(CONFIG_REGULATOR_FAN53555) += fan53555_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_RK8XX) += rk8xx.o diff --git a/drivers/power/regulator/fan53555_regulator.c b/drivers/power/regulator/fan53555_regulator.c new file mode 100644 index 0000000000..3a3e1970d6 --- /dev/null +++ b/drivers/power/regulator/fan53555_regulator.c @@ -0,0 +1,506 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* Voltage setting */ +#define FAN53555_VSEL0 0x00 +#define FAN53555_VSEL1 0x01 + +#define TCS452X_VSEL0 0x11 +#define TCS452X_VSEL1 0x10 +#define TCS452X_TIME 0x13 +#define TCS452X_COMMAND 0x14 + +/* Control register */ +#define FAN53555_CONTROL 0x02 +/* IC Type */ +#define FAN53555_ID1 0x03 +/* IC mask version */ +#define FAN53555_ID2 0x04 +/* Monitor register */ +#define FAN53555_MONITOR 0x05 + +/* VSEL bit definitions */ +#define VSEL_BUCK_EN BIT(7) +#define VSEL_MODE BIT(6) +#define VSEL_NSEL_MASK 0x3F + +/* Chip ID and Version */ +#define DIE_ID 0x0F/* ID1 */ +#define DIE_REV 0x0F/* ID2 */ +/* Control bit definitions */ +#define CTL_OUTPUT_DISCHG BIT(7) +#define CTL_SLEW_MASK (0x7 << 4) +#define CTL_SLEW_SHIFT 4 +#define CTL_RESET BIT(2) + +#define TCS_VSEL_NSEL_MASK 0x7f +#define TCS_VSEL0_MODE BIT(7) +#define TCS_VSEL1_MODE BIT(6) + +#define TCS_SLEW_SHIFT 3 +#define TCS_SLEW_MASK (0x3 < 3) + +#define FAN53555_NVOLTAGES_64 64/* Numbers of voltages */ +#define FAN53555_NVOLTAGES_127 127/* Numbers of voltages */ + +enum fan53555_vendor { + FAN53555_VENDOR_FAIRCHILD = 0, + FAN53555_VENDOR_SILERGY, + FAN53555_VENDOR_TCS, +}; + +/* IC Type */ +enum { + FAN53555_CHIP_ID_00 = 0, + FAN53555_CHIP_ID_01, + FAN53555_CHIP_ID_02, + FAN53555_CHIP_ID_03, + FAN53555_CHIP_ID_04, + FAN53555_CHIP_ID_05, + FAN53555_CHIP_ID_08 = 8, +}; + +/* IC mask revision */ +enum { + FAN53555_CHIP_REV_00 = 0x3, + FAN53555_CHIP_REV_13 = 0xf, +}; + +enum { + SILERGY_SYR82X = 8, +}; + +enum { + FAN53555_VSEL_ID_0 = 0, + FAN53555_VSEL_ID_1, +}; + +struct fan53555_regulator_info { + enum fan53555_vendor vendor; + struct udevice *dev; + /* IC Type and Rev */ + int chip_id; + int chip_rev; + /* Voltage setting register */ + unsigned int vol_reg; + unsigned int sleep_reg; + unsigned int mode_reg; + unsigned int vol_mask; + unsigned int mode_mask; + /* Voltage range and step(linear) */ + unsigned int vsel_min; + unsigned int vsel_step; + struct gpio_desc vsel_gpio; + unsigned int sleep_vsel_id; +}; + +static int fan53555_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) { + debug("%s: write reg 0x%02x failed, ret=%d\n", + __func__, reg, ret); + return ret; + } + + return 0; +} + +static int fan53555_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) { + debug("%s: read reg 0x%02x failed, ret=%d\n", + __func__, reg, ret); + return ret; + } + + return 0; +} + +int fan53555_reg_read(struct udevice *dev, uint reg) +{ + u8 byte; + int ret; + + debug("%s: reg=%x", __func__, reg); + ret = fan53555_read(dev, reg, &byte, 1); + debug(", value=%x, ret=%d\n", byte, ret); + + return ret ? ret : byte; +} + +int fan53555_reg_write(struct udevice *dev, uint reg, uint value) +{ + u8 byte = value; + int ret; + + debug("%s: reg=%x, value=%x", __func__, reg, value); + ret = fan53555_write(dev, reg, &byte, 1); + debug(", ret=%d\n", ret); + + return ret; +} + +int fan53555_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) +{ + u8 byte; + int ret; + + ret = fan53555_reg_read(dev, reg); + if (ret < 0) + return ret; + byte = (ret & ~clr) | set; + + return fan53555_reg_write(dev, reg, byte); +} + +static int fan53555_regulator_set_enable(struct udevice *dev, bool enable) +{ + struct fan53555_regulator_info *priv = dev_get_priv(dev); + int val, sleep_vsel_id; + + if (enable) { + val = VSEL_BUCK_EN; + sleep_vsel_id = !priv->sleep_vsel_id; + } else { + val = 0; + sleep_vsel_id = priv->sleep_vsel_id; + } + + if (dm_gpio_is_valid(&priv->vsel_gpio)) { + dm_gpio_set_value(&priv->vsel_gpio, sleep_vsel_id); + return 0; + } + fan53555_clrsetbits(dev, priv->vol_reg, VSEL_BUCK_EN, val); + + return 0; +} + +static int fan53555_regulator_get_enable(struct udevice *dev) +{ + struct fan53555_regulator_info *priv = dev_get_priv(dev); + int val; + + if (dm_gpio_is_valid(&priv->vsel_gpio)) { + if (priv->sleep_vsel_id) + return !dm_gpio_get_value(&priv->vsel_gpio); + else + return dm_gpio_get_value(&priv->vsel_gpio); + } + + val = fan53555_reg_read(dev, priv->vol_reg); + if (val & VSEL_BUCK_EN) + return 1; + else + return 0; +} + +static int fan53555_regulator_set_suspend_enable(struct udevice *dev, + bool enable) +{ + struct fan53555_regulator_info *priv = dev_get_priv(dev); + int val; + + if (enable) + val = VSEL_BUCK_EN; + else + val = 0; + + fan53555_clrsetbits(dev, priv->sleep_reg, VSEL_BUCK_EN, val); + + return 0; +} + +static int fan53555_regulator_get_suspend_enable(struct udevice *dev) +{ + struct fan53555_regulator_info *priv = dev_get_priv(dev); + int val; + + val = fan53555_reg_read(dev, priv->sleep_reg); + if (val & VSEL_BUCK_EN) + return 1; + else + return 0; +} + +static int fan53555_regulator_get_voltage(struct udevice *dev) +{ + struct fan53555_regulator_info *priv = dev_get_priv(dev); + int uvolt = 0, val; + + val = fan53555_reg_read(dev, priv->vol_reg); + val &= priv->vol_mask; + uvolt = (val * priv->vsel_step) + priv->vsel_min; + + return uvolt; +} + +static int fan53555_regulator_set_voltage(struct udevice *dev, int uvolt) +{ + struct fan53555_regulator_info *priv = dev_get_priv(dev); + int val; + + val = ((uvolt - priv->vsel_min) / priv->vsel_step); + fan53555_clrsetbits(dev, priv->vol_reg, priv->vol_mask, val); + + return 0; +} + +static int fan53555_regulator_get_suspend_voltage(struct udevice *dev) +{ + struct fan53555_regulator_info *priv = dev_get_priv(dev); + int uvolt = 0, val; + + val = fan53555_reg_read(dev, priv->sleep_reg); + val &= priv->vol_mask; + uvolt = (val * priv->vsel_step) + priv->vsel_min; + + return uvolt; +} + +static int fan53555_regulator_set_suspend_voltage(struct udevice *dev, + int uvolt) +{ + struct fan53555_regulator_info *priv = dev_get_priv(dev); + int val; + + val = ((uvolt - priv->vsel_min) / priv->vsel_step); + fan53555_clrsetbits(dev, priv->sleep_reg, priv->vol_mask, val); + + return 0; +} + +static int fan53555_voltages_setup_fairchild(struct fan53555_regulator_info *di) +{ + /* Init voltage range and step */ + switch (di->chip_id) { + case FAN53555_CHIP_ID_00: + switch (di->chip_rev) { + case FAN53555_CHIP_REV_00: + di->vsel_min = 600000; + di->vsel_step = 10000; + break; + case FAN53555_CHIP_REV_13: + di->vsel_min = 800000; + di->vsel_step = 10000; + break; + default: + dev_err(di->dev, + "Chip ID %d with rev %d not supported!\n", + di->chip_id, di->chip_rev); + return -EINVAL; + } + break; + case FAN53555_CHIP_ID_01: + case FAN53555_CHIP_ID_03: + case FAN53555_CHIP_ID_05: + case FAN53555_CHIP_ID_08: + di->vsel_min = 600000; + di->vsel_step = 10000; + break; + case FAN53555_CHIP_ID_04: + di->vsel_min = 603000; + di->vsel_step = 12826; + break; + default: + dev_err(di->dev, + "Chip ID %d not supported!\n", di->chip_id); + return -EINVAL; + } + di->vol_mask = VSEL_NSEL_MASK; + + return 0; +} + +static int fan53555_voltages_setup_silergy(struct fan53555_regulator_info *di) +{ + /* Init voltage range and step */ + di->vsel_min = 712500; + di->vsel_step = 12500; + di->vol_mask = VSEL_NSEL_MASK; + + return 0; +} + +static int fan53555_voltages_setup_tcs(struct fan53555_regulator_info *di) +{ + if (di->sleep_vsel_id) { + di->sleep_reg = TCS452X_VSEL1; + di->vol_reg = TCS452X_VSEL0; + } else { + di->sleep_reg = TCS452X_VSEL0; + di->vol_reg = TCS452X_VSEL1; + } + + di->vol_mask = TCS_VSEL_NSEL_MASK; + + /* Init voltage range and step */ + di->vsel_min = 600000; + di->vsel_step = 6250; + + return 0; +} + +/* For 00,01,03,05 options: + * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. + * For 04 option: + * VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V. + * + */ + +static int fan53555_device_setup(struct fan53555_regulator_info *di) +{ + int ret = 0; + + /* Setup voltage control register */ + switch (di->sleep_vsel_id) { + case FAN53555_VSEL_ID_0: + di->sleep_reg = FAN53555_VSEL0; + di->vol_reg = FAN53555_VSEL1; + break; + case FAN53555_VSEL_ID_1: + di->sleep_reg = FAN53555_VSEL1; + di->vol_reg = FAN53555_VSEL0; + break; + default: + dev_err(di->dev, "Invalid VSEL ID!\n"); + return -EINVAL; + } + + switch (di->vendor) { + case FAN53555_VENDOR_FAIRCHILD: + ret = fan53555_voltages_setup_fairchild(di); + break; + case FAN53555_VENDOR_SILERGY: + ret = fan53555_voltages_setup_silergy(di); + break; + case FAN53555_VENDOR_TCS: + ret = fan53555_voltages_setup_tcs(di); + break; + default: + dev_err(di->dev, "vendor %d not supported!\n", di->vendor); + return -EINVAL; + } + + return ret; +} + +static int fan53555_regulator_ofdata_to_platdata(struct udevice *dev) +{ + struct fan53555_regulator_info *priv = dev_get_priv(dev); + int ret; + + priv->sleep_vsel_id = dev_read_u32_default(dev, + "fcs,suspend-voltage-selector", + 1); + + ret = gpio_request_by_name(dev, "vsel-gpios", 0, + &priv->vsel_gpio, GPIOD_IS_OUT); + if (ret) + dev_err(dev, "vsel-gpios- not found! Error: %d\n", ret); + + if (dm_gpio_is_valid(&priv->vsel_gpio)) + dm_gpio_set_value(&priv->vsel_gpio, !priv->sleep_vsel_id); + + priv->vendor = dev_get_driver_data(dev); + + return 0; +} + +static int fan53555_regulator_probe(struct udevice *dev) +{ + struct fan53555_regulator_info *di = dev_get_priv(dev); + struct dm_regulator_uclass_platdata *uc_pdata; + u8 val; + int ret; + + uc_pdata = dev_get_uclass_platdata(dev); + uc_pdata->type = REGULATOR_TYPE_BUCK; + uc_pdata->mode_count = 0; + + /* Get chip ID */ + val = fan53555_reg_read(dev, FAN53555_ID1); + if (val < 0) { + dev_err(dev, "Failed to get chip ID!\n"); + return val; + } + di->chip_id = val & DIE_ID; + + /* Get chip revision */ + val = fan53555_reg_read(dev, FAN53555_ID2); + if (val < 0) { + dev_err(dev, "Failed to get chip Rev!\n"); + return val; + } + di->chip_rev = val & DIE_REV; + + debug("FAN53555 Option[%d] Rev[%d] Detected!\n", + di->chip_id, di->chip_rev); + + /* Device init */ + ret = fan53555_device_setup(di); + if (ret < 0) { + dev_err(dev, "Failed to setup device!\n"); + return ret; + } + + return 0; +} + +static const struct udevice_id fan53555_id[] = { + { + .compatible = "fan53555", + .data = FAN53555_VENDOR_FAIRCHILD, + }, { + .compatible = "silergy,syr827", + .data = FAN53555_VENDOR_SILERGY, + }, { + .compatible = "silergy,syr828", + .data = FAN53555_VENDOR_SILERGY, + }, { + .compatible = "tcs,tcs452x", /* tcs4525/4526 */ + .data = FAN53555_VENDOR_TCS, + }, + { }, +}; + +static const struct dm_regulator_ops fan53555_regulator_ops = { + .get_value = fan53555_regulator_get_voltage, + .set_value = fan53555_regulator_set_voltage, + .set_suspend_value = fan53555_regulator_set_suspend_voltage, + .get_suspend_value = fan53555_regulator_get_suspend_voltage, + .set_enable = fan53555_regulator_set_enable, + .get_enable = fan53555_regulator_get_enable, + .set_suspend_enable = fan53555_regulator_set_suspend_enable, + .get_suspend_enable = fan53555_regulator_get_suspend_enable, +}; + +U_BOOT_DRIVER(fan53555_regulator) = { + .name = "fan53555_regulator", + .id = UCLASS_REGULATOR, + .ops = &fan53555_regulator_ops, + .probe = fan53555_regulator_probe, + .of_match = fan53555_id, + .ofdata_to_platdata = fan53555_regulator_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct fan53555_regulator_info), +}; +