422 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include <linux/bits.h>4#include <linux/kernel.h>5#include <linux/module.h>6#include <linux/of.h>7#include <linux/platform_device.h>8#include <linux/regmap.h>9#include <linux/regulator/driver.h>10#include <linux/regulator/machine.h>11#include <linux/regulator/of_regulator.h>12 13#define RT5120_REG_PGSTAT 0x0314#define RT5120_REG_CH1VID 0x0615#define RT5120_REG_CH1SLPVID 0x0716#define RT5120_REG_ENABLE 0x0817#define RT5120_REG_MODECTL 0x0918#define RT5120_REG_UVOVPROT 0x0A19#define RT5120_REG_SLPCTL 0x0C20#define RT5120_REG_INTSTAT 0x1E21#define RT5120_REG_DISCHG 0x1F22 23#define RT5120_OUTPG_MASK(rid) BIT(rid + 1)24#define RT5120_OUTUV_MASK(rid) BIT(rid + 9)25#define RT5120_OUTOV_MASK(rid) BIT(rid + 16)26#define RT5120_CH1VID_MASK GENMASK(6, 0)27#define RT5120_RIDEN_MASK(rid) BIT(rid + 1)28#define RT5120_RADEN_MASK(rid) BIT(rid)29#define RT5120_FPWM_MASK(rid) BIT(rid + 1)30#define RT5120_UVHICCUP_MASK BIT(1)31#define RT5120_OVHICCUP_MASK BIT(0)32#define RT5120_HOTDIE_MASK BIT(1)33 34#define RT5120_BUCK1_MINUV 60000035#define RT5120_BUCK1_MAXUV 139375036#define RT5120_BUCK1_STEPUV 625037#define RT5120_BUCK1_NUM_VOLT 0x8038 39#define RT5120_AUTO_MODE 040#define RT5120_FPWM_MODE 141 42enum {43 RT5120_REGULATOR_BUCK1 = 0,44 RT5120_REGULATOR_BUCK2,45 RT5120_REGULATOR_BUCK3,46 RT5120_REGULATOR_BUCK4,47 RT5120_REGULATOR_LDO,48 RT5120_REGULATOR_EXTEN,49 RT5120_MAX_REGULATOR50};51 52struct rt5120_priv {53 struct device *dev;54 struct regmap *regmap;55 struct regulator_desc rdesc[RT5120_MAX_REGULATOR];56};57 58static int rt5120_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)59{60 struct regmap *regmap = rdev_get_regmap(rdev);61 int rid = rdev_get_id(rdev);62 unsigned int mask = RT5120_FPWM_MASK(rid), val;63 64 switch (mode) {65 case REGULATOR_MODE_NORMAL:66 val = 0;67 break;68 case REGULATOR_MODE_FAST:69 val = RT5120_FPWM_MASK(rid);70 break;71 default:72 return -EINVAL;73 }74 75 return regmap_update_bits(regmap, RT5120_REG_MODECTL, mask, val);76}77 78static unsigned int rt5120_buck_get_mode(struct regulator_dev *rdev)79{80 struct regmap *regmap = rdev_get_regmap(rdev);81 int ret, rid = rdev_get_id(rdev);82 unsigned int val;83 84 ret = regmap_read(regmap, RT5120_REG_MODECTL, &val);85 if (ret)86 return REGULATOR_MODE_INVALID;87 88 if (val & RT5120_FPWM_MASK(rid))89 return REGULATOR_MODE_FAST;90 91 return REGULATOR_MODE_NORMAL;92}93 94static int rt5120_regulator_get_error_flags(struct regulator_dev *rdev,95 unsigned int *flags)96{97 struct regmap *regmap = rdev_get_regmap(rdev);98 unsigned int stat, hd_stat, cur_flags = 0;99 int rid = rdev_get_id(rdev), ret;100 101 /*102 * reg 0x03/0x04/0x05 to indicate PG/UV/OV103 * use block read to descrease I/O xfer time104 */105 ret = regmap_raw_read(regmap, RT5120_REG_PGSTAT, &stat, 3);106 if (ret)107 return ret;108 109 ret = regmap_read(regmap, RT5120_REG_INTSTAT, &hd_stat);110 if (ret)111 return ret;112 113 if (!(stat & RT5120_OUTPG_MASK(rid))) {114 if (stat & RT5120_OUTUV_MASK(rid))115 cur_flags |= REGULATOR_ERROR_UNDER_VOLTAGE;116 117 if (stat & RT5120_OUTOV_MASK(rid))118 cur_flags |= REGULATOR_ERROR_REGULATION_OUT;119 }120 121 if (hd_stat & RT5120_HOTDIE_MASK)122 cur_flags |= REGULATOR_ERROR_OVER_TEMP;123 124 *flags = cur_flags;125 return 0;126}127 128static int rt5120_buck1_set_suspend_voltage(struct regulator_dev *rdev, int uV)129{130 struct regmap *regmap = rdev_get_regmap(rdev);131 int sel;132 133 if (uV < RT5120_BUCK1_MINUV || uV > RT5120_BUCK1_MAXUV)134 return -EINVAL;135 136 sel = (uV - RT5120_BUCK1_MINUV) / RT5120_BUCK1_STEPUV;137 return regmap_write(regmap, RT5120_REG_CH1SLPVID, sel);138}139 140static int rt5120_regulator_set_suspend_enable(struct regulator_dev *rdev)141{142 struct regmap *regmap = rdev_get_regmap(rdev);143 int rid = rdev_get_id(rdev);144 unsigned int mask = RT5120_RIDEN_MASK(rid);145 146 return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, mask);147}148 149static int rt5120_regulator_set_suspend_disable(struct regulator_dev *rdev)150{151 struct regmap *regmap = rdev_get_regmap(rdev);152 int rid = rdev_get_id(rdev);153 unsigned int mask = RT5120_RIDEN_MASK(rid);154 155 return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, 0);156}157 158static const struct regulator_ops rt5120_buck1_ops = {159 .enable = regulator_enable_regmap,160 .disable = regulator_disable_regmap,161 .is_enabled = regulator_is_enabled_regmap,162 .list_voltage = regulator_list_voltage_linear,163 .set_voltage_sel = regulator_set_voltage_sel_regmap,164 .get_voltage_sel = regulator_get_voltage_sel_regmap,165 .set_active_discharge = regulator_set_active_discharge_regmap,166 .set_mode = rt5120_buck_set_mode,167 .get_mode = rt5120_buck_get_mode,168 .get_error_flags = rt5120_regulator_get_error_flags,169 .set_suspend_voltage = rt5120_buck1_set_suspend_voltage,170 .set_suspend_enable = rt5120_regulator_set_suspend_enable,171 .set_suspend_disable = rt5120_regulator_set_suspend_disable,172};173 174static const struct regulator_ops rt5120_buck234_ops = {175 .enable = regulator_enable_regmap,176 .disable = regulator_disable_regmap,177 .is_enabled = regulator_is_enabled_regmap,178 .set_active_discharge = regulator_set_active_discharge_regmap,179 .set_mode = rt5120_buck_set_mode,180 .get_mode = rt5120_buck_get_mode,181 .get_error_flags = rt5120_regulator_get_error_flags,182 .set_suspend_enable = rt5120_regulator_set_suspend_enable,183 .set_suspend_disable = rt5120_regulator_set_suspend_disable,184};185 186static const struct regulator_ops rt5120_ldo_ops = {187 .enable = regulator_enable_regmap,188 .disable = regulator_disable_regmap,189 .is_enabled = regulator_is_enabled_regmap,190 .set_active_discharge = regulator_set_active_discharge_regmap,191 .get_error_flags = rt5120_regulator_get_error_flags,192 .set_suspend_enable = rt5120_regulator_set_suspend_enable,193 .set_suspend_disable = rt5120_regulator_set_suspend_disable,194};195 196static const struct regulator_ops rt5120_exten_ops = {197 .enable = regulator_enable_regmap,198 .disable = regulator_disable_regmap,199 .is_enabled = regulator_is_enabled_regmap,200 .set_suspend_enable = rt5120_regulator_set_suspend_enable,201 .set_suspend_disable = rt5120_regulator_set_suspend_disable,202};203 204static unsigned int rt5120_buck_of_map_mode(unsigned int mode)205{206 switch (mode) {207 case RT5120_AUTO_MODE:208 return REGULATOR_MODE_NORMAL;209 case RT5120_FPWM_MODE:210 return REGULATOR_MODE_FAST;211 default:212 return REGULATOR_MODE_INVALID;213 }214}215 216static void rt5120_fillin_regulator_desc(struct regulator_desc *desc, int rid)217{218 static const char * const name[] = {219 "buck1", "buck2", "buck3", "buck4", "ldo", "exten" };220 static const char * const sname[] = {221 "vin1", "vin2", "vin3", "vin4", "vinldo", NULL };222 223 /* Common regulator property */224 desc->name = name[rid];225 desc->supply_name = sname[rid];226 desc->owner = THIS_MODULE;227 desc->type = REGULATOR_VOLTAGE;228 desc->id = rid;229 desc->enable_reg = RT5120_REG_ENABLE;230 desc->enable_mask = RT5120_RIDEN_MASK(rid);231 desc->active_discharge_reg = RT5120_REG_DISCHG;232 desc->active_discharge_mask = RT5120_RADEN_MASK(rid);233 desc->active_discharge_on = RT5120_RADEN_MASK(rid);234 /* Config n_voltages to 1 for all*/235 desc->n_voltages = 1;236 237 /* Only buck support mode change */238 if (rid >= RT5120_REGULATOR_BUCK1 && rid <= RT5120_REGULATOR_BUCK4)239 desc->of_map_mode = rt5120_buck_of_map_mode;240 241 /* RID specific property init */242 switch (rid) {243 case RT5120_REGULATOR_BUCK1:244 /* Only buck1 support voltage change by I2C */245 desc->n_voltages = RT5120_BUCK1_NUM_VOLT;246 desc->min_uV = RT5120_BUCK1_MINUV;247 desc->uV_step = RT5120_BUCK1_STEPUV;248 desc->vsel_reg = RT5120_REG_CH1VID;249 desc->vsel_mask = RT5120_CH1VID_MASK;250 desc->ops = &rt5120_buck1_ops;251 break;252 case RT5120_REGULATOR_BUCK2 ... RT5120_REGULATOR_BUCK4:253 desc->ops = &rt5120_buck234_ops;254 break;255 case RT5120_REGULATOR_LDO:256 desc->ops = &rt5120_ldo_ops;257 break;258 default:259 desc->ops = &rt5120_exten_ops;260 }261}262 263static int rt5120_of_parse_cb(struct rt5120_priv *priv, int rid,264 struct of_regulator_match *match)265{266 struct regulator_desc *desc = priv->rdesc + rid;267 struct regulator_init_data *init_data = match->init_data;268 269 if (!init_data || rid == RT5120_REGULATOR_BUCK1)270 return 0;271 272 if (init_data->constraints.min_uV != init_data->constraints.max_uV) {273 dev_err(priv->dev, "Variable voltage for fixed regulator\n");274 return -EINVAL;275 }276 277 desc->fixed_uV = init_data->constraints.min_uV;278 return 0;279}280 281static struct of_regulator_match rt5120_regu_match[RT5120_MAX_REGULATOR] = {282 [RT5120_REGULATOR_BUCK1] = { .name = "buck1", },283 [RT5120_REGULATOR_BUCK2] = { .name = "buck2", },284 [RT5120_REGULATOR_BUCK3] = { .name = "buck3", },285 [RT5120_REGULATOR_BUCK4] = { .name = "buck4", },286 [RT5120_REGULATOR_LDO] = { .name = "ldo", },287 [RT5120_REGULATOR_EXTEN] = { .name = "exten", }288};289 290static int rt5120_parse_regulator_dt_data(struct rt5120_priv *priv)291{292 struct device *dev = priv->dev->parent;293 struct device_node *reg_node;294 int i, ret;295 296 for (i = 0; i < RT5120_MAX_REGULATOR; i++) {297 rt5120_fillin_regulator_desc(priv->rdesc + i, i);298 299 rt5120_regu_match[i].desc = priv->rdesc + i;300 }301 302 reg_node = of_get_child_by_name(dev->of_node, "regulators");303 if (!reg_node) {304 dev_err(priv->dev, "Couldn't find 'regulators' node\n");305 return -ENODEV;306 }307 308 ret = of_regulator_match(priv->dev, reg_node, rt5120_regu_match,309 ARRAY_SIZE(rt5120_regu_match));310 311 of_node_put(reg_node);312 313 if (ret < 0) {314 dev_err(priv->dev,315 "Error parsing regulator init data (%d)\n", ret);316 return ret;317 }318 319 for (i = 0; i < RT5120_MAX_REGULATOR; i++) {320 ret = rt5120_of_parse_cb(priv, i, rt5120_regu_match + i);321 if (ret) {322 dev_err(priv->dev, "Failed in [%d] of_passe_cb\n", i);323 return ret;324 }325 }326 327 return 0;328}329 330static int rt5120_device_property_init(struct rt5120_priv *priv)331{332 struct device *dev = priv->dev->parent;333 struct device_node *np = dev->of_node;334 bool prot_enable;335 unsigned int prot_enable_val = 0;336 337 /* Assign UV/OV HW protection behavior */338 prot_enable = of_property_read_bool(np,339 "richtek,enable-undervolt-hiccup");340 if (prot_enable)341 prot_enable_val |= RT5120_UVHICCUP_MASK;342 343 prot_enable = of_property_read_bool(np,344 "richtek,enable-overvolt-hiccup");345 if (prot_enable)346 prot_enable_val |= RT5120_OVHICCUP_MASK;347 348 return regmap_update_bits(priv->regmap, RT5120_REG_UVOVPROT,349 RT5120_UVHICCUP_MASK | RT5120_OVHICCUP_MASK,350 prot_enable_val);351}352 353static int rt5120_regulator_probe(struct platform_device *pdev)354{355 struct rt5120_priv *priv;356 struct regulator_dev *rdev;357 struct regulator_config config = {};358 int i, ret;359 360 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);361 if (!priv)362 return -ENOMEM;363 364 priv->dev = &pdev->dev;365 366 priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);367 if (!priv->regmap) {368 dev_err(&pdev->dev, "Failed to init regmap\n");369 return -ENODEV;370 }371 372 ret = rt5120_device_property_init(priv);373 if (ret) {374 dev_err(&pdev->dev, "Failed to do property init\n");375 return ret;376 }377 378 ret = rt5120_parse_regulator_dt_data(priv);379 if (ret) {380 dev_err(&pdev->dev, "Failed to parse dt data\n");381 return ret;382 }383 384 config.dev = &pdev->dev;385 config.regmap = priv->regmap;386 387 for (i = 0; i < RT5120_MAX_REGULATOR; i++) {388 config.of_node = rt5120_regu_match[i].of_node;389 config.init_data = rt5120_regu_match[i].init_data;390 391 rdev = devm_regulator_register(&pdev->dev, priv->rdesc + i,392 &config);393 if (IS_ERR(rdev)) {394 dev_err(&pdev->dev,395 "Failed to register regulator [%d]\n", i);396 return PTR_ERR(rdev);397 }398 }399 400 return 0;401}402 403static const struct platform_device_id rt5120_regulator_dev_table[] = {404 { "rt5120-regulator", 0 },405 {}406};407MODULE_DEVICE_TABLE(platform, rt5120_regulator_dev_table);408 409static struct platform_driver rt5120_regulator_driver = {410 .driver = {411 .name = "rt5120-regulator",412 .probe_type = PROBE_PREFER_ASYNCHRONOUS,413 },414 .id_table = rt5120_regulator_dev_table,415 .probe = rt5120_regulator_probe,416};417module_platform_driver(rt5120_regulator_driver);418 419MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");420MODULE_DESCRIPTION("Richtek RT5120 regulator driver");421MODULE_LICENSE("GPL v2");422