diff options
| author | GuEe-GUI <[email protected]> | 2026-06-15 15:10:18 +0800 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2026-06-23 08:02:09 +0800 |
| commit | b2e1f13a05a880d536d3a72a391ff18303c30f89 (patch) | |
| tree | 48c6d71a5b78e42d85684f5bd5c11faf5c751f1f /components/drivers | |
| parent | 741d82c42b1ae96fe3634be4469fb2f33def2df7 (diff) | |
[bsp][rockchip] support DVFS for Rockchip
The I2C will timeout in fan53555, fixed it.
Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components/drivers')
| -rw-r--r-- | components/drivers/regulator/Kconfig | 6 | ||||
| -rwxr-xr-x | components/drivers/regulator/SConscript | 3 | ||||
| -rw-r--r-- | components/drivers/regulator/regulator-fan53555.c | 1091 |
3 files changed, 1100 insertions, 0 deletions
diff --git a/components/drivers/regulator/Kconfig b/components/drivers/regulator/Kconfig index 17d2f5b17a..8767d59a7d 100644 --- a/components/drivers/regulator/Kconfig +++ b/components/drivers/regulator/Kconfig @@ -4,6 +4,12 @@ menuconfig RT_USING_REGULATOR select RT_USING_ADT_REF default n +config RT_REGULATOR_FAN53555 + bool "Fairchild FAN53555 / TCS4525 Regulator" + depends on RT_USING_REGULATOR + depends on RT_USING_I2C + default n + config RT_REGULATOR_FIXED bool "Fixed regulator support" depends on RT_USING_REGULATOR diff --git a/components/drivers/regulator/SConscript b/components/drivers/regulator/SConscript index 2069f50869..70245b9c49 100755 --- a/components/drivers/regulator/SConscript +++ b/components/drivers/regulator/SConscript @@ -10,6 +10,9 @@ CPPPATH = [cwd + '/../include'] src = ['regulator.c', 'regulator_dm.c', 'regulator_cmd.c'] +if GetDepend(['RT_REGULATOR_FAN53555']): + src += ['regulator-fan53555.c'] + if GetDepend(['RT_REGULATOR_FIXED']): src += ['regulator-fixed.c'] diff --git a/components/drivers/regulator/regulator-fan53555.c b/components/drivers/regulator/regulator-fan53555.c new file mode 100644 index 0000000000..3d5e58eb54 --- /dev/null +++ b/components/drivers/regulator/regulator-fan53555.c @@ -0,0 +1,1091 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#define DBG_TAG "regulator.fan53555" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#include "regulator_dm.h" + +/* Voltage setting */ +#define FAN53555_VSEL0 0x00 +#define FAN53555_VSEL1 0x01 + +#define TCS4525_VSEL0 0x11 +#define TCS4525_VSEL1 0x10 +#define TCS4525_TIME 0x13 +#define TCS4525_COMMAND 0x14 +#define TCS4525_LIMCONF 0x16 + +#define RK8600_VSEL0 FAN53555_VSEL0 +#define RK8600_VSEL1 FAN53555_VSEL1 +#define RK8602_VSEL0 0x06 +#define RK8602_VSEL1 0x07 +#define RK860X_MAX_SET 0x08 + +/* 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 RT_BIT(7) +#define VSEL_MODE RT_BIT(6) +#define RK8600_VSEL_NSEL_MASK 0x3f +#define RK8602_VSEL_NSEL_MASK 0xff +/* Chip ID */ +#define DIE_ID 0x0f +#define DIE_REV 0x0f +/* Control bit definitions */ +#define CTL_OUTPUT_DISCHG RT_BIT(7) +#define CTL_SLEW_MASK (0x7 << 4) +#define CTL_SLEW_SHIFT 4 +#define CTL_RESET RT_BIT(2) +#define CTL_MODE_VSEL0_MODE RT_BIT(0) +#define CTL_MODE_VSEL1_MODE RT_BIT(1) + +#define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ +#define FAN53526_NVOLTAGES 128 +#define RK8600_NVOLTAGES FAN53555_NVOLTAGES +#define RK8602_NVOLTAGES 160 + +#define TCS_VSEL0_MODE RT_BIT(7) +#define TCS_VSEL1_MODE RT_BIT(6) + +#define TCS_SLEW_MASK (0x3 << 3) +#define TCS_SLEW_SHIFT 3 + +/* VSEL ID */ +enum +{ + FAN53555_VSEL_ID_0 = 0, + FAN53555_VSEL_ID_1, +}; + +enum fan53555_vendor +{ + FAN53526_VENDOR_FAIRCHILD = 0, + FAN53555_VENDOR_FAIRCHILD, + RK8600_VENDOR_ROCKCHIP, /* RK8600, RK8601 */ + RK8602_VENDOR_ROCKCHIP, /* RK8602, RK8603 */ + FAN53555_VENDOR_SILERGY, + FAN53526_VENDOR_TCS, +}; + +enum +{ + FAN53526_CHIP_ID_01 = 1, +}; + +enum +{ + FAN53526_CHIP_REV_08 = 8, +}; + +/* 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, +}; + +enum +{ + RK8600_CHIP_ID_08 = 8, /* RK8600, RK8601 */ + RK8602_CHIP_ID_10 = 10, /* RK8602, RK8603 */ +}; + +enum +{ + TCS4525_CHIP_ID_12 = 12, +}; + +enum +{ + TCS4526_CHIP_ID_00 = 0, +}; + +/* IC mask revision */ +enum +{ + FAN53555_CHIP_REV_00 = 0x3, + FAN53555_CHIP_REV_13 = 0xf, +}; + +enum +{ + SILERGY_SYR82X = 8, + SILERGY_SYR83X = 9, +}; + +struct fan53555_regulator +{ + struct rt_regulator_node parent; + struct rt_regulator_param param; + + struct rt_i2c_client *client; + + rt_ubase_t vsel_pin; + + /* IC Type and Rev */ + int chip_id; + int chip_rev; + enum fan53555_vendor vendor; + + rt_uint32_t limit_volt; + + /* Voltage setting register */ + rt_uint32_t vol_reg; + rt_uint32_t vol_mask; + rt_uint32_t sleep_reg; + rt_uint32_t en_reg; + rt_uint32_t sleep_en_reg; + /* Mode */ + rt_uint32_t mode_reg; + rt_uint32_t mode_mask; + /* Slew rate */ + rt_uint32_t slew_reg; + rt_uint32_t slew_mask; + rt_uint32_t slew_shift; + /* Voltage range and step(linear) */ + rt_uint32_t vsel_min; + rt_uint32_t vsel_step; + rt_uint32_t vsel_count; + + /* Voltage slew rate limiting */ + rt_uint32_t slew_rate; + rt_uint32_t sleep_vsel_id; + + const int *ramp_delay_table; + int ramp_delay_nr; +}; + +#define raw_to_fan53555_regulator(raw) rt_container_of(raw, struct fan53555_regulator, parent) + +static rt_uint32_t fan53555_vol_mask(rt_uint32_t vsel_count) +{ + rt_uint32_t bit; + + if (!vsel_count) + { + return 0; + } + + bit = 32 - __rt_clz(vsel_count - 1); + + return (1U << bit) - 1; +} + +static const int slew_rates[] = +{ + 64000, 32000, 16000, 8000, 4000, 2000, 1000, 500, +}; + +static const int tcs_slew_rates[] = +{ + 18700, 9300, 4600, 2300, +}; + +static rt_err_t fan53555_regulator_write(struct fan53555_regulator *freg, + rt_uint8_t reg, rt_uint8_t value) +{ + rt_int32_t res; + struct rt_i2c_msg msg[1]; + rt_uint8_t data[sizeof(reg) + sizeof(value)] = { reg }; + struct rt_i2c_client *client = freg->client; + + rt_memcpy(&data[sizeof(reg)], &value, sizeof(value)); + + msg[0].buf = data; + msg[0].addr = client->client_addr; + msg[0].len = sizeof(data); + msg[0].flags = RT_I2C_WR; + + res = rt_i2c_transfer(client->bus, msg, 1); + + return res > 0 ? RT_EOK : res; +} + +static rt_err_t fan53555_regulator_read(struct fan53555_regulator *freg, + rt_uint8_t reg, rt_uint8_t *values) +{ + rt_int32_t res; + struct rt_i2c_msg msg[2]; + struct rt_i2c_client *client = freg->client; + + msg[0].buf = ® + msg[0].addr = client->client_addr; + msg[0].len = sizeof(reg); + msg[0].flags = RT_I2C_WR; + + msg[1].buf = (rt_uint8_t *)values; + msg[1].addr = client->client_addr; + msg[1].len = sizeof(*values); + msg[1].flags = RT_I2C_RD; + + res = rt_i2c_transfer(client->bus, msg, 2); + + return res >= 2 ? RT_EOK : (res < 0 ? (rt_err_t)res : -RT_EIO); +} + +static rt_err_t fan53555_regulator_update_bits(struct fan53555_regulator *freg, + rt_uint8_t reg, rt_uint8_t mask, rt_uint8_t data) +{ + rt_err_t err; + rt_uint8_t old, tmp; + + if ((err = fan53555_regulator_read(freg, reg, &old))) + { + return err; + } + + tmp = old & ~mask; + tmp |= (data & mask); + + return fan53555_regulator_write(freg, reg, tmp); +} + +static rt_err_t fan53555_regulator_enable(struct rt_regulator_node *reg_np) +{ + struct fan53555_regulator *freg = raw_to_fan53555_regulator(reg_np); + + if (freg->vsel_pin >= 0) + { + rt_pin_mode(freg->vsel_pin, PIN_MODE_OUTPUT); + rt_pin_write(freg->vsel_pin, !freg->sleep_vsel_id); + + return RT_EOK; + } + + return fan53555_regulator_update_bits(freg, freg->en_reg, VSEL_BUCK_EN, VSEL_BUCK_EN); +} + +static rt_err_t fan53555_regulator_disable(struct rt_regulator_node *reg_np) +{ + struct fan53555_regulator *freg = raw_to_fan53555_regulator(reg_np); + + if (freg->vsel_pin >= 0) + { + rt_pin_mode(freg->vsel_pin, PIN_MODE_OUTPUT); + rt_pin_write(freg->vsel_pin, freg->sleep_vsel_id); + + return RT_EOK; + } + + return fan53555_regulator_update_bits(freg, freg->en_reg, VSEL_BUCK_EN, 0); +} + +static rt_bool_t fan53555_regulator_is_enabled(struct rt_regulator_node *reg_np) +{ + rt_err_t err; + rt_uint8_t val; + struct fan53555_regulator *freg = raw_to_fan53555_regulator(reg_np); + + if (freg->vsel_pin >= 0) + { + rt_uint8_t pin_val; + + rt_pin_mode(freg->vsel_pin, PIN_MODE_INPUT); + pin_val = rt_pin_read(freg->vsel_pin); + + return freg->sleep_vsel_id ? !pin_val : pin_val; + } + + if ((err = fan53555_regulator_read(freg, freg->en_reg, &val))) + { + LOG_E("Read %s register error = %s", "enable", rt_strerror(err)); + + return RT_FALSE; + } + + if (val & VSEL_BUCK_EN) + { + return RT_TRUE; + } + + return RT_FALSE; +} + +static rt_err_t fan53555_regulator_set_voltage(struct rt_regulator_node *reg_np, + int min_uvolt, int max_uvolt) +{ + int uvolt; + rt_uint8_t selector; + struct fan53555_regulator *freg = raw_to_fan53555_regulator(reg_np); + + if (freg->vsel_count == 1 && freg->vsel_step == 0) + { + if (min_uvolt <= freg->vsel_min && freg->vsel_min <= max_uvolt) + { + return 0; + } + else + { + return -RT_EINVAL; + } + } + + if (!freg->vsel_step) + { + return -RT_EINVAL; + } + + if (min_uvolt < freg->vsel_min) + { + min_uvolt = freg->vsel_min; + } + + selector = RT_DIV_ROUND_UP(min_uvolt - freg->vsel_min, freg->vsel_step); + + if ((rt_int8_t)selector < 0) + { + return selector; + } + + if (selector >= freg->vsel_count) + { + return -RT_EINVAL; + } + + uvolt = freg->vsel_min + (freg->vsel_step * selector); + + if (uvolt < min_uvolt || uvolt > max_uvolt) + { + return -RT_EINVAL; + } + + selector <<= __rt_ffs(freg->vol_mask) - 1; + + return fan53555_regulator_update_bits(freg, freg->vol_reg, freg->vol_mask, selector); +} + +static int fan53555_regulator_get_voltage(struct rt_regulator_node *reg_np) +{ + rt_err_t err; + rt_uint8_t selector; + struct fan53555_regulator *freg = raw_to_fan53555_regulator(reg_np); + + if ((err = fan53555_regulator_read(freg, freg->vol_reg, &selector))) + { + return err; + } + + selector = (selector & freg->vol_mask) >> (__rt_ffs(freg->vol_mask) - 1); + + if (selector >= freg->vsel_count) + { + return -RT_EINVAL; + } + + return freg->vsel_min + (freg->vsel_step * selector); +} + +static rt_err_t fan53555_regulator_set_mode(struct rt_regulator_node *reg_np, + rt_uint32_t mode) +{ + struct fan53555_regulator *freg = raw_to_fan53555_regulator(reg_np); + + switch (mode) + { + case RT_REGULATOR_MODE_FAST: + fan53555_regulator_update_bits(freg, + freg->mode_reg, freg->mode_mask, freg->mode_mask); + break; + + case RT_REGULATOR_MODE_NORMAL: + fan53555_regulator_update_bits(freg, + freg->mode_reg, freg->mode_mask, 0); + break; + + default: + return -RT_EINVAL; + } + + return RT_EOK; +} + +static rt_int32_t fan53555_regulator_get_mode(struct rt_regulator_node *reg_np) +{ + rt_err_t err; + rt_uint8_t val; + struct fan53555_regulator *freg = raw_to_fan53555_regulator(reg_np); + + if ((err = fan53555_regulator_read(freg, freg->mode_reg, &val))) + { + LOG_E("Read %s register error = %s", "mode", rt_strerror(err)); + + return RT_FALSE; + } + + if (val & freg->mode_mask) + { + return RT_REGULATOR_MODE_FAST; + } + else + { + return RT_REGULATOR_MODE_NORMAL; + } +} + +static rt_err_t fan53555_regulator_set_ramp_delay(struct rt_regulator_node *reg_np, + int ramp) +{ + int regval = -1, ramp_delay_nr; + const int *ramp_delay_table; + struct fan53555_regulator *freg = raw_to_fan53555_regulator(reg_np); + + ramp_delay_nr = freg->ramp_delay_nr; + ramp_delay_table = freg->ramp_delay_table; + + for (int i = 0; i < ramp_delay_nr; ++i) + { + if (ramp <= ramp_delay_table[i]) + { + regval = i; + continue; + } + + break; + } + + if (regval < 0) + { + LOG_E("unsupported ramp value %d", ramp); + + return -RT_EINVAL; + } + + return fan53555_regulator_update_bits(freg, freg->slew_reg, + freg->slew_mask, regval << freg->slew_shift); +} + +static const struct rt_regulator_ops fan53555_regulator_switch_ops = +{ + .enable = fan53555_regulator_enable, + .disable = fan53555_regulator_disable, + .is_enabled = fan53555_regulator_is_enabled, + .set_voltage = fan53555_regulator_set_voltage, + .get_voltage = fan53555_regulator_get_voltage, + .set_mode = fan53555_regulator_set_mode, + .get_mode = fan53555_regulator_get_mode, + .set_ramp_delay = fan53555_regulator_set_ramp_delay, +}; + +#ifdef RT_USING_OFW +static rt_err_t fan53555_regulator_parse_ofw(struct fan53555_regulator *freg, + struct rt_device *dev) +{ + rt_err_t err; + struct rt_ofw_node *np = dev->ofw_node; + + if ((err = regulator_ofw_parse(np, &freg->param))) + { + return err; + } + + rt_ofw_prop_read_u32(np, "limit-microvolt", &freg->limit_volt); + + rt_ofw_prop_read_u32(np, "fcs,suspend-voltage-selector", &freg->sleep_vsel_id); + rt_ofw_prop_read_u32(np, "rockchip,suspend-voltage-selector", &freg->sleep_vsel_id); + + freg->vsel_pin = rt_ofw_get_named_pin(np, "vsel", 0, RT_NULL, RT_NULL); + if (freg->vsel_pin < 0) + { + freg->vsel_pin = PIN_NONE; + } + + return RT_EOK; +} +#else +static rt_err_t fan53555_regulator_parse_ofw(struct fan53555_regulator *freg, + struct rt_device *dev) +{ + return RT_EOK; +} +#endif /* RT_USING_OFW */ + +static rt_err_t fan53555_regulator_probe(struct rt_i2c_client *client) +{ + rt_err_t err; + rt_uint8_t val; + rt_bool_t hw_always_on; + rt_uint32_t ramp_delay; + struct rt_regulator_node *rgp; + struct rt_device *dev = &client->parent; + struct fan53555_regulator *freg = rt_calloc(1, sizeof(*freg)); + + if (!freg) + { + return -RT_ENOMEM; + } + + if ((err = fan53555_regulator_parse_ofw(freg, dev))) + { + goto _fail; + } + + if (dev->ofw_node) + { + freg->vendor = (rt_ubase_t)client->ofw_id->data; + } + else + { + if (!freg->param.ramp_delay) + { + int slew_idx = freg->slew_rate; + + if (slew_idx > RT_ARRAY_SIZE(slew_rates)) + { + LOG_E("Invalid slew rate"); + + err = -RT_EINVAL; + goto _fail; + } + + freg->param.ramp_delay = slew_rates[slew_idx]; + } + + freg->vendor = (rt_ubase_t)rt_i2c_client_id_data(client); + } + freg->client = client; + + /* Get chip ID */ + if ((err = fan53555_regulator_read(freg, FAN53555_ID1, &val))) + { + LOG_E("%s: read ID1 failed: %s", client->name, rt_strerror(err)); + goto _fail; + } + freg->chip_id = val & DIE_ID; + + /* Get chip revision */ + if ((err = fan53555_regulator_read(freg, FAN53555_ID2, &val))) + { + LOG_E("%s: read ID2 failed: %s", client->name, rt_strerror(err)); + goto _fail; + } + freg->chip_rev = val & DIE_REV; + + if (freg->sleep_vsel_id > FAN53555_VSEL_ID_1) + { + LOG_E("Invalid vsel-id = %d", freg->sleep_vsel_id); + goto _fail; + } + + /* + * For 00,01 options: + * VOUT = 0.7125V + NSELx * 12.5mV, from 0.7125 to 1.5V. + * For 02,03 options: + * VOUT = 0.5V + NSELx * 6.25mV, from 0.5 to 1.5V. + */ + + /* Setup voltage control register */ + freg->vol_reg = 0xff; + switch (freg->vendor) + { + case FAN53526_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_SILERGY: + switch (freg->sleep_vsel_id) + { + case FAN53555_VSEL_ID_0: + freg->sleep_reg = FAN53555_VSEL0; + freg->vol_reg = FAN53555_VSEL1; + break; + + case FAN53555_VSEL_ID_1: + freg->sleep_reg = FAN53555_VSEL1; + freg->vol_reg = FAN53555_VSEL0; + break; + + default: + break; + } + freg->sleep_en_reg = freg->sleep_reg; + freg->en_reg = freg->vol_reg; + break; + + case RK8600_VENDOR_ROCKCHIP: + switch (freg->sleep_vsel_id) + { + case FAN53555_VSEL_ID_0: + freg->sleep_reg = RK8600_VSEL0; + freg->vol_reg = RK8600_VSEL1; + break; + + case FAN53555_VSEL_ID_1: + freg->sleep_reg = RK8600_VSEL1; + freg->vol_reg = RK8600_VSEL0; + break; + + default: + break; + } + freg->sleep_en_reg = freg->sleep_reg; + freg->en_reg = freg->vol_reg; + freg->vol_reg = RK8600_VSEL_NSEL_MASK; + break; + + case RK8602_VENDOR_ROCKCHIP: + switch (freg->sleep_vsel_id) + { + case FAN53555_VSEL_ID_0: + freg->sleep_reg = RK8602_VSEL0; + freg->vol_reg = RK8602_VSEL1; + freg->sleep_en_reg = RK8600_VSEL0; + freg->en_reg = RK8600_VSEL1; + break; + + case FAN53555_VSEL_ID_1: + freg->sleep_reg = RK8602_VSEL1; + freg->vol_reg = RK8602_VSEL0; + freg->sleep_en_reg = RK8600_VSEL1; + freg->en_reg = RK8600_VSEL0; + break; + + default: + break; + } + freg->vol_reg = RK8602_VSEL_NSEL_MASK; + break; + + case FAN53526_VENDOR_TCS: + switch (freg->sleep_vsel_id) + { + case FAN53555_VSEL_ID_0: + freg->sleep_reg = TCS4525_VSEL0; + freg->vol_reg = TCS4525_VSEL1; + break; + + case FAN53555_VSEL_ID_1: + freg->sleep_reg = TCS4525_VSEL1; + freg->vol_reg = TCS4525_VSEL0; + break; + + default: + break; + } + freg->sleep_en_reg = freg->sleep_reg; + freg->en_reg = freg->vol_reg; + break; + + default: + break; + } + + /* Setup mode control register */ + switch (freg->vendor) + { + case FAN53526_VENDOR_FAIRCHILD: + freg->mode_reg = FAN53555_CONTROL; + + switch (freg->sleep_vsel_id) + { + case FAN53555_VSEL_ID_0: + freg->mode_mask = CTL_MODE_VSEL1_MODE; + break; + + case FAN53555_VSEL_ID_1: + freg->mode_mask = CTL_MODE_VSEL0_MODE; + break; + + default: + break; + } + break; + case FAN53555_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_SILERGY: + case RK8600_VENDOR_ROCKCHIP: + freg->mode_reg = freg->vol_reg; + freg->mode_mask = VSEL_MODE; + break; + + case RK8602_VENDOR_ROCKCHIP: + freg->mode_mask = VSEL_MODE; + + switch (freg->sleep_vsel_id) + { + case FAN53555_VSEL_ID_0: + freg->mode_reg = RK8600_VSEL1; + break; + + case FAN53555_VSEL_ID_1: + freg->mode_reg = RK8600_VSEL0; + break; + + default: + break; + } + break; + + case FAN53526_VENDOR_TCS: + freg->mode_reg = TCS4525_COMMAND; + + switch (freg->sleep_vsel_id) + { + case FAN53555_VSEL_ID_0: + freg->mode_mask = TCS_VSEL1_MODE; + break; + + case FAN53555_VSEL_ID_1: + freg->mode_mask = TCS_VSEL0_MODE; + break; + + default: + break; + } + break; + + default: + break; + } + + /* Setup voltage range */ + switch (freg->vendor) + { + case FAN53526_VENDOR_FAIRCHILD: + /* Init voltage range and step */ + switch (freg->chip_id) + { + case FAN53526_CHIP_ID_01: + switch (freg->chip_rev) + { + case FAN53526_CHIP_REV_08: + freg->vsel_min = 600000; + freg->vsel_step = 6250; + break; + + default: + LOG_E("Chip ID %d with rev %d not supported", + freg->chip_id, freg->chip_rev); + err = -RT_EINVAL; + goto _fail; + } + break; + + default: + LOG_E("Chip ID %d not supported", freg->chip_id); + err = -RT_EINVAL; + goto _fail; + } + + freg->slew_reg = FAN53555_CONTROL; + freg->slew_mask = CTL_SLEW_MASK; + freg->slew_shift = CTL_SLEW_SHIFT; + freg->ramp_delay_table = slew_rates; + freg->ramp_delay_nr = RT_ARRAY_SIZE(slew_rates); + freg->vsel_count = FAN53526_NVOLTAGES; + break; + + case FAN53555_VENDOR_FAIRCHILD: + /* Init voltage range and step */ + switch (freg->chip_id) { + case FAN53555_CHIP_ID_00: + switch (freg->chip_rev) + { + case FAN53555_CHIP_REV_00: + freg->vsel_min = 600000; + freg->vsel_step = 10000; + break; + + case FAN53555_CHIP_REV_13: + freg->vsel_min = 800000; + freg->vsel_step = 10000; + break; + + default: + LOG_E("Chip ID %d with rev %d not supported", + freg->chip_id, freg->chip_rev); + err = -RT_EINVAL; + goto _fail; + } + break; + case FAN53555_CHIP_ID_01: + case FAN53555_CHIP_ID_03: + case FAN53555_CHIP_ID_05: + case FAN53555_CHIP_ID_08: + freg->vsel_min = 600000; + freg->vsel_step = 10000; + break; + + case FAN53555_CHIP_ID_04: + freg->vsel_min = 603000; + freg->vsel_step = 12826; + break; + + default: + LOG_E("Chip ID %d not supported", freg->chip_id); + err = -RT_EINVAL; + goto _fail; + } + + freg->slew_reg = FAN53555_CONTROL; + freg->slew_mask = CTL_SLEW_MASK; + freg->slew_shift = CTL_SLEW_SHIFT; + freg->ramp_delay_table = slew_rates; + freg->ramp_delay_nr = RT_ARRAY_SIZE(slew_rates); + freg->vsel_count = FAN53555_NVOLTAGES; + break; + + case FAN53555_VENDOR_SILERGY: + /* Init voltage range and step */ + switch (freg->chip_id) + { + case SILERGY_SYR82X: + case SILERGY_SYR83X: + freg->vsel_min = 712500; + freg->vsel_step = 12500; + break; + + default: + LOG_E("Chip ID %d not supported", freg->chip_id); + err = -RT_EINVAL; + goto _fail; + } + + freg->slew_reg = FAN53555_CONTROL; + freg->slew_mask = CTL_SLEW_MASK; + freg->slew_shift = CTL_SLEW_SHIFT; + freg->ramp_delay_table = slew_rates; + freg->ramp_delay_nr = RT_ARRAY_SIZE(slew_rates); + freg->vsel_count = FAN53555_NVOLTAGES; + break; + + case RK8600_VENDOR_ROCKCHIP: + /* Init voltage range and step */ + switch (freg->chip_id) + { + case RK8600_CHIP_ID_08: + freg->vsel_min = 712500; + freg->vsel_step = 12500; + break; + + default: + LOG_E("Chip ID %d not supported", freg->chip_id); + err = -RT_EINVAL; + goto _fail; + } + + freg->slew_reg = FAN53555_CONTROL; + freg->slew_mask = CTL_SLEW_MASK; + freg->slew_shift = CTL_SLEW_SHIFT; + freg->ramp_delay_table = slew_rates; + freg->ramp_delay_nr = RT_ARRAY_SIZE(slew_rates); + freg->vsel_count = RK8600_NVOLTAGES; + break; + + case RK8602_VENDOR_ROCKCHIP: + /* Init voltage range and step */ + switch (freg->chip_id) + { + case RK8602_CHIP_ID_10: + freg->vsel_min = 500000; + freg->vsel_step = 6250; + break; + + default: + LOG_E("Chip ID %d not supported", freg->chip_id); + err = -RT_EINVAL; + goto _fail; + } + + freg->slew_reg = FAN53555_CONTROL; + freg->slew_mask = CTL_SLEW_MASK; + freg->slew_shift = CTL_SLEW_SHIFT; + freg->ramp_delay_table = slew_rates; + freg->ramp_delay_nr = RT_ARRAY_SIZE(slew_rates); + freg->vsel_count = RK8602_NVOLTAGES; + break; + + case FAN53526_VENDOR_TCS: + switch (freg->chip_id) + { + case TCS4525_CHIP_ID_12: + case TCS4526_CHIP_ID_00: + freg->slew_reg = TCS4525_TIME; + freg->slew_mask = TCS_SLEW_MASK; + freg->slew_shift = TCS_SLEW_SHIFT; + freg->ramp_delay_table = tcs_slew_rates; + freg->ramp_delay_nr = RT_ARRAY_SIZE(tcs_slew_rates); + + /* Init voltage range and step */ + freg->vsel_min = 600000; + freg->vsel_step = 6250; + freg->vsel_count = FAN53526_NVOLTAGES; + break; + + default: + LOG_E("Chip ID %d not supported", freg->chip_id); + err = -RT_EINVAL; + goto _fail; + } + break; + + default: + break; + } + + if (freg->limit_volt) + { + if (freg->limit_volt < freg->vsel_min || freg->limit_volt > 1500000) + { + freg->limit_volt = 1500000; + } + + val = (freg->limit_volt - freg->vsel_min) / freg->vsel_step; + + if (freg->vendor == FAN53526_VENDOR_TCS) + { + err = fan53555_regulator_write(freg, TCS4525_LIMCONF, val); + } + else + { + err = fan53555_regulator_write(freg, RK860X_MAX_SET, val); + } + + if (err) + { + LOG_E("%s: Failed to set limit voltage", client->name); + goto _fail; + } + } + + freg->vol_mask = fan53555_vol_mask(freg->vsel_count); + + rgp = &freg->parent; + rgp->ops = &fan53555_regulator_switch_ops; + rgp->param = &freg->param; + rgp->dev = &client->parent; + rgp->supply_name = freg->param.name; + + freg->param.enable_delay = 400; + + client->parent.user_data = freg; + + /* + * U-Boot/loader already enables always-on rails (e.g. vdd_cpu). + * Skip boot-time enable/ramp I2C in rt_regulator_register() to avoid + * blocking early boot on a shared PMU I2C bus. + */ + hw_always_on = freg->param.always_on; + ramp_delay = freg->param.ramp_delay; + if (hw_always_on) + { + freg->param.boot_on = RT_FALSE; + freg->param.always_on = RT_FALSE; + freg->param.ramp_delay = 0; + freg->param.ramp_disable = RT_TRUE; + } + + if ((err = rt_regulator_register(rgp))) + { + goto _fail; + } + + if (hw_always_on) + { + rt_atomic_store(&rgp->enabled_count, 1); + } + + if (ramp_delay) + { + err = fan53555_regulator_set_ramp_delay(rgp, ramp_delay); + if (err) + { + LOG_W("%s: set ramp %u us failed: %s", client->name, + ramp_delay, rt_strerror(err)); + } + } + + return RT_EOK; + +_fail: + rt_free(freg); + + return err; +} + +static rt_err_t fan53555_regulator_shutdown(struct rt_i2c_client *client) +{ + rt_err_t err = RT_EOK; + struct fan53555_regulator *freg = client->parent.user_data; + + switch (freg->vendor) + { + case FAN53555_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_SILERGY: + err = fan53555_regulator_update_bits(freg, freg->slew_reg, CTL_RESET, CTL_RESET); + break; + + case FAN53526_VENDOR_TCS: + err = fan53555_regulator_update_bits(freg, TCS4525_LIMCONF, CTL_RESET, CTL_RESET); + break; + + default: + break; + } + + if (err < 0) + { + LOG_E("Shutdown error = %s", rt_strerror(err)); + } + + return RT_EOK; +} + +static const struct rt_i2c_device_id fan53555_regulator_ids[] = +{ + { .name = "fan53526", .data = (void *)FAN53526_VENDOR_FAIRCHILD }, + { .name = "fan53555", .data = (void *)FAN53555_VENDOR_FAIRCHILD }, + { .name = "rk8600", .data = (void *)RK8600_VENDOR_ROCKCHIP }, + { .name = "rk8601", .data = (void *)RK8600_VENDOR_ROCKCHIP }, + { .name = "rk8602", .data = (void *)RK8602_VENDOR_ROCKCHIP }, + { .name = "rk8603", .data = (void *)RK8602_VENDOR_ROCKCHIP }, + { .name = "syr827", .data = (void *)FAN53555_VENDOR_SILERGY }, + { .name = "syr828", .data = (void *)FAN53555_VENDOR_SILERGY }, + { .name = "tcs4525", .data = (void *)FAN53526_VENDOR_TCS }, + { .name = "tcs4526", .data = (void *)FAN53526_VENDOR_TCS }, + { .name = "tcs452x", .data = (void *)FAN53526_VENDOR_TCS }, + { /* sentinel */ }, +}; + +static const struct rt_ofw_node_id fan53555_regulator_ofw_ids[] = +{ + { .compatible = "fcs,fan53526", .data = (void *)FAN53526_VENDOR_FAIRCHILD }, + { .compatible = "fcs,fan53555", .data = (void *)FAN53555_VENDOR_FAIRCHILD }, + { .compatible = "rockchip,rk8600", .data = (void *)RK8600_VENDOR_ROCKCHIP }, + { .compatible = "rockchip,rk8601", .data = (void *)RK8600_VENDOR_ROCKCHIP }, + { .compatible = "rockchip,rk8602", .data = (void *)RK8602_VENDOR_ROCKCHIP }, + { .compatible = "rockchip,rk8603", .data = (void *)RK8602_VENDOR_ROCKCHIP }, + { .compatible = "silergy,syr827", .data = (void *)FAN53555_VENDOR_SILERGY }, + { .compatible = "silergy,syr828", .data = (void *)FAN53555_VENDOR_SILERGY }, + { .compatible = "tcs,tcs4525", .data = (void *)FAN53526_VENDOR_TCS }, + { .compatible = "tcs,tcs4526", .data = (void *)FAN53526_VENDOR_TCS }, + { .compatible = "tcs,tcs452x", .data = (void *)FAN53526_VENDOR_TCS }, + { /* sentinel */ }, +}; + +static struct rt_i2c_driver fan53555_regulator_driver = +{ + .ids = fan53555_regulator_ids, + .ofw_ids = fan53555_regulator_ofw_ids, + + .probe = fan53555_regulator_probe, + .shutdown = fan53555_regulator_shutdown, +}; +RT_I2C_DRIVER_EXPORT(fan53555_regulator_driver); |
