| 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* |
| 3 | * Copyright (c) 2023 Analog Devices, Inc. |
| 4 | * ADI Regulator driver for the MAX77857 |
| 5 | * MAX77859 and MAX77831. |
| 6 | */ |
| 7 | #include <linux/bitfield.h> |
| 8 | #include <linux/i2c.h> |
| 9 | #include <linux/interrupt.h> |
| 10 | #include <linux/module.h> |
| 11 | #include <linux/regmap.h> |
| 12 | #include <linux/regulator/driver.h> |
| 13 | #include <linux/regulator/machine.h> |
| 14 | #include <linux/regulator/of_regulator.h> |
| 15 | #include <linux/util_macros.h> |
| 16 | |
| 17 | #define MAX77857_REG_INT_SRC 0x10 |
| 18 | #define MAX77857_REG_INT_MASK 0x11 |
| 19 | #define MAX77857_REG_CONT1 0x12 |
| 20 | #define MAX77857_REG_CONT2 0x13 |
| 21 | #define MAX77857_REG_CONT3 0x14 |
| 22 | |
| 23 | #define MAX77857_INT_SRC_OCP BIT(0) |
| 24 | #define MAX77857_INT_SRC_THS BIT(1) |
| 25 | #define MAX77857_INT_SRC_HARDSHORT BIT(2) |
| 26 | #define MAX77857_INT_SRC_OVP BIT(3) |
| 27 | #define MAX77857_INT_SRC_POK BIT(4) |
| 28 | |
| 29 | #define MAX77857_ILIM_MASK GENMASK(2, 0) |
| 30 | #define MAX77857_CONT1_FREQ GENMASK(4, 3) |
| 31 | #define MAX77857_CONT3_FPWM BIT(5) |
| 32 | |
| 33 | #define MAX77859_REG_INT_SRC 0x11 |
| 34 | #define MAX77859_REG_CONT1 0x13 |
| 35 | #define MAX77859_REG_CONT2 0x14 |
| 36 | #define MAX77859_REG_CONT3 0x15 |
| 37 | #define MAX77859_REG_CONT5 0x17 |
| 38 | #define MAX77859_CONT2_FPWM BIT(2) |
| 39 | #define MAX77859_CONT2_INTB BIT(3) |
| 40 | #define MAX77859_CONT3_DVS_START BIT(2) |
| 41 | #define MAX77859_VOLTAGE_SEL_MASK GENMASK(9, 0) |
| 42 | |
| 43 | #define MAX77859_CURRENT_MIN 1000000 |
| 44 | #define MAX77859_CURRENT_MAX 5000000 |
| 45 | #define MAX77859_CURRENT_STEP 50000 |
| 46 | |
| 47 | enum max77857_id { |
| 48 | ID_MAX77831 = 1, |
| 49 | ID_MAX77857, |
| 50 | ID_MAX77859, |
| 51 | ID_MAX77859A, |
| 52 | }; |
| 53 | |
| 54 | static bool max77857_volatile_reg(struct device *dev, unsigned int reg) |
| 55 | { |
| 56 | enum max77857_id id = (uintptr_t)dev_get_drvdata(dev); |
| 57 | |
| 58 | switch (id) { |
| 59 | case ID_MAX77831: |
| 60 | case ID_MAX77857: |
| 61 | return reg == MAX77857_REG_INT_SRC; |
| 62 | case ID_MAX77859: |
| 63 | case ID_MAX77859A: |
| 64 | return reg == MAX77859_REG_INT_SRC; |
| 65 | default: |
| 66 | return true; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | static const struct regmap_config max77857_regmap_config = { |
| 71 | .reg_bits = 8, |
| 72 | .val_bits = 8, |
| 73 | .cache_type = REGCACHE_MAPLE, |
| 74 | .volatile_reg = max77857_volatile_reg, |
| 75 | }; |
| 76 | |
| 77 | static int max77857_get_status(struct regulator_dev *rdev) |
| 78 | { |
| 79 | unsigned int val; |
| 80 | int ret; |
| 81 | |
| 82 | ret = regmap_read(map: rdev->regmap, MAX77857_REG_INT_SRC, val: &val); |
| 83 | if (ret) |
| 84 | return ret; |
| 85 | |
| 86 | if (FIELD_GET(MAX77857_INT_SRC_POK, val)) |
| 87 | return REGULATOR_STATUS_ON; |
| 88 | |
| 89 | return REGULATOR_STATUS_ERROR; |
| 90 | } |
| 91 | |
| 92 | static unsigned int max77857_get_mode(struct regulator_dev *rdev) |
| 93 | { |
| 94 | enum max77857_id id = (uintptr_t)rdev_get_drvdata(rdev); |
| 95 | unsigned int regval; |
| 96 | int ret; |
| 97 | |
| 98 | switch (id) { |
| 99 | case ID_MAX77831: |
| 100 | case ID_MAX77857: |
| 101 | ret = regmap_read(map: rdev->regmap, MAX77857_REG_CONT3, val: ®val); |
| 102 | if (ret) |
| 103 | return ret; |
| 104 | |
| 105 | if (FIELD_GET(MAX77857_CONT3_FPWM, regval)) |
| 106 | return REGULATOR_MODE_FAST; |
| 107 | |
| 108 | break; |
| 109 | case ID_MAX77859: |
| 110 | case ID_MAX77859A: |
| 111 | ret = regmap_read(map: rdev->regmap, MAX77859_REG_CONT2, val: ®val); |
| 112 | if (ret) |
| 113 | return ret; |
| 114 | |
| 115 | if (FIELD_GET(MAX77859_CONT2_FPWM, regval)) |
| 116 | return REGULATOR_MODE_FAST; |
| 117 | |
| 118 | break; |
| 119 | default: |
| 120 | return -EINVAL; |
| 121 | } |
| 122 | |
| 123 | return REGULATOR_MODE_NORMAL; |
| 124 | } |
| 125 | |
| 126 | static int max77857_set_mode(struct regulator_dev *rdev, unsigned int mode) |
| 127 | { |
| 128 | enum max77857_id id = (uintptr_t)rdev_get_drvdata(rdev); |
| 129 | unsigned int reg, val; |
| 130 | |
| 131 | switch (id) { |
| 132 | case ID_MAX77831: |
| 133 | case ID_MAX77857: |
| 134 | reg = MAX77857_REG_CONT3; |
| 135 | val = MAX77857_CONT3_FPWM; |
| 136 | break; |
| 137 | case ID_MAX77859: |
| 138 | case ID_MAX77859A: |
| 139 | reg = MAX77859_REG_CONT2; |
| 140 | val = MAX77859_CONT2_FPWM; |
| 141 | break; |
| 142 | default: |
| 143 | return -EINVAL; |
| 144 | } |
| 145 | |
| 146 | switch (mode) { |
| 147 | case REGULATOR_MODE_FAST: |
| 148 | return regmap_set_bits(map: rdev->regmap, reg, bits: val); |
| 149 | case REGULATOR_MODE_NORMAL: |
| 150 | return regmap_clear_bits(map: rdev->regmap, reg, bits: val); |
| 151 | default: |
| 152 | return -EINVAL; |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | static int max77857_get_error_flags(struct regulator_dev *rdev, |
| 157 | unsigned int *flags) |
| 158 | { |
| 159 | unsigned int val; |
| 160 | int ret; |
| 161 | |
| 162 | ret = regmap_read(map: rdev->regmap, MAX77857_REG_INT_SRC, val: &val); |
| 163 | if (ret) |
| 164 | return ret; |
| 165 | |
| 166 | *flags = 0; |
| 167 | |
| 168 | if (FIELD_GET(MAX77857_INT_SRC_OVP, val)) |
| 169 | *flags |= REGULATOR_ERROR_OVER_VOLTAGE_WARN; |
| 170 | |
| 171 | if (FIELD_GET(MAX77857_INT_SRC_OCP, val) || |
| 172 | FIELD_GET(MAX77857_INT_SRC_HARDSHORT, val)) |
| 173 | *flags |= REGULATOR_ERROR_OVER_CURRENT; |
| 174 | |
| 175 | if (FIELD_GET(MAX77857_INT_SRC_THS, val)) |
| 176 | *flags |= REGULATOR_ERROR_OVER_TEMP; |
| 177 | |
| 178 | if (!FIELD_GET(MAX77857_INT_SRC_POK, val)) |
| 179 | *flags |= REGULATOR_ERROR_FAIL; |
| 180 | |
| 181 | return 0; |
| 182 | } |
| 183 | |
| 184 | static struct linear_range max77859_lin_ranges[] = { |
| 185 | REGULATOR_LINEAR_RANGE(3200000, 0x0A0, 0x320, 20000) |
| 186 | }; |
| 187 | |
| 188 | static const unsigned int max77859_ramp_table[4] = { |
| 189 | 1000, 500, 250, 125 |
| 190 | }; |
| 191 | |
| 192 | static int max77859_set_voltage_sel(struct regulator_dev *rdev, |
| 193 | unsigned int sel) |
| 194 | { |
| 195 | __be16 reg; |
| 196 | int ret; |
| 197 | |
| 198 | reg = cpu_to_be16(sel); |
| 199 | |
| 200 | ret = regmap_bulk_write(map: rdev->regmap, MAX77859_REG_CONT3, val: ®, val_count: 2); |
| 201 | if (ret) |
| 202 | return ret; |
| 203 | |
| 204 | /* actually apply new voltage */ |
| 205 | return regmap_set_bits(map: rdev->regmap, MAX77859_REG_CONT3, |
| 206 | MAX77859_CONT3_DVS_START); |
| 207 | } |
| 208 | |
| 209 | static int max77859_get_voltage_sel(struct regulator_dev *rdev) |
| 210 | { |
| 211 | __be16 reg; |
| 212 | int ret; |
| 213 | |
| 214 | ret = regmap_bulk_read(map: rdev->regmap, MAX77859_REG_CONT3, val: ®, val_count: 2); |
| 215 | if (ret) |
| 216 | return ret; |
| 217 | |
| 218 | return FIELD_GET(MAX77859_VOLTAGE_SEL_MASK, __be16_to_cpu(reg)); |
| 219 | } |
| 220 | |
| 221 | static int max77859_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA) |
| 222 | { |
| 223 | u32 selector; |
| 224 | |
| 225 | if (max_uA < MAX77859_CURRENT_MIN) |
| 226 | return -EINVAL; |
| 227 | |
| 228 | selector = 0x12 + (max_uA - MAX77859_CURRENT_MIN) / MAX77859_CURRENT_STEP; |
| 229 | |
| 230 | selector = clamp_val(selector, 0x00, 0x7F); |
| 231 | |
| 232 | return regmap_write(map: rdev->regmap, MAX77859_REG_CONT5, val: selector); |
| 233 | } |
| 234 | |
| 235 | static int max77859_get_current_limit(struct regulator_dev *rdev) |
| 236 | { |
| 237 | u32 selector; |
| 238 | int ret; |
| 239 | |
| 240 | ret = regmap_read(map: rdev->regmap, MAX77859_REG_CONT5, val: &selector); |
| 241 | if (ret) |
| 242 | return ret; |
| 243 | |
| 244 | if (selector <= 0x12) |
| 245 | return MAX77859_CURRENT_MIN; |
| 246 | |
| 247 | if (selector >= 0x64) |
| 248 | return MAX77859_CURRENT_MAX; |
| 249 | |
| 250 | return MAX77859_CURRENT_MIN + (selector - 0x12) * MAX77859_CURRENT_STEP; |
| 251 | } |
| 252 | |
| 253 | static const struct regulator_ops max77859_regulator_ops = { |
| 254 | .list_voltage = regulator_list_voltage_linear_range, |
| 255 | .set_voltage_sel = max77859_set_voltage_sel, |
| 256 | .get_voltage_sel = max77859_get_voltage_sel, |
| 257 | .set_ramp_delay = regulator_set_ramp_delay_regmap, |
| 258 | .get_status = max77857_get_status, |
| 259 | .set_mode = max77857_set_mode, |
| 260 | .get_mode = max77857_get_mode, |
| 261 | .get_error_flags = max77857_get_error_flags, |
| 262 | }; |
| 263 | |
| 264 | static const struct regulator_ops max77859a_regulator_ops = { |
| 265 | .list_voltage = regulator_list_voltage_linear_range, |
| 266 | .set_voltage_sel = max77859_set_voltage_sel, |
| 267 | .get_voltage_sel = max77859_get_voltage_sel, |
| 268 | .set_current_limit = max77859_set_current_limit, |
| 269 | .get_current_limit = max77859_get_current_limit, |
| 270 | .set_ramp_delay = regulator_set_ramp_delay_regmap, |
| 271 | .get_status = max77857_get_status, |
| 272 | .set_mode = max77857_set_mode, |
| 273 | .get_mode = max77857_get_mode, |
| 274 | .get_error_flags = max77857_get_error_flags, |
| 275 | }; |
| 276 | |
| 277 | static const struct regulator_ops max77857_regulator_ops = { |
| 278 | .list_voltage = regulator_list_voltage_linear_range, |
| 279 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
| 280 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
| 281 | .set_ramp_delay = regulator_set_ramp_delay_regmap, |
| 282 | .get_status = max77857_get_status, |
| 283 | .set_mode = max77857_set_mode, |
| 284 | .get_mode = max77857_get_mode, |
| 285 | .get_error_flags = max77857_get_error_flags, |
| 286 | }; |
| 287 | |
| 288 | static struct linear_range max77857_lin_ranges[] = { |
| 289 | REGULATOR_LINEAR_RANGE(4485000, 0x3D, 0xCC, 73500) |
| 290 | }; |
| 291 | |
| 292 | static const unsigned int max77857_switch_freq[] = { |
| 293 | 1200000, 1500000, 1800000, 2100000 |
| 294 | }; |
| 295 | |
| 296 | #define RAMAP_DELAY_INIT_VAL 1333 |
| 297 | |
| 298 | static const unsigned int max77857_ramp_table[2][4] = { |
| 299 | { RAMAP_DELAY_INIT_VAL, 667, 333, 227 }, /* when switch freq is 1.8MHz or 2.1MHz */ |
| 300 | { 1166, 667, 333, 167 }, /* when switch freq is 1.2MHz or 1.5MHz */ |
| 301 | }; |
| 302 | |
| 303 | static struct regulator_desc max77857_regulator_desc = { |
| 304 | .ops = &max77857_regulator_ops, |
| 305 | .name = "max77857" , |
| 306 | .linear_ranges = max77857_lin_ranges, |
| 307 | .n_linear_ranges = ARRAY_SIZE(max77857_lin_ranges), |
| 308 | .vsel_mask = 0xFF, |
| 309 | .vsel_reg = MAX77857_REG_CONT2, |
| 310 | .ramp_delay_table = max77857_ramp_table[0], |
| 311 | .n_ramp_values = ARRAY_SIZE(max77857_ramp_table[0]), |
| 312 | .ramp_reg = MAX77857_REG_CONT3, |
| 313 | .ramp_mask = GENMASK(1, 0), |
| 314 | .ramp_delay = RAMAP_DELAY_INIT_VAL, |
| 315 | .owner = THIS_MODULE, |
| 316 | }; |
| 317 | |
| 318 | static void max77857_calc_range(struct device *dev, enum max77857_id id) |
| 319 | { |
| 320 | struct linear_range *range; |
| 321 | unsigned long vref_step; |
| 322 | u32 rtop = 0; |
| 323 | u32 rbot = 0; |
| 324 | |
| 325 | device_property_read_u32(dev, propname: "adi,rtop-ohms" , val: &rtop); |
| 326 | device_property_read_u32(dev, propname: "adi,rbot-ohms" , val: &rbot); |
| 327 | |
| 328 | if (!rbot || !rtop) |
| 329 | return; |
| 330 | |
| 331 | switch (id) { |
| 332 | case ID_MAX77831: |
| 333 | case ID_MAX77857: |
| 334 | range = max77857_lin_ranges; |
| 335 | vref_step = 4900UL; |
| 336 | break; |
| 337 | case ID_MAX77859: |
| 338 | case ID_MAX77859A: |
| 339 | range = max77859_lin_ranges; |
| 340 | vref_step = 1250UL; |
| 341 | break; |
| 342 | } |
| 343 | |
| 344 | range->step = DIV_ROUND_CLOSEST(vref_step * (rbot + rtop), rbot); |
| 345 | range->min = range->step * range->min_sel; |
| 346 | } |
| 347 | |
| 348 | static int max77857_probe(struct i2c_client *client) |
| 349 | { |
| 350 | const struct i2c_device_id *i2c_id; |
| 351 | struct device *dev = &client->dev; |
| 352 | struct regulator_config cfg = { }; |
| 353 | struct regulator_dev *rdev; |
| 354 | struct regmap *regmap; |
| 355 | enum max77857_id id; |
| 356 | u32 switch_freq = 0; |
| 357 | int ret; |
| 358 | |
| 359 | i2c_id = i2c_client_get_device_id(client); |
| 360 | if (!i2c_id) |
| 361 | return -EINVAL; |
| 362 | |
| 363 | id = i2c_id->driver_data; |
| 364 | |
| 365 | dev_set_drvdata(dev, data: (void *)id); |
| 366 | |
| 367 | if (id == ID_MAX77859 || id == ID_MAX77859A) { |
| 368 | max77857_regulator_desc.ops = &max77859_regulator_ops; |
| 369 | max77857_regulator_desc.linear_ranges = max77859_lin_ranges; |
| 370 | max77857_regulator_desc.ramp_delay_table = max77859_ramp_table; |
| 371 | max77857_regulator_desc.ramp_delay = max77859_ramp_table[0]; |
| 372 | } |
| 373 | |
| 374 | if (id == ID_MAX77859A) |
| 375 | max77857_regulator_desc.ops = &max77859a_regulator_ops; |
| 376 | |
| 377 | max77857_calc_range(dev, id); |
| 378 | |
| 379 | regmap = devm_regmap_init_i2c(client, &max77857_regmap_config); |
| 380 | if (IS_ERR(ptr: regmap)) |
| 381 | return dev_err_probe(dev, err: PTR_ERR(ptr: regmap), |
| 382 | fmt: "cannot initialize regmap\n" ); |
| 383 | |
| 384 | device_property_read_u32(dev, propname: "adi,switch-frequency-hz" , val: &switch_freq); |
| 385 | if (switch_freq) { |
| 386 | switch_freq = find_closest(switch_freq, max77857_switch_freq, |
| 387 | ARRAY_SIZE(max77857_switch_freq)); |
| 388 | |
| 389 | if (id == ID_MAX77831 && switch_freq == 3) |
| 390 | switch_freq = 2; |
| 391 | |
| 392 | switch (id) { |
| 393 | case ID_MAX77831: |
| 394 | case ID_MAX77857: |
| 395 | ret = regmap_update_bits(map: regmap, MAX77857_REG_CONT1, |
| 396 | MAX77857_CONT1_FREQ, val: switch_freq); |
| 397 | |
| 398 | if (switch_freq >= 2) |
| 399 | break; |
| 400 | |
| 401 | max77857_regulator_desc.ramp_delay_table = max77857_ramp_table[1]; |
| 402 | max77857_regulator_desc.ramp_delay = max77857_ramp_table[1][0]; |
| 403 | break; |
| 404 | case ID_MAX77859: |
| 405 | case ID_MAX77859A: |
| 406 | ret = regmap_update_bits(map: regmap, MAX77859_REG_CONT1, |
| 407 | MAX77857_CONT1_FREQ, val: switch_freq); |
| 408 | break; |
| 409 | } |
| 410 | if (ret) |
| 411 | return ret; |
| 412 | } |
| 413 | |
| 414 | cfg.dev = dev; |
| 415 | cfg.driver_data = (void *)id; |
| 416 | cfg.regmap = regmap; |
| 417 | cfg.init_data = of_get_regulator_init_data(dev, node: dev->of_node, |
| 418 | desc: &max77857_regulator_desc); |
| 419 | if (!cfg.init_data) |
| 420 | return -ENOMEM; |
| 421 | |
| 422 | rdev = devm_regulator_register(dev, regulator_desc: &max77857_regulator_desc, config: &cfg); |
| 423 | if (IS_ERR(ptr: rdev)) |
| 424 | return dev_err_probe(dev, err: PTR_ERR(ptr: rdev), |
| 425 | fmt: "cannot register regulator\n" ); |
| 426 | |
| 427 | return 0; |
| 428 | } |
| 429 | |
| 430 | static const struct i2c_device_id max77857_id[] = { |
| 431 | { "max77831" , ID_MAX77831 }, |
| 432 | { "max77857" , ID_MAX77857 }, |
| 433 | { "max77859" , ID_MAX77859 }, |
| 434 | { "max77859a" , ID_MAX77859A }, |
| 435 | { } |
| 436 | }; |
| 437 | MODULE_DEVICE_TABLE(i2c, max77857_id); |
| 438 | |
| 439 | static const struct of_device_id max77857_of_id[] = { |
| 440 | { .compatible = "adi,max77831" , .data = (void *)ID_MAX77831 }, |
| 441 | { .compatible = "adi,max77857" , .data = (void *)ID_MAX77857 }, |
| 442 | { .compatible = "adi,max77859" , .data = (void *)ID_MAX77859 }, |
| 443 | { .compatible = "adi,max77859a" , .data = (void *)ID_MAX77859A }, |
| 444 | { } |
| 445 | }; |
| 446 | MODULE_DEVICE_TABLE(of, max77857_of_id); |
| 447 | |
| 448 | static struct i2c_driver max77857_driver = { |
| 449 | .driver = { |
| 450 | .name = "max77857" , |
| 451 | .of_match_table = max77857_of_id, |
| 452 | }, |
| 453 | .id_table = max77857_id, |
| 454 | .probe = max77857_probe, |
| 455 | }; |
| 456 | module_i2c_driver(max77857_driver); |
| 457 | |
| 458 | MODULE_DESCRIPTION("Analog Devices MAX77857 Buck-Boost Converter Driver" ); |
| 459 | MODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>" ); |
| 460 | MODULE_AUTHOR("Okan Sahin <Okan.Sahin@analog.com>" ); |
| 461 | MODULE_LICENSE("GPL" ); |
| 462 | |