370 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// MP8867/MP8869 regulator driver4//5// Copyright (C) 2020 Synaptics Incorporated6//7// Author: Jisheng Zhang <jszhang@kernel.org>8 9#include <linux/gpio/consumer.h>10#include <linux/i2c.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/regmap.h>14#include <linux/regulator/driver.h>15#include <linux/regulator/of_regulator.h>16 17#define MP886X_VSEL 0x0018#define MP886X_V_BOOT (1 << 7)19#define MP886X_SYSCNTLREG1 0x0120#define MP886X_MODE (1 << 0)21#define MP886X_SLEW_SHIFT 322#define MP886X_SLEW_MASK (0x7 << MP886X_SLEW_SHIFT)23#define MP886X_GO (1 << 6)24#define MP886X_EN (1 << 7)25#define MP8869_SYSCNTLREG2 0x0226 27struct mp886x_cfg_info {28 const struct regulator_ops *rops;29 const unsigned int slew_rates[8];30 const int switch_freq[4];31 const u8 fs_reg;32 const u8 fs_shift;33};34 35struct mp886x_device_info {36 struct device *dev;37 struct regulator_desc desc;38 struct regulator_init_data *regulator;39 struct gpio_desc *en_gpio;40 const struct mp886x_cfg_info *ci;41 u32 r[2];42 unsigned int sel;43};44 45static void mp886x_set_switch_freq(struct mp886x_device_info *di,46 struct regmap *regmap,47 u32 freq)48{49 const struct mp886x_cfg_info *ci = di->ci;50 int i;51 52 for (i = 0; i < ARRAY_SIZE(ci->switch_freq); i++) {53 if (freq == ci->switch_freq[i]) {54 regmap_update_bits(regmap, ci->fs_reg,55 0x3 << ci->fs_shift, i << ci->fs_shift);56 return;57 }58 }59 60 dev_err(di->dev, "invalid frequency %d\n", freq);61}62 63static int mp886x_set_mode(struct regulator_dev *rdev, unsigned int mode)64{65 switch (mode) {66 case REGULATOR_MODE_FAST:67 regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,68 MP886X_MODE, MP886X_MODE);69 break;70 case REGULATOR_MODE_NORMAL:71 regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,72 MP886X_MODE, 0);73 break;74 default:75 return -EINVAL;76 }77 return 0;78}79 80static unsigned int mp886x_get_mode(struct regulator_dev *rdev)81{82 u32 val;83 int ret;84 85 ret = regmap_read(rdev->regmap, MP886X_SYSCNTLREG1, &val);86 if (ret < 0)87 return ret;88 if (val & MP886X_MODE)89 return REGULATOR_MODE_FAST;90 else91 return REGULATOR_MODE_NORMAL;92}93 94static int mp8869_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)95{96 int ret;97 98 ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,99 MP886X_GO, MP886X_GO);100 if (ret < 0)101 return ret;102 103 sel <<= ffs(rdev->desc->vsel_mask) - 1;104 return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,105 MP886X_V_BOOT | rdev->desc->vsel_mask, sel);106}107 108static inline unsigned int mp8869_scale(unsigned int uv, u32 r1, u32 r2)109{110 u32 tmp = uv * r1 / r2;111 112 return uv + tmp;113}114 115static int mp8869_get_voltage_sel(struct regulator_dev *rdev)116{117 struct mp886x_device_info *di = rdev_get_drvdata(rdev);118 int ret, uv;119 unsigned int val;120 bool fbloop;121 122 ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);123 if (ret)124 return ret;125 126 fbloop = val & MP886X_V_BOOT;127 if (fbloop) {128 uv = rdev->desc->min_uV;129 uv = mp8869_scale(uv, di->r[0], di->r[1]);130 return regulator_map_voltage_linear(rdev, uv, uv);131 }132 133 val &= rdev->desc->vsel_mask;134 val >>= ffs(rdev->desc->vsel_mask) - 1;135 136 return val;137}138 139static const struct regulator_ops mp8869_regulator_ops = {140 .set_voltage_sel = mp8869_set_voltage_sel,141 .get_voltage_sel = mp8869_get_voltage_sel,142 .set_voltage_time_sel = regulator_set_voltage_time_sel,143 .map_voltage = regulator_map_voltage_linear,144 .list_voltage = regulator_list_voltage_linear,145 .enable = regulator_enable_regmap,146 .disable = regulator_disable_regmap,147 .is_enabled = regulator_is_enabled_regmap,148 .set_mode = mp886x_set_mode,149 .get_mode = mp886x_get_mode,150 .set_ramp_delay = regulator_set_ramp_delay_regmap,151};152 153static const struct mp886x_cfg_info mp8869_ci = {154 .rops = &mp8869_regulator_ops,155 .slew_rates = {156 40000,157 30000,158 20000,159 10000,160 5000,161 2500,162 1250,163 625,164 },165 .switch_freq = {166 500000,167 750000,168 1000000,169 1250000,170 },171 .fs_reg = MP8869_SYSCNTLREG2,172 .fs_shift = 4,173};174 175static int mp8867_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)176{177 struct mp886x_device_info *di = rdev_get_drvdata(rdev);178 int ret, delta;179 180 ret = mp8869_set_voltage_sel(rdev, sel);181 if (ret < 0)182 return ret;183 184 delta = di->sel - sel;185 if (abs(delta) <= 5)186 ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,187 MP886X_GO, 0);188 di->sel = sel;189 190 return ret;191}192 193static int mp8867_get_voltage_sel(struct regulator_dev *rdev)194{195 struct mp886x_device_info *di = rdev_get_drvdata(rdev);196 int ret, uv;197 unsigned int val;198 bool fbloop;199 200 ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);201 if (ret)202 return ret;203 204 fbloop = val & MP886X_V_BOOT;205 206 val &= rdev->desc->vsel_mask;207 val >>= ffs(rdev->desc->vsel_mask) - 1;208 209 if (fbloop) {210 uv = regulator_list_voltage_linear(rdev, val);211 uv = mp8869_scale(uv, di->r[0], di->r[1]);212 return regulator_map_voltage_linear(rdev, uv, uv);213 }214 215 return val;216}217 218static const struct regulator_ops mp8867_regulator_ops = {219 .set_voltage_sel = mp8867_set_voltage_sel,220 .get_voltage_sel = mp8867_get_voltage_sel,221 .set_voltage_time_sel = regulator_set_voltage_time_sel,222 .map_voltage = regulator_map_voltage_linear,223 .list_voltage = regulator_list_voltage_linear,224 .enable = regulator_enable_regmap,225 .disable = regulator_disable_regmap,226 .is_enabled = regulator_is_enabled_regmap,227 .set_mode = mp886x_set_mode,228 .get_mode = mp886x_get_mode,229 .set_ramp_delay = regulator_set_ramp_delay_regmap,230};231 232static const struct mp886x_cfg_info mp8867_ci = {233 .rops = &mp8867_regulator_ops,234 .slew_rates = {235 64000,236 32000,237 16000,238 8000,239 4000,240 2000,241 1000,242 500,243 },244 .switch_freq = {245 500000,246 750000,247 1000000,248 1500000,249 },250 .fs_reg = MP886X_SYSCNTLREG1,251 .fs_shift = 1,252};253 254static int mp886x_regulator_register(struct mp886x_device_info *di,255 struct regulator_config *config)256{257 struct regulator_desc *rdesc = &di->desc;258 struct regulator_dev *rdev;259 260 rdesc->name = "mp886x-reg";261 rdesc->supply_name = "vin";262 rdesc->ops = di->ci->rops;263 rdesc->type = REGULATOR_VOLTAGE;264 rdesc->n_voltages = 128;265 rdesc->enable_reg = MP886X_SYSCNTLREG1;266 rdesc->enable_mask = MP886X_EN;267 rdesc->min_uV = 600000;268 rdesc->uV_step = 10000;269 rdesc->vsel_reg = MP886X_VSEL;270 rdesc->vsel_mask = 0x3f;271 rdesc->ramp_reg = MP886X_SYSCNTLREG1;272 rdesc->ramp_mask = MP886X_SLEW_MASK;273 rdesc->ramp_delay_table = di->ci->slew_rates;274 rdesc->n_ramp_values = ARRAY_SIZE(di->ci->slew_rates);275 rdesc->owner = THIS_MODULE;276 277 rdev = devm_regulator_register(di->dev, &di->desc, config);278 if (IS_ERR(rdev))279 return PTR_ERR(rdev);280 di->sel = rdesc->ops->get_voltage_sel(rdev);281 return 0;282}283 284static const struct regmap_config mp886x_regmap_config = {285 .reg_bits = 8,286 .val_bits = 8,287};288 289static int mp886x_i2c_probe(struct i2c_client *client)290{291 struct device *dev = &client->dev;292 struct device_node *np = dev->of_node;293 struct mp886x_device_info *di;294 struct regulator_config config = { };295 struct regmap *regmap;296 u32 freq;297 int ret;298 299 di = devm_kzalloc(dev, sizeof(struct mp886x_device_info), GFP_KERNEL);300 if (!di)301 return -ENOMEM;302 303 di->regulator = of_get_regulator_init_data(dev, np, &di->desc);304 if (!di->regulator) {305 dev_err(dev, "Platform data not found!\n");306 return -EINVAL;307 }308 309 ret = of_property_read_u32_array(np, "mps,fb-voltage-divider",310 di->r, 2);311 if (ret)312 return ret;313 314 di->en_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);315 if (IS_ERR(di->en_gpio))316 return PTR_ERR(di->en_gpio);317 318 di->ci = i2c_get_match_data(client);319 di->dev = dev;320 321 regmap = devm_regmap_init_i2c(client, &mp886x_regmap_config);322 if (IS_ERR(regmap)) {323 dev_err(dev, "Failed to allocate regmap!\n");324 return PTR_ERR(regmap);325 }326 i2c_set_clientdata(client, di);327 328 config.dev = di->dev;329 config.init_data = di->regulator;330 config.regmap = regmap;331 config.driver_data = di;332 config.of_node = np;333 334 if (!of_property_read_u32(np, "mps,switch-frequency-hz", &freq))335 mp886x_set_switch_freq(di, regmap, freq);336 337 ret = mp886x_regulator_register(di, &config);338 if (ret < 0)339 dev_err(dev, "Failed to register regulator!\n");340 return ret;341}342 343static const struct of_device_id mp886x_dt_ids[] = {344 { .compatible = "mps,mp8867", .data = &mp8867_ci },345 { .compatible = "mps,mp8869", .data = &mp8869_ci },346 { }347};348MODULE_DEVICE_TABLE(of, mp886x_dt_ids);349 350static const struct i2c_device_id mp886x_id[] = {351 { "mp886x", (kernel_ulong_t)&mp8869_ci },352 { },353};354MODULE_DEVICE_TABLE(i2c, mp886x_id);355 356static struct i2c_driver mp886x_regulator_driver = {357 .driver = {358 .name = "mp886x-regulator",359 .probe_type = PROBE_PREFER_ASYNCHRONOUS,360 .of_match_table = mp886x_dt_ids,361 },362 .probe = mp886x_i2c_probe,363 .id_table = mp886x_id,364};365module_i2c_driver(mp886x_regulator_driver);366 367MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");368MODULE_DESCRIPTION("MP886x regulator driver");369MODULE_LICENSE("GPL v2");370