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