162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/delay.h> 462306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 562306a36Sopenharmony_ci#include <linux/i2c.h> 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/property.h> 962306a36Sopenharmony_ci#include <linux/regmap.h> 1062306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1162306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define RT6160_MODE_AUTO 0 1462306a36Sopenharmony_ci#define RT6160_MODE_FPWM 1 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define RT6160_REG_CNTL 0x01 1762306a36Sopenharmony_ci#define RT6160_REG_STATUS 0x02 1862306a36Sopenharmony_ci#define RT6160_REG_DEVID 0x03 1962306a36Sopenharmony_ci#define RT6160_REG_VSELL 0x04 2062306a36Sopenharmony_ci#define RT6160_REG_VSELH 0x05 2162306a36Sopenharmony_ci#define RT6160_NUM_REGS (RT6160_REG_VSELH + 1) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define RT6160_FPWM_MASK BIT(3) 2462306a36Sopenharmony_ci#define RT6160_RAMPRATE_MASK GENMASK(1, 0) 2562306a36Sopenharmony_ci#define RT6160_VID_MASK GENMASK(7, 4) 2662306a36Sopenharmony_ci#define RT6160_VSEL_MASK GENMASK(6, 0) 2762306a36Sopenharmony_ci#define RT6160_HDSTAT_MASK BIT(4) 2862306a36Sopenharmony_ci#define RT6160_UVSTAT_MASK BIT(3) 2962306a36Sopenharmony_ci#define RT6160_OCSTAT_MASK BIT(2) 3062306a36Sopenharmony_ci#define RT6160_TSDSTAT_MASK BIT(1) 3162306a36Sopenharmony_ci#define RT6160_PGSTAT_MASK BIT(0) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define RT6160_VENDOR_ID 0xA0 3462306a36Sopenharmony_ci#define RT6160_VOUT_MINUV 2025000 3562306a36Sopenharmony_ci#define RT6160_VOUT_MAXUV 5200000 3662306a36Sopenharmony_ci#define RT6160_VOUT_STPUV 25000 3762306a36Sopenharmony_ci#define RT6160_N_VOUTS ((RT6160_VOUT_MAXUV - RT6160_VOUT_MINUV) / RT6160_VOUT_STPUV + 1) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define RT6160_I2CRDY_TIMEUS 100 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct rt6160_priv { 4262306a36Sopenharmony_ci struct regulator_desc desc; 4362306a36Sopenharmony_ci struct gpio_desc *enable_gpio; 4462306a36Sopenharmony_ci struct regmap *regmap; 4562306a36Sopenharmony_ci bool enable_state; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic const unsigned int rt6160_ramp_tables[] = { 4962306a36Sopenharmony_ci 1000, 2500, 5000, 10000 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int rt6160_enable(struct regulator_dev *rdev) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct rt6160_priv *priv = rdev_get_drvdata(rdev); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (!priv->enable_gpio) 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci gpiod_set_value_cansleep(priv->enable_gpio, 1); 6062306a36Sopenharmony_ci priv->enable_state = true; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci usleep_range(RT6160_I2CRDY_TIMEUS, RT6160_I2CRDY_TIMEUS + 100); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci regcache_cache_only(priv->regmap, false); 6562306a36Sopenharmony_ci return regcache_sync(priv->regmap); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int rt6160_disable(struct regulator_dev *rdev) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct rt6160_priv *priv = rdev_get_drvdata(rdev); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (!priv->enable_gpio) 7362306a36Sopenharmony_ci return -EINVAL; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* Mark regcache as dirty and cache only before HW disabled */ 7662306a36Sopenharmony_ci regcache_cache_only(priv->regmap, true); 7762306a36Sopenharmony_ci regcache_mark_dirty(priv->regmap); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci priv->enable_state = false; 8062306a36Sopenharmony_ci gpiod_set_value_cansleep(priv->enable_gpio, 0); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int rt6160_is_enabled(struct regulator_dev *rdev) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct rt6160_priv *priv = rdev_get_drvdata(rdev); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci return priv->enable_state ? 1 : 0; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int rt6160_set_mode(struct regulator_dev *rdev, unsigned int mode) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct regmap *regmap = rdev_get_regmap(rdev); 9562306a36Sopenharmony_ci unsigned int mode_val; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci switch (mode) { 9862306a36Sopenharmony_ci case REGULATOR_MODE_FAST: 9962306a36Sopenharmony_ci mode_val = RT6160_FPWM_MASK; 10062306a36Sopenharmony_ci break; 10162306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 10262306a36Sopenharmony_ci mode_val = 0; 10362306a36Sopenharmony_ci break; 10462306a36Sopenharmony_ci default: 10562306a36Sopenharmony_ci dev_err(&rdev->dev, "mode not supported\n"); 10662306a36Sopenharmony_ci return -EINVAL; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return regmap_update_bits(regmap, RT6160_REG_CNTL, RT6160_FPWM_MASK, mode_val); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic unsigned int rt6160_get_mode(struct regulator_dev *rdev) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct regmap *regmap = rdev_get_regmap(rdev); 11562306a36Sopenharmony_ci unsigned int val; 11662306a36Sopenharmony_ci int ret; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ret = regmap_read(regmap, RT6160_REG_CNTL, &val); 11962306a36Sopenharmony_ci if (ret) 12062306a36Sopenharmony_ci return ret; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (val & RT6160_FPWM_MASK) 12362306a36Sopenharmony_ci return REGULATOR_MODE_FAST; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return REGULATOR_MODE_NORMAL; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int rt6160_set_suspend_voltage(struct regulator_dev *rdev, int uV) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct regmap *regmap = rdev_get_regmap(rdev); 13162306a36Sopenharmony_ci unsigned int suspend_vsel_reg; 13262306a36Sopenharmony_ci int vsel; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci vsel = regulator_map_voltage_linear(rdev, uV, uV); 13562306a36Sopenharmony_ci if (vsel < 0) 13662306a36Sopenharmony_ci return vsel; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (rdev->desc->vsel_reg == RT6160_REG_VSELL) 13962306a36Sopenharmony_ci suspend_vsel_reg = RT6160_REG_VSELH; 14062306a36Sopenharmony_ci else 14162306a36Sopenharmony_ci suspend_vsel_reg = RT6160_REG_VSELL; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return regmap_update_bits(regmap, suspend_vsel_reg, 14462306a36Sopenharmony_ci RT6160_VSEL_MASK, vsel); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int rt6160_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct regmap *regmap = rdev_get_regmap(rdev); 15062306a36Sopenharmony_ci unsigned int val, events = 0; 15162306a36Sopenharmony_ci int ret; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci ret = regmap_read(regmap, RT6160_REG_STATUS, &val); 15462306a36Sopenharmony_ci if (ret) 15562306a36Sopenharmony_ci return ret; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (val & (RT6160_HDSTAT_MASK | RT6160_TSDSTAT_MASK)) 15862306a36Sopenharmony_ci events |= REGULATOR_ERROR_OVER_TEMP; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (val & RT6160_UVSTAT_MASK) 16162306a36Sopenharmony_ci events |= REGULATOR_ERROR_UNDER_VOLTAGE; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (val & RT6160_OCSTAT_MASK) 16462306a36Sopenharmony_ci events |= REGULATOR_ERROR_OVER_CURRENT; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (val & RT6160_PGSTAT_MASK) 16762306a36Sopenharmony_ci events |= REGULATOR_ERROR_FAIL; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci *flags = events; 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic const struct regulator_ops rt6160_regulator_ops = { 17462306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 17562306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 17662306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci .enable = rt6160_enable, 17962306a36Sopenharmony_ci .disable = rt6160_disable, 18062306a36Sopenharmony_ci .is_enabled = rt6160_is_enabled, 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci .set_mode = rt6160_set_mode, 18362306a36Sopenharmony_ci .get_mode = rt6160_get_mode, 18462306a36Sopenharmony_ci .set_suspend_voltage = rt6160_set_suspend_voltage, 18562306a36Sopenharmony_ci .set_ramp_delay = regulator_set_ramp_delay_regmap, 18662306a36Sopenharmony_ci .get_error_flags = rt6160_get_error_flags, 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic unsigned int rt6160_of_map_mode(unsigned int mode) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci switch (mode) { 19262306a36Sopenharmony_ci case RT6160_MODE_FPWM: 19362306a36Sopenharmony_ci return REGULATOR_MODE_FAST; 19462306a36Sopenharmony_ci case RT6160_MODE_AUTO: 19562306a36Sopenharmony_ci return REGULATOR_MODE_NORMAL; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return REGULATOR_MODE_INVALID; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic bool rt6160_is_accessible_reg(struct device *dev, unsigned int reg) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci if (reg >= RT6160_REG_CNTL && reg <= RT6160_REG_VSELH) 20462306a36Sopenharmony_ci return true; 20562306a36Sopenharmony_ci return false; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic bool rt6160_is_volatile_reg(struct device *dev, unsigned int reg) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci if (reg == RT6160_REG_STATUS) 21162306a36Sopenharmony_ci return true; 21262306a36Sopenharmony_ci return false; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic const struct regmap_config rt6160_regmap_config = { 21662306a36Sopenharmony_ci .reg_bits = 8, 21762306a36Sopenharmony_ci .val_bits = 8, 21862306a36Sopenharmony_ci .max_register = RT6160_REG_VSELH, 21962306a36Sopenharmony_ci .num_reg_defaults_raw = RT6160_NUM_REGS, 22062306a36Sopenharmony_ci .cache_type = REGCACHE_FLAT, 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci .writeable_reg = rt6160_is_accessible_reg, 22362306a36Sopenharmony_ci .readable_reg = rt6160_is_accessible_reg, 22462306a36Sopenharmony_ci .volatile_reg = rt6160_is_volatile_reg, 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int rt6160_probe(struct i2c_client *i2c) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct rt6160_priv *priv; 23062306a36Sopenharmony_ci struct regulator_config regulator_cfg = {}; 23162306a36Sopenharmony_ci struct regulator_dev *rdev; 23262306a36Sopenharmony_ci bool vsel_active_low; 23362306a36Sopenharmony_ci unsigned int devid; 23462306a36Sopenharmony_ci int ret; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); 23762306a36Sopenharmony_ci if (!priv) 23862306a36Sopenharmony_ci return -ENOMEM; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci vsel_active_low = 24162306a36Sopenharmony_ci device_property_present(&i2c->dev, "richtek,vsel-active-low"); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH); 24462306a36Sopenharmony_ci if (IS_ERR(priv->enable_gpio)) { 24562306a36Sopenharmony_ci dev_err(&i2c->dev, "Failed to get 'enable' gpio\n"); 24662306a36Sopenharmony_ci return PTR_ERR(priv->enable_gpio); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci priv->enable_state = true; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci usleep_range(RT6160_I2CRDY_TIMEUS, RT6160_I2CRDY_TIMEUS + 100); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci priv->regmap = devm_regmap_init_i2c(i2c, &rt6160_regmap_config); 25362306a36Sopenharmony_ci if (IS_ERR(priv->regmap)) { 25462306a36Sopenharmony_ci ret = PTR_ERR(priv->regmap); 25562306a36Sopenharmony_ci dev_err(&i2c->dev, "Failed to init regmap (%d)\n", ret); 25662306a36Sopenharmony_ci return ret; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci ret = regmap_read(priv->regmap, RT6160_REG_DEVID, &devid); 26062306a36Sopenharmony_ci if (ret) 26162306a36Sopenharmony_ci return ret; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if ((devid & RT6160_VID_MASK) != RT6160_VENDOR_ID) { 26462306a36Sopenharmony_ci dev_err(&i2c->dev, "VID not correct [0x%02x]\n", devid); 26562306a36Sopenharmony_ci return -ENODEV; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci priv->desc.name = "rt6160-buckboost"; 26962306a36Sopenharmony_ci priv->desc.type = REGULATOR_VOLTAGE; 27062306a36Sopenharmony_ci priv->desc.owner = THIS_MODULE; 27162306a36Sopenharmony_ci priv->desc.min_uV = RT6160_VOUT_MINUV; 27262306a36Sopenharmony_ci priv->desc.uV_step = RT6160_VOUT_STPUV; 27362306a36Sopenharmony_ci if (vsel_active_low) 27462306a36Sopenharmony_ci priv->desc.vsel_reg = RT6160_REG_VSELL; 27562306a36Sopenharmony_ci else 27662306a36Sopenharmony_ci priv->desc.vsel_reg = RT6160_REG_VSELH; 27762306a36Sopenharmony_ci priv->desc.vsel_mask = RT6160_VSEL_MASK; 27862306a36Sopenharmony_ci priv->desc.n_voltages = RT6160_N_VOUTS; 27962306a36Sopenharmony_ci priv->desc.ramp_reg = RT6160_REG_CNTL; 28062306a36Sopenharmony_ci priv->desc.ramp_mask = RT6160_RAMPRATE_MASK; 28162306a36Sopenharmony_ci priv->desc.ramp_delay_table = rt6160_ramp_tables; 28262306a36Sopenharmony_ci priv->desc.n_ramp_values = ARRAY_SIZE(rt6160_ramp_tables); 28362306a36Sopenharmony_ci priv->desc.of_map_mode = rt6160_of_map_mode; 28462306a36Sopenharmony_ci priv->desc.ops = &rt6160_regulator_ops; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci regulator_cfg.dev = &i2c->dev; 28762306a36Sopenharmony_ci regulator_cfg.of_node = i2c->dev.of_node; 28862306a36Sopenharmony_ci regulator_cfg.regmap = priv->regmap; 28962306a36Sopenharmony_ci regulator_cfg.driver_data = priv; 29062306a36Sopenharmony_ci regulator_cfg.init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node, 29162306a36Sopenharmony_ci &priv->desc); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci rdev = devm_regulator_register(&i2c->dev, &priv->desc, ®ulator_cfg); 29462306a36Sopenharmony_ci if (IS_ERR(rdev)) { 29562306a36Sopenharmony_ci dev_err(&i2c->dev, "Failed to register regulator\n"); 29662306a36Sopenharmony_ci return PTR_ERR(rdev); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic const struct of_device_id __maybe_unused rt6160_of_match_table[] = { 30362306a36Sopenharmony_ci { .compatible = "richtek,rt6160", }, 30462306a36Sopenharmony_ci {} 30562306a36Sopenharmony_ci}; 30662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rt6160_of_match_table); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic struct i2c_driver rt6160_driver = { 30962306a36Sopenharmony_ci .driver = { 31062306a36Sopenharmony_ci .name = "rt6160", 31162306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 31262306a36Sopenharmony_ci .of_match_table = rt6160_of_match_table, 31362306a36Sopenharmony_ci }, 31462306a36Sopenharmony_ci .probe = rt6160_probe, 31562306a36Sopenharmony_ci}; 31662306a36Sopenharmony_cimodule_i2c_driver(rt6160_driver); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ciMODULE_DESCRIPTION("Richtek RT6160 voltage regulator driver"); 31962306a36Sopenharmony_ciMODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); 32062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 321