linux/drivers/regulator/mp886x.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// MP8867/MP8869 regulator driver
   4//
   5// Copyright (C) 2020 Synaptics Incorporated
   6//
   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_device.h>
  13#include <linux/regmap.h>
  14#include <linux/regulator/driver.h>
  15#include <linux/regulator/of_regulator.h>
  16
  17#define MP886X_VSEL             0x00
  18#define  MP886X_V_BOOT          (1 << 7)
  19#define MP886X_SYSCNTLREG1      0x01
  20#define  MP886X_MODE            (1 << 0)
  21#define  MP886X_SLEW_SHIFT      3
  22#define  MP886X_SLEW_MASK       (0x7 << MP886X_SLEW_SHIFT)
  23#define  MP886X_GO              (1 << 6)
  24#define  MP886X_EN              (1 << 7)
  25#define MP8869_SYSCNTLREG2      0x02
  26
  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        else
  91                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 = of_device_get_match_data(dev);
 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        {
 345                .compatible = "mps,mp8867",
 346                .data = &mp8867_ci
 347        },
 348        {
 349                .compatible = "mps,mp8869",
 350                .data = &mp8869_ci
 351        },
 352        { }
 353};
 354MODULE_DEVICE_TABLE(of, mp886x_dt_ids);
 355
 356static const struct i2c_device_id mp886x_id[] = {
 357        { "mp886x", },
 358        { },
 359};
 360MODULE_DEVICE_TABLE(i2c, mp886x_id);
 361
 362static struct i2c_driver mp886x_regulator_driver = {
 363        .driver = {
 364                .name = "mp886x-regulator",
 365                .of_match_table = of_match_ptr(mp886x_dt_ids),
 366        },
 367        .probe_new = mp886x_i2c_probe,
 368        .id_table = mp886x_id,
 369};
 370module_i2c_driver(mp886x_regulator_driver);
 371
 372MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
 373MODULE_DESCRIPTION("MP886x regulator driver");
 374MODULE_LICENSE("GPL v2");
 375