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 const struct i2c_device_id *id) 211 { 212 struct device *dev = &client->dev; 213 struct device_node *np = dev->of_node; 214 struct mp886x_device_info *di; 215 struct regulator_config config = { }; 216 struct regmap *regmap; 217 int ret; 218 219 di = devm_kzalloc(dev, sizeof(struct mp886x_device_info), GFP_KERNEL); 220 if (!di) 221 return -ENOMEM; 222 223 di->regulator = of_get_regulator_init_data(dev, np, &di->desc); 224 if (!di->regulator) { 225 dev_err(dev, "Platform data not found!\n"); 226 return -EINVAL; 227 } 228 229 ret = of_property_read_u32_array(np, "mps,fb-voltage-divider", 230 di->r, 2); 231 if (ret) 232 return ret; 233 234 di->en_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); 235 if (IS_ERR(di->en_gpio)) 236 return PTR_ERR(di->en_gpio); 237 238 di->dev = dev; 239 240 regmap = devm_regmap_init_i2c(client, &mp886x_regmap_config); 241 if (IS_ERR(regmap)) { 242 dev_err(dev, "Failed to allocate regmap!\n"); 243 return PTR_ERR(regmap); 244 } 245 i2c_set_clientdata(client, di); 246 247 config.dev = di->dev; 248 config.init_data = di->regulator; 249 config.regmap = regmap; 250 config.driver_data = di; 251 config.of_node = np; 252 253 ret = mp886x_regulator_register(di, &config); 254 if (ret < 0) 255 dev_err(dev, "Failed to register regulator!\n"); 256 return ret; 257 } 258 259 static const struct of_device_id mp886x_dt_ids[] = { 260 { 261 .compatible = "mps,mp8867", 262 .data = &mp8867_regulator_ops 263 }, 264 { 265 .compatible = "mps,mp8869", 266 .data = &mp8869_regulator_ops 267 }, 268 { } 269 }; 270 MODULE_DEVICE_TABLE(of, mp886x_dt_ids); 271 272 static const struct i2c_device_id mp886x_id[] = { 273 { "mp886x", }, 274 { }, 275 }; 276 MODULE_DEVICE_TABLE(i2c, mp886x_id); 277 278 static struct i2c_driver mp886x_regulator_driver = { 279 .driver = { 280 .name = "mp886x-regulator", 281 .of_match_table = of_match_ptr(mp886x_dt_ids), 282 }, 283 .probe = mp886x_i2c_probe, 284 .id_table = mp886x_id, 285 }; 286 module_i2c_driver(mp886x_regulator_driver); 287 288 MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); 289 MODULE_DESCRIPTION("MP886x regulator driver"); 290 MODULE_LICENSE("GPL v2"); 291