0001
0002
0003
0004
0005
0006 #include <linux/module.h>
0007 #include <linux/i2c.h>
0008 #include <linux/of.h>
0009 #include <linux/regulator/driver.h>
0010 #include <linux/regmap.h>
0011
0012
0013 #define VOL_MIN_IDX 0x00
0014 #define VOL_MAX_IDX 0x7ff
0015
0016
0017 #define MP8859_VOUT_L_REG 0
0018 #define MP8859_VOUT_H_REG 1
0019 #define MP8859_VOUT_GO_REG 2
0020 #define MP8859_IOUT_LIM_REG 3
0021 #define MP8859_CTL1_REG 4
0022 #define MP8859_CTL2_REG 5
0023 #define MP8859_RESERVED1_REG 6
0024 #define MP8859_RESERVED2_REG 7
0025 #define MP8859_RESERVED3_REG 8
0026 #define MP8859_STATUS_REG 9
0027 #define MP8859_INTERRUPT_REG 0x0A
0028 #define MP8859_MASK_REG 0x0B
0029 #define MP8859_ID1_REG 0x0C
0030 #define MP8859_MFR_ID_REG 0x27
0031 #define MP8859_DEV_ID_REG 0x28
0032 #define MP8859_IC_REV_REG 0x29
0033
0034 #define MP8859_MAX_REG 0x29
0035
0036 #define MP8859_GO_BIT 0x01
0037
0038
0039 static int mp8859_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
0040 {
0041 int ret;
0042
0043 ret = regmap_write(rdev->regmap, MP8859_VOUT_L_REG, sel & 0x7);
0044
0045 if (ret)
0046 return ret;
0047 ret = regmap_write(rdev->regmap, MP8859_VOUT_H_REG, sel >> 3);
0048
0049 if (ret)
0050 return ret;
0051 ret = regmap_update_bits(rdev->regmap, MP8859_VOUT_GO_REG,
0052 MP8859_GO_BIT, 1);
0053 return ret;
0054 }
0055
0056 static int mp8859_get_voltage_sel(struct regulator_dev *rdev)
0057 {
0058 unsigned int val_tmp;
0059 unsigned int val;
0060 int ret;
0061
0062 ret = regmap_read(rdev->regmap, MP8859_VOUT_H_REG, &val_tmp);
0063
0064 if (ret)
0065 return ret;
0066 val = val_tmp << 3;
0067
0068 ret = regmap_read(rdev->regmap, MP8859_VOUT_L_REG, &val_tmp);
0069
0070 if (ret)
0071 return ret;
0072 val |= val_tmp & 0x07;
0073 return val;
0074 }
0075
0076 static const struct linear_range mp8859_dcdc_ranges[] = {
0077 REGULATOR_LINEAR_RANGE(0, VOL_MIN_IDX, VOL_MAX_IDX, 10000),
0078 };
0079
0080 static const struct regmap_config mp8859_regmap = {
0081 .reg_bits = 8,
0082 .val_bits = 8,
0083 .max_register = MP8859_MAX_REG,
0084 .cache_type = REGCACHE_RBTREE,
0085 };
0086
0087 static const struct regulator_ops mp8859_ops = {
0088 .set_voltage_sel = mp8859_set_voltage_sel,
0089 .get_voltage_sel = mp8859_get_voltage_sel,
0090 .list_voltage = regulator_list_voltage_linear_range,
0091 };
0092
0093 static const struct regulator_desc mp8859_regulators[] = {
0094 {
0095 .id = 0,
0096 .type = REGULATOR_VOLTAGE,
0097 .name = "mp8859_dcdc",
0098 .supply_name = "vin",
0099 .of_match = of_match_ptr("mp8859_dcdc"),
0100 .n_voltages = VOL_MAX_IDX + 1,
0101 .linear_ranges = mp8859_dcdc_ranges,
0102 .n_linear_ranges = 1,
0103 .ops = &mp8859_ops,
0104 .owner = THIS_MODULE,
0105 },
0106 };
0107
0108 static int mp8859_i2c_probe(struct i2c_client *i2c)
0109 {
0110 int ret;
0111 struct regulator_config config = {.dev = &i2c->dev};
0112 struct regmap *regmap = devm_regmap_init_i2c(i2c, &mp8859_regmap);
0113 struct regulator_dev *rdev;
0114
0115 if (IS_ERR(regmap)) {
0116 ret = PTR_ERR(regmap);
0117 dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
0118 return ret;
0119 }
0120 rdev = devm_regulator_register(&i2c->dev, &mp8859_regulators[0],
0121 &config);
0122
0123 if (IS_ERR(rdev)) {
0124 ret = PTR_ERR(rdev);
0125 dev_err(&i2c->dev, "failed to register %s: %d\n",
0126 mp8859_regulators[0].name, ret);
0127 return ret;
0128 }
0129 return 0;
0130 }
0131
0132 static const struct of_device_id mp8859_dt_id[] = {
0133 {.compatible = "mps,mp8859"},
0134 {},
0135 };
0136 MODULE_DEVICE_TABLE(of, mp8859_dt_id);
0137
0138 static const struct i2c_device_id mp8859_i2c_id[] = {
0139 { "mp8859", },
0140 { },
0141 };
0142 MODULE_DEVICE_TABLE(i2c, mp8859_i2c_id);
0143
0144 static struct i2c_driver mp8859_regulator_driver = {
0145 .driver = {
0146 .name = "mp8859",
0147 .of_match_table = of_match_ptr(mp8859_dt_id),
0148 },
0149 .probe_new = mp8859_i2c_probe,
0150 .id_table = mp8859_i2c_id,
0151 };
0152
0153 module_i2c_driver(mp8859_regulator_driver);
0154
0155 MODULE_DESCRIPTION("Monolithic Power Systems MP8859 voltage regulator driver");
0156 MODULE_AUTHOR("Markus Reichl <m.reichl@fivetechno.de>");
0157 MODULE_LICENSE("GPL v2");