linux/drivers/regulator/mp8859.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Copyright (c) 2019 five technologies GmbH
   4// Author: Markus Reichl <m.reichl@fivetechno.de>
   5
   6#include <linux/module.h>
   7#include <linux/i2c.h>
   8#include <linux/of.h>
   9#include <linux/regulator/driver.h>
  10#include <linux/regmap.h>
  11
  12
  13#define VOL_MIN_IDX                     0x00
  14#define VOL_MAX_IDX                     0x7ff
  15
  16/* Register definitions */
  17#define MP8859_VOUT_L_REG               0    //3 lo Bits
  18#define MP8859_VOUT_H_REG               1    //8 hi Bits
  19#define MP8859_VOUT_GO_REG              2
  20#define MP8859_IOUT_LIM_REG             3
  21#define MP8859_CTL1_REG                 4
  22#define MP8859_CTL2_REG                 5
  23#define MP8859_RESERVED1_REG            6
  24#define MP8859_RESERVED2_REG            7
  25#define MP8859_RESERVED3_REG            8
  26#define MP8859_STATUS_REG               9
  27#define MP8859_INTERRUPT_REG            0x0A
  28#define MP8859_MASK_REG                 0x0B
  29#define MP8859_ID1_REG                  0x0C
  30#define MP8859_MFR_ID_REG               0x27
  31#define MP8859_DEV_ID_REG               0x28
  32#define MP8859_IC_REV_REG               0x29
  33
  34#define MP8859_MAX_REG                  0x29
  35
  36#define MP8859_GO_BIT                   0x01
  37
  38
  39static int mp8859_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
  40{
  41        int ret;
  42
  43        ret = regmap_write(rdev->regmap, MP8859_VOUT_L_REG, sel & 0x7);
  44
  45        if (ret)
  46                return ret;
  47        ret = regmap_write(rdev->regmap, MP8859_VOUT_H_REG, sel >> 3);
  48
  49        if (ret)
  50                return ret;
  51        ret = regmap_update_bits(rdev->regmap, MP8859_VOUT_GO_REG,
  52                                        MP8859_GO_BIT, 1);
  53        return ret;
  54}
  55
  56static int mp8859_get_voltage_sel(struct regulator_dev *rdev)
  57{
  58        unsigned int val_tmp;
  59        unsigned int val;
  60        int ret;
  61
  62        ret = regmap_read(rdev->regmap, MP8859_VOUT_H_REG, &val_tmp);
  63
  64        if (ret)
  65                return ret;
  66        val = val_tmp << 3;
  67
  68        ret = regmap_read(rdev->regmap, MP8859_VOUT_L_REG, &val_tmp);
  69
  70        if (ret)
  71                return ret;
  72        val |= val_tmp & 0x07;
  73        return val;
  74}
  75
  76static const struct linear_range mp8859_dcdc_ranges[] = {
  77        REGULATOR_LINEAR_RANGE(0, VOL_MIN_IDX, VOL_MAX_IDX, 10000),
  78};
  79
  80static const struct regmap_config mp8859_regmap = {
  81        .reg_bits = 8,
  82        .val_bits = 8,
  83        .max_register = MP8859_MAX_REG,
  84        .cache_type = REGCACHE_RBTREE,
  85};
  86
  87static const struct regulator_ops mp8859_ops = {
  88        .set_voltage_sel = mp8859_set_voltage_sel,
  89        .get_voltage_sel = mp8859_get_voltage_sel,
  90        .list_voltage = regulator_list_voltage_linear_range,
  91};
  92
  93static const struct regulator_desc mp8859_regulators[] = {
  94        {
  95                .id = 0,
  96                .type = REGULATOR_VOLTAGE,
  97                .name = "mp8859_dcdc",
  98                .supply_name = "vin",
  99                .of_match = of_match_ptr("mp8859_dcdc"),
 100                .n_voltages = VOL_MAX_IDX + 1,
 101                .linear_ranges = mp8859_dcdc_ranges,
 102                .n_linear_ranges = 1,
 103                .ops = &mp8859_ops,
 104                .owner = THIS_MODULE,
 105        },
 106};
 107
 108static int mp8859_i2c_probe(struct i2c_client *i2c)
 109{
 110        int ret;
 111        struct regulator_config config = {.dev = &i2c->dev};
 112        struct regmap *regmap = devm_regmap_init_i2c(i2c, &mp8859_regmap);
 113        struct regulator_dev *rdev;
 114
 115        if (IS_ERR(regmap)) {
 116                ret = PTR_ERR(regmap);
 117                dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
 118                return ret;
 119        }
 120        rdev = devm_regulator_register(&i2c->dev, &mp8859_regulators[0],
 121                                        &config);
 122
 123        if (IS_ERR(rdev)) {
 124                ret = PTR_ERR(rdev);
 125                dev_err(&i2c->dev, "failed to register %s: %d\n",
 126                        mp8859_regulators[0].name, ret);
 127                return ret;
 128        }
 129        return 0;
 130}
 131
 132static const struct of_device_id mp8859_dt_id[] = {
 133        {.compatible =  "mps,mp8859"},
 134        {},
 135};
 136MODULE_DEVICE_TABLE(of, mp8859_dt_id);
 137
 138static const struct i2c_device_id mp8859_i2c_id[] = {
 139        { "mp8859", },
 140        {  },
 141};
 142MODULE_DEVICE_TABLE(i2c, mp8859_i2c_id);
 143
 144static struct i2c_driver mp8859_regulator_driver = {
 145        .driver = {
 146                .name = "mp8859",
 147                .of_match_table = of_match_ptr(mp8859_dt_id),
 148        },
 149        .probe_new = mp8859_i2c_probe,
 150        .id_table = mp8859_i2c_id,
 151};
 152
 153module_i2c_driver(mp8859_regulator_driver);
 154
 155MODULE_DESCRIPTION("Monolithic Power Systems MP8859 voltage regulator driver");
 156MODULE_AUTHOR("Markus Reichl <m.reichl@fivetechno.de>");
 157MODULE_LICENSE("GPL v2");
 158