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_GO (1 << 6) 22 #define MP886X_EN (1 << 7) 23 24 struct mp886x_device_info { 25 struct device *dev; 26 struct regulator_desc desc; 27 struct regulator_init_data *regulator; 28 struct gpio_desc *en_gpio; 29 u32 r[2]; 30 unsigned int sel; 31 }; 32 33 static int mp886x_set_mode(struct regulator_dev *rdev, unsigned int mode) 34 { 35 switch (mode) { 36 case REGULATOR_MODE_FAST: 37 regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1, 38 MP886X_MODE, MP886X_MODE); 39 break; 40 case REGULATOR_MODE_NORMAL: 41 regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1, 42 MP886X_MODE, 0); 43 break; 44 default: 45 return -EINVAL; 46 } 47 return 0; 48 } 49 50 static unsigned int mp886x_get_mode(struct regulator_dev *rdev) 51 { 52 u32 val; 53 int ret; 54 55 ret = regmap_read(rdev->regmap, MP886X_SYSCNTLREG1, &val); 56 if (ret < 0) 57 return ret; 58 if (val & MP886X_MODE) 59 return REGULATOR_MODE_FAST; 60 else 61 return REGULATOR_MODE_NORMAL; 62 } 63 64 static int mp8869_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) 65 { 66 int ret; 67 68 ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1, 69 MP886X_GO, MP886X_GO); 70 if (ret < 0) 71 return ret; 72 73 sel <<= ffs(rdev->desc->vsel_mask) - 1; 74 return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, 75 MP886X_V_BOOT | rdev->desc->vsel_mask, sel); 76 } 77 78 static inline unsigned int mp8869_scale(unsigned int uv, u32 r1, u32 r2) 79 { 80 u32 tmp = uv * r1 / r2; 81 82 return uv + tmp; 83 } 84 85 static int mp8869_get_voltage_sel(struct regulator_dev *rdev) 86 { 87 struct mp886x_device_info *di = rdev_get_drvdata(rdev); 88 int ret, uv; 89 unsigned int val; 90 bool fbloop; 91 92 ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); 93 if (ret) 94 return ret; 95 96 fbloop = val & MP886X_V_BOOT; 97 if (fbloop) { 98 uv = rdev->desc->min_uV; 99 uv = mp8869_scale(uv, di->r[0], di->r[1]); 100 return regulator_map_voltage_linear(rdev, uv, uv); 101 } 102 103 val &= rdev->desc->vsel_mask; 104 val >>= ffs(rdev->desc->vsel_mask) - 1; 105 106 return val; 107 } 108 109 static const struct regulator_ops mp8869_regulator_ops = { 110 .set_voltage_sel = mp8869_set_voltage_sel, 111 .get_voltage_sel = mp8869_get_voltage_sel, 112 .set_voltage_time_sel = regulator_set_voltage_time_sel, 113 .map_voltage = regulator_map_voltage_linear, 114 .list_voltage = regulator_list_voltage_linear, 115 .enable = regulator_enable_regmap, 116 .disable = regulator_disable_regmap, 117 .is_enabled = regulator_is_enabled_regmap, 118 .set_mode = mp886x_set_mode, 119 .get_mode = mp886x_get_mode, 120 }; 121 122 static int mp8867_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) 123 { 124 struct mp886x_device_info *di = rdev_get_drvdata(rdev); 125 int ret, delta; 126 127 ret = mp8869_set_voltage_sel(rdev, sel); 128 if (ret < 0) 129 return ret; 130 131 delta = di->sel - sel; 132 if (abs(delta) <= 5) 133 ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1, 134 MP886X_GO, 0); 135 di->sel = sel; 136 137 return ret; 138 } 139 140 static int mp8867_get_voltage_sel(struct regulator_dev *rdev) 141 { 142 struct mp886x_device_info *di = rdev_get_drvdata(rdev); 143 int ret, uv; 144 unsigned int val; 145 bool fbloop; 146 147 ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); 148 if (ret) 149 return ret; 150 151 fbloop = val & MP886X_V_BOOT; 152 153 val &= rdev->desc->vsel_mask; 154 val >>= ffs(rdev->desc->vsel_mask) - 1; 155 156 if (fbloop) { 157 uv = regulator_list_voltage_linear(rdev, val); 158 uv = mp8869_scale(uv, di->r[0], di->r[1]); 159 return regulator_map_voltage_linear(rdev, uv, uv); 160 } 161 162 return val; 163 } 164 165 static const struct regulator_ops mp8867_regulator_ops = { 166 .set_voltage_sel = mp8867_set_voltage_sel, 167 .get_voltage_sel = mp8867_get_voltage_sel, 168 .set_voltage_time_sel = regulator_set_voltage_time_sel, 169 .map_voltage = regulator_map_voltage_linear, 170 .list_voltage = regulator_list_voltage_linear, 171 .enable = regulator_enable_regmap, 172 .disable = regulator_disable_regmap, 173 .is_enabled = regulator_is_enabled_regmap, 174 .set_mode = mp886x_set_mode, 175 .get_mode = mp886x_get_mode, 176 }; 177 178 static int mp886x_regulator_register(struct mp886x_device_info *di, 179 struct regulator_config *config) 180 { 181 struct regulator_desc *rdesc = &di->desc; 182 struct regulator_dev *rdev; 183 184 rdesc->name = "mp886x-reg"; 185 rdesc->supply_name = "vin"; 186 rdesc->ops = of_device_get_match_data(di->dev); 187 rdesc->type = REGULATOR_VOLTAGE; 188 rdesc->n_voltages = 128; 189 rdesc->enable_reg = MP886X_SYSCNTLREG1; 190 rdesc->enable_mask = MP886X_EN; 191 rdesc->min_uV = 600000; 192 rdesc->uV_step = 10000; 193 rdesc->vsel_reg = MP886X_VSEL; 194 rdesc->vsel_mask = 0x3f; 195 rdesc->owner = THIS_MODULE; 196 197 rdev = devm_regulator_register(di->dev, &di->desc, config); 198 if (IS_ERR(rdev)) 199 return PTR_ERR(rdev); 200 di->sel = rdesc->ops->get_voltage_sel(rdev); 201 return 0; 202 } 203 204 static const struct regmap_config mp886x_regmap_config = { 205 .reg_bits = 8, 206 .val_bits = 8, 207 }; 208 209 static int mp886x_i2c_probe(struct i2c_client *client) 210 { 211 struct device *dev = &client->dev; 212 struct device_node *np = dev->of_node; 213 struct mp886x_device_info *di; 214 struct regulator_config config = { }; 215 struct regmap *regmap; 216 int ret; 217 218 di = devm_kzalloc(dev, sizeof(struct mp886x_device_info), GFP_KERNEL); 219 if (!di) 220 return -ENOMEM; 221 222 di->regulator = of_get_regulator_init_data(dev, np, &di->desc); 223 if (!di->regulator) { 224 dev_err(dev, "Platform data not found!\n"); 225 return -EINVAL; 226 } 227 228 ret = of_property_read_u32_array(np, "mps,fb-voltage-divider", 229 di->r, 2); 230 if (ret) 231 return ret; 232 233 di->en_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); 234 if (IS_ERR(di->en_gpio)) 235 return PTR_ERR(di->en_gpio); 236 237 di->dev = dev; 238 239 regmap = devm_regmap_init_i2c(client, &mp886x_regmap_config); 240 if (IS_ERR(regmap)) { 241 dev_err(dev, "Failed to allocate regmap!\n"); 242 return PTR_ERR(regmap); 243 } 244 i2c_set_clientdata(client, di); 245 246 config.dev = di->dev; 247 config.init_data = di->regulator; 248 config.regmap = regmap; 249 config.driver_data = di; 250 config.of_node = np; 251 252 ret = mp886x_regulator_register(di, &config); 253 if (ret < 0) 254 dev_err(dev, "Failed to register regulator!\n"); 255 return ret; 256 } 257 258 static const struct of_device_id mp886x_dt_ids[] = { 259 { 260 .compatible = "mps,mp8867", 261 .data = &mp8867_regulator_ops 262 }, 263 { 264 .compatible = "mps,mp8869", 265 .data = &mp8869_regulator_ops 266 }, 267 { } 268 }; 269 MODULE_DEVICE_TABLE(of, mp886x_dt_ids); 270 271 static const struct i2c_device_id mp886x_id[] = { 272 { "mp886x", }, 273 { }, 274 }; 275 MODULE_DEVICE_TABLE(i2c, mp886x_id); 276 277 static struct i2c_driver mp886x_regulator_driver = { 278 .driver = { 279 .name = "mp886x-regulator", 280 .of_match_table = of_match_ptr(mp886x_dt_ids), 281 }, 282 .probe_new = mp886x_i2c_probe, 283 .id_table = mp886x_id, 284 }; 285 module_i2c_driver(mp886x_regulator_driver); 286 287 MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); 288 MODULE_DESCRIPTION("MP886x regulator driver"); 289 MODULE_LICENSE("GPL v2"); 290