From 1ca735225ab43f53328b832aff7e57fe8a0df9f9 Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Mon, 15 Oct 2018 11:51:20 +0800 Subject: [PATCH] regulator: fan53555: add TCS4525 DCDC support TCS4525 main features: - 2.7V to 5.5V Input Voltage Range; - 3MHz Constant Switching Frequency; - 5A Available Load Current; - Programmable Output Voltage: 0.6V to 1.4V in 6.25mV Steps; - PFM/PWM Operation for Optimum Increased Efficiency; Change-Id: I7d4b8bbf38a5c74174b16ae4cb64d04f903a2902 Signed-off-by: Joseph Chen Signed-off-by: Elaine Zhang --- drivers/regulator/fan53555.c | 172 +++++++++++++++++++++++++---------- 1 file changed, 124 insertions(+), 48 deletions(-) diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 059cf3330bfa..babc18213606 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -26,6 +26,13 @@ /* 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 +#define TCS452X_LIMCONF 0x16 + /* Control register */ #define FAN53555_CONTROL 0x02 /* IC Type */ @@ -38,6 +45,7 @@ /* VSEL bit definitions */ #define VSEL_BUCK_EN (1 << 7) #define VSEL_MODE (1 << 6) +#define VSEL_NSEL_MASK 0x3F /* Chip ID and Verison */ #define DIE_ID 0x0F /* ID1 */ #define DIE_REV 0x0F /* ID2 */ @@ -49,13 +57,21 @@ #define CTL_MODE_VSEL0_MODE BIT(0) #define CTL_MODE_VSEL1_MODE BIT(1) -#define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ -#define FAN53526_NVOLTAGES 128 +#define TCS_VSEL_NSEL_MASK 0x7f +#define TCS_VSEL0_MODE (1 << 7) +#define TCS_VSEL1_MODE (1 << 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 { FAN53526_VENDOR_FAIRCHILD = 0, FAN53555_VENDOR_FAIRCHILD, FAN53555_VENDOR_SILERGY, + FAN53555_VENDOR_TCS, }; enum { @@ -90,8 +106,10 @@ enum { struct fan53555_device_info { enum fan53555_vendor vendor; + struct regmap *regmap; struct device *dev; struct regulator_desc desc; + struct regulator_dev *rdev; struct regulator_init_data *regulator; /* IC Type and Rev */ int chip_id; @@ -99,13 +117,18 @@ struct fan53555_device_info { /* Voltage setting register */ unsigned int vol_reg; unsigned int sleep_reg; + unsigned int mode_reg; + unsigned int vol_mask; + unsigned int mode_mask; + unsigned int slew_reg; + unsigned int slew_mask; + unsigned int slew_shift; /* Voltage range and step(linear) */ unsigned int vsel_min; unsigned int vsel_step; - unsigned int vsel_count; - /* Mode */ - unsigned int mode_reg; - unsigned int mode_mask; + unsigned int n_voltages; + /* Voltage slew rate limiting */ + unsigned int slew_rate; /* Sleep voltage cache */ unsigned int sleep_vol_cache; struct gpio_desc *vsel_gpio; @@ -128,8 +151,8 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) ret = regulator_map_voltage_linear(rdev, uV, uV); if (ret < 0) return ret; - ret = regmap_update_bits(rdev->regmap, di->sleep_reg, - di->desc.vsel_mask, ret); + ret = regmap_update_bits(di->regmap, di->sleep_reg, + di->vol_mask, ret); if (ret < 0) return ret; /* Cache the sleep voltage setting. @@ -143,7 +166,7 @@ static int fan53555_set_suspend_enable(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); - return regmap_update_bits(rdev->regmap, di->sleep_reg, + return regmap_update_bits(di->regmap, di->sleep_reg, VSEL_BUCK_EN, VSEL_BUCK_EN); } @@ -151,7 +174,7 @@ static int fan53555_set_suspend_disable(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); - return regmap_update_bits(rdev->regmap, di->sleep_reg, + return regmap_update_bits(di->regmap, di->sleep_reg, VSEL_BUCK_EN, 0); } @@ -209,11 +232,11 @@ static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) switch (mode) { case REGULATOR_MODE_FAST: - regmap_update_bits(rdev->regmap, di->mode_reg, + regmap_update_bits(di->regmap, di->mode_reg, di->mode_mask, di->mode_mask); break; case REGULATOR_MODE_NORMAL: - regmap_update_bits(rdev->regmap, di->vol_reg, di->mode_mask, 0); + regmap_update_bits(di->regmap, di->mode_reg, di->mode_mask, 0); break; default: return -EINVAL; @@ -227,7 +250,7 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev) unsigned int val; int ret = 0; - ret = regmap_read(rdev->regmap, di->mode_reg, &val); + ret = regmap_read(di->regmap, di->mode_reg, &val); if (ret < 0) return ret; if (val & di->mode_mask) @@ -247,13 +270,36 @@ static const int slew_rates[] = { 500, }; +static const int tcs_slew_rates[] = { + 18700, + 9300, + 4600, + 2300, +}; + static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); int regval = -1, i; + const int *slew_rate_t; + int slew_rate_n; - for (i = 0; i < ARRAY_SIZE(slew_rates); i++) { - if (ramp <= slew_rates[i]) + switch (di->vendor) { + case FAN53555_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_SILERGY: + slew_rate_t = slew_rates; + slew_rate_n = ARRAY_SIZE(slew_rates); + break; + case FAN53555_VENDOR_TCS: + slew_rate_t = tcs_slew_rates; + slew_rate_n = ARRAY_SIZE(tcs_slew_rates); + break; + default: + return -EINVAL; + } + + for (i = 0; i < slew_rate_n; i++) { + if (ramp <= slew_rate_t[i]) regval = i; else break; @@ -264,8 +310,8 @@ static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) return -EINVAL; } - return regmap_update_bits(rdev->regmap, FAN53555_CONTROL, - CTL_SLEW_MASK, regval << CTL_SLEW_SHIFT); + return regmap_update_bits(di->regmap, di->slew_reg, + di->slew_mask, regval << di->slew_shift); } static const struct regulator_ops fan53555_regulator_ops = { @@ -308,7 +354,7 @@ static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di) return -EINVAL; } - di->vsel_count = FAN53526_NVOLTAGES; + di->n_voltages = FAN53555_NVOLTAGES_64; return 0; } @@ -350,8 +396,13 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) "Chip ID %d not supported!\n", di->chip_id); return -EINVAL; } - - di->vsel_count = FAN53555_NVOLTAGES; + di->vol_mask = VSEL_NSEL_MASK; + di->mode_reg = di->vol_reg; + di->mode_mask = VSEL_MODE; + di->slew_reg = FAN53555_CONTROL; + di->slew_mask = CTL_SLEW_MASK; + di->slew_shift = CTL_SLEW_SHIFT; + di->n_voltages = FAN53555_NVOLTAGES_64; return 0; } @@ -370,8 +421,40 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) "Chip ID %d not supported!\n", di->chip_id); return -EINVAL; } + di->vol_mask = VSEL_NSEL_MASK; + di->mode_reg = di->vol_reg; + di->mode_mask = VSEL_MODE; + di->slew_reg = FAN53555_CONTROL; + di->slew_reg = FAN53555_CONTROL; + di->slew_mask = CTL_SLEW_MASK; + di->slew_shift = CTL_SLEW_SHIFT; + di->n_voltages = FAN53555_NVOLTAGES_64; - di->vsel_count = FAN53555_NVOLTAGES; + return 0; +} + +static int fan53555_voltages_setup_tcs(struct fan53555_device_info *di) +{ + if (di->sleep_vsel_id) { + di->sleep_reg = TCS452X_VSEL1; + di->vol_reg = TCS452X_VSEL0; + di->mode_mask = TCS_VSEL0_MODE; + } else { + di->sleep_reg = TCS452X_VSEL0; + di->vol_reg = TCS452X_VSEL1; + di->mode_mask = TCS_VSEL1_MODE; + } + + di->mode_reg = TCS452X_COMMAND; + di->vol_mask = TCS_VSEL_NSEL_MASK; + di->slew_reg = TCS452X_TIME; + di->slew_mask = TCS_SLEW_MASK; + di->slew_shift = TCS_SLEW_MASK; + + /* Init voltage range and step */ + di->vsel_min = 600000; + di->vsel_step = 6250; + di->n_voltages = FAN53555_NVOLTAGES_127; return 0; } @@ -401,7 +484,7 @@ static int fan53555_device_setup(struct fan53555_device_info *di, return -EINVAL; } - /* Setup mode control register */ + /* Setup voltage range */ switch (di->vendor) { case FAN53526_VENDOR_FAIRCHILD: di->mode_reg = FAN53555_CONTROL; @@ -414,20 +497,6 @@ static int fan53555_device_setup(struct fan53555_device_info *di, di->mode_mask = CTL_MODE_VSEL0_MODE; break; } - break; - case FAN53555_VENDOR_FAIRCHILD: - case FAN53555_VENDOR_SILERGY: - di->mode_reg = di->vol_reg; - di->mode_mask = VSEL_MODE; - break; - default: - dev_err(di->dev, "vendor %d not supported!\n", di->vendor); - return -EINVAL; - } - - /* Setup voltage range */ - switch (di->vendor) { - case FAN53526_VENDOR_FAIRCHILD: ret = fan53526_voltages_setup_fairchild(di); break; case FAN53555_VENDOR_FAIRCHILD: @@ -436,6 +505,9 @@ static int fan53555_device_setup(struct fan53555_device_info *di, 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; @@ -448,24 +520,23 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, struct regulator_config *config) { struct regulator_desc *rdesc = &di->desc; - struct regulator_dev *rdev; rdesc->name = "fan53555-reg"; rdesc->supply_name = "vin"; rdesc->ops = &fan53555_regulator_ops; rdesc->type = REGULATOR_VOLTAGE; - rdesc->n_voltages = di->vsel_count; + rdesc->n_voltages = di->n_voltages; rdesc->enable_reg = di->vol_reg; rdesc->enable_mask = VSEL_BUCK_EN; rdesc->min_uV = di->vsel_min; rdesc->uV_step = di->vsel_step; rdesc->vsel_reg = di->vol_reg; - rdesc->vsel_mask = di->vsel_count - 1; + rdesc->vsel_mask = di->vol_mask; rdesc->owner = THIS_MODULE; rdesc->enable_time = 400; - rdev = devm_regulator_register(di->dev, &di->desc, config); - return PTR_ERR_OR_ZERO(rdev); + di->rdev = devm_regulator_register(di->dev, &di->desc, config); + return PTR_ERR_OR_ZERO(di->rdev); } static const struct regmap_config fan53555_regmap_config = { @@ -523,6 +594,9 @@ static const struct of_device_id __maybe_unused fan53555_dt_ids[] = { }, { .compatible = "silergy,syr828", .data = (void *)FAN53555_VENDOR_SILERGY, + }, { + .compatible = "tcs,tcs452x", /* tcs4525/4526 */ + .data = (void *)FAN53555_VENDOR_TCS }, { } }; @@ -535,7 +609,6 @@ static int fan53555_regulator_probe(struct i2c_client *client, struct fan53555_device_info *di; struct fan53555_platform_data *pdata; struct regulator_config config = { }; - struct regmap *regmap; unsigned int val; int ret; @@ -577,22 +650,22 @@ static int fan53555_regulator_probe(struct i2c_client *client, di->vendor = id->driver_data; } - regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config); - if (IS_ERR(regmap)) { + di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config); + if (IS_ERR(di->regmap)) { dev_err(&client->dev, "Failed to allocate regmap!\n"); - return PTR_ERR(regmap); + return PTR_ERR(di->regmap); } di->dev = &client->dev; i2c_set_clientdata(client, di); /* Get chip ID */ - ret = regmap_read(regmap, FAN53555_ID1, &val); + ret = regmap_read(di->regmap, FAN53555_ID1, &val); if (ret < 0) { dev_err(&client->dev, "Failed to get chip ID!\n"); return ret; } di->chip_id = val & DIE_ID; /* Get chip revision */ - ret = regmap_read(regmap, FAN53555_ID2, &val); + ret = regmap_read(di->regmap, FAN53555_ID2, &val); if (ret < 0) { dev_err(&client->dev, "Failed to get chip Rev!\n"); return ret; @@ -609,7 +682,7 @@ static int fan53555_regulator_probe(struct i2c_client *client, /* Register regulator */ config.dev = di->dev; config.init_data = di->regulator; - config.regmap = regmap; + config.regmap = di->regmap; config.driver_data = di; config.of_node = np; @@ -633,6 +706,9 @@ static const struct i2c_device_id fan53555_id[] = { }, { .name = "syr828", .driver_data = FAN53555_VENDOR_SILERGY + }, { + .name = "tcs452x", + .driver_data = FAN53555_VENDOR_TCS }, { }, };