Blame view
drivers/regulator/fan53555.c
13.4 KB
6a1beee2f
|
1 2 3 4 5 6 7 8 9 |
// SPDX-License-Identifier: GPL-2.0 // // FAN53555 Fairchild Digitally Programmable TinyBuck Regulator Driver. // // Supported Part Numbers: // FAN53555UC00X/01X/03X/04X/05X // // Copyright (c) 2012 Marvell Technology Ltd. // Yunfan Zhang <yfzhang@marvell.com> |
49d8c5992
|
10 11 12 13 14 15 |
#include <linux/module.h> #include <linux/param.h> #include <linux/err.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> |
91f23d8fb
|
16 17 |
#include <linux/regulator/of_regulator.h> #include <linux/of_device.h> |
49d8c5992
|
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include <linux/i2c.h> #include <linux/slab.h> #include <linux/regmap.h> #include <linux/regulator/fan53555.h> /* Voltage setting */ #define FAN53555_VSEL0 0x00 #define FAN53555_VSEL1 0x01 /* Control register */ #define FAN53555_CONTROL 0x02 /* IC Type */ #define FAN53555_ID1 0x03 /* IC mask version */ #define FAN53555_ID2 0x04 /* Monitor register */ #define FAN53555_MONITOR 0x05 /* VSEL bit definitions */ #define VSEL_BUCK_EN (1 << 7) #define VSEL_MODE (1 << 6) |
49d8c5992
|
38 39 40 41 42 43 44 45 |
/* Chip ID and Verison */ #define DIE_ID 0x0F /* ID1 */ #define DIE_REV 0x0F /* ID2 */ /* Control bit definitions */ #define CTL_OUTPUT_DISCHG (1 << 7) #define CTL_SLEW_MASK (0x7 << 4) #define CTL_SLEW_SHIFT 4 #define CTL_RESET (1 << 2) |
f2a9eb975
|
46 47 |
#define CTL_MODE_VSEL0_MODE BIT(0) #define CTL_MODE_VSEL1_MODE BIT(1) |
49d8c5992
|
48 49 |
#define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ |
f2a9eb975
|
50 |
#define FAN53526_NVOLTAGES 128 |
49d8c5992
|
51 |
|
ee30928ab
|
52 |
enum fan53555_vendor { |
f2a9eb975
|
53 54 |
FAN53526_VENDOR_FAIRCHILD = 0, FAN53555_VENDOR_FAIRCHILD, |
ee30928ab
|
55 56 |
FAN53555_VENDOR_SILERGY, }; |
f2a9eb975
|
57 58 59 60 61 62 63 |
enum { FAN53526_CHIP_ID_01 = 1, }; enum { FAN53526_CHIP_REV_08 = 8, }; |
49d8c5992
|
64 65 66 67 68 69 70 71 |
/* IC Type */ enum { FAN53555_CHIP_ID_00 = 0, FAN53555_CHIP_ID_01, FAN53555_CHIP_ID_02, FAN53555_CHIP_ID_03, FAN53555_CHIP_ID_04, FAN53555_CHIP_ID_05, |
5e39cf497
|
72 |
FAN53555_CHIP_ID_08 = 8, |
49d8c5992
|
73 |
}; |
e57cbb70b
|
74 75 76 77 78 |
/* IC mask revision */ enum { FAN53555_CHIP_REV_00 = 0x3, FAN53555_CHIP_REV_13 = 0xf, }; |
ee30928ab
|
79 80 |
enum { SILERGY_SYR82X = 8, |
5365e3df4
|
81 |
SILERGY_SYR83X = 9, |
ee30928ab
|
82 |
}; |
49d8c5992
|
83 |
struct fan53555_device_info { |
ee30928ab
|
84 |
enum fan53555_vendor vendor; |
49d8c5992
|
85 86 |
struct device *dev; struct regulator_desc desc; |
49d8c5992
|
87 88 89 90 91 92 93 94 95 |
struct regulator_init_data *regulator; /* IC Type and Rev */ int chip_id; int chip_rev; /* Voltage setting register */ unsigned int vol_reg; unsigned int sleep_reg; /* Voltage range and step(linear) */ unsigned int vsel_min; |
49d8c5992
|
96 |
unsigned int vsel_step; |
f2a9eb975
|
97 |
unsigned int vsel_count; |
f2a9eb975
|
98 99 100 |
/* Mode */ unsigned int mode_reg; unsigned int mode_mask; |
49d8c5992
|
101 102 103 104 105 106 107 108 109 110 111 112 113 |
/* Sleep voltage cache */ unsigned int sleep_vol_cache; }; static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); int ret; if (di->sleep_vol_cache == uV) return 0; ret = regulator_map_voltage_linear(rdev, uV, uV); if (ret < 0) |
145fe1e1d
|
114 |
return ret; |
a69929c7a
|
115 |
ret = regmap_update_bits(rdev->regmap, di->sleep_reg, |
f2a9eb975
|
116 |
di->desc.vsel_mask, ret); |
49d8c5992
|
117 |
if (ret < 0) |
145fe1e1d
|
118 |
return ret; |
49d8c5992
|
119 120 121 122 123 124 |
/* Cache the sleep voltage setting. * Might not be the real voltage which is rounded */ di->sleep_vol_cache = uV; return 0; } |
ab7cad331
|
125 126 127 |
static int fan53555_set_suspend_enable(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); |
a69929c7a
|
128 |
return regmap_update_bits(rdev->regmap, di->sleep_reg, |
ab7cad331
|
129 130 131 132 133 134 |
VSEL_BUCK_EN, VSEL_BUCK_EN); } static int fan53555_set_suspend_disable(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); |
a69929c7a
|
135 |
return regmap_update_bits(rdev->regmap, di->sleep_reg, |
ab7cad331
|
136 137 |
VSEL_BUCK_EN, 0); } |
49d8c5992
|
138 139 140 141 142 143 |
static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); switch (mode) { case REGULATOR_MODE_FAST: |
a69929c7a
|
144 |
regmap_update_bits(rdev->regmap, di->mode_reg, |
f2a9eb975
|
145 |
di->mode_mask, di->mode_mask); |
49d8c5992
|
146 147 |
break; case REGULATOR_MODE_NORMAL: |
a69929c7a
|
148 |
regmap_update_bits(rdev->regmap, di->vol_reg, di->mode_mask, 0); |
49d8c5992
|
149 150 151 152 153 154 155 156 157 158 159 160 |
break; default: return -EINVAL; } return 0; } static unsigned int fan53555_get_mode(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); unsigned int val; int ret = 0; |
a69929c7a
|
161 |
ret = regmap_read(rdev->regmap, di->mode_reg, &val); |
49d8c5992
|
162 163 |
if (ret < 0) return ret; |
f2a9eb975
|
164 |
if (val & di->mode_mask) |
49d8c5992
|
165 166 167 168 |
return REGULATOR_MODE_FAST; else return REGULATOR_MODE_NORMAL; } |
121b567d8
|
169 |
static const int slew_rates[] = { |
dd7e71fbe
|
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
64000, 32000, 16000, 8000, 4000, 2000, 1000, 500, }; static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); int regval = -1, i; for (i = 0; i < ARRAY_SIZE(slew_rates); i++) { if (ramp <= slew_rates[i]) regval = i; else break; } if (regval < 0) { dev_err(di->dev, "unsupported ramp value %d ", ramp); return -EINVAL; } |
a69929c7a
|
197 |
return regmap_update_bits(rdev->regmap, FAN53555_CONTROL, |
dd7e71fbe
|
198 199 |
CTL_SLEW_MASK, regval << CTL_SLEW_SHIFT); } |
71880ab24
|
200 |
static const struct regulator_ops fan53555_regulator_ops = { |
49d8c5992
|
201 202 |
.set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, |
fda87a428
|
203 |
.set_voltage_time_sel = regulator_set_voltage_time_sel, |
49d8c5992
|
204 205 206 207 208 209 210 211 |
.map_voltage = regulator_map_voltage_linear, .list_voltage = regulator_list_voltage_linear, .set_suspend_voltage = fan53555_set_suspend_voltage, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .set_mode = fan53555_set_mode, .get_mode = fan53555_get_mode, |
dd7e71fbe
|
212 |
.set_ramp_delay = fan53555_set_ramp, |
ab7cad331
|
213 214 |
.set_suspend_enable = fan53555_set_suspend_enable, .set_suspend_disable = fan53555_set_suspend_disable, |
49d8c5992
|
215 |
}; |
f2a9eb975
|
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di) { /* Init voltage range and step */ switch (di->chip_id) { case FAN53526_CHIP_ID_01: switch (di->chip_rev) { case FAN53526_CHIP_REV_08: di->vsel_min = 600000; di->vsel_step = 6250; break; default: dev_err(di->dev, "Chip ID %d with rev %d not supported! ", di->chip_id, di->chip_rev); return -EINVAL; } break; default: dev_err(di->dev, "Chip ID %d not supported! ", di->chip_id); return -EINVAL; } di->vsel_count = FAN53526_NVOLTAGES; return 0; } |
ee30928ab
|
245 246 247 248 249 |
static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) { /* Init voltage range and step */ switch (di->chip_id) { case FAN53555_CHIP_ID_00: |
e57cbb70b
|
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
switch (di->chip_rev) { case FAN53555_CHIP_REV_00: di->vsel_min = 600000; di->vsel_step = 10000; break; case FAN53555_CHIP_REV_13: di->vsel_min = 800000; di->vsel_step = 10000; break; default: dev_err(di->dev, "Chip ID %d with rev %d not supported! ", di->chip_id, di->chip_rev); return -EINVAL; } break; |
ee30928ab
|
267 268 269 |
case FAN53555_CHIP_ID_01: case FAN53555_CHIP_ID_03: case FAN53555_CHIP_ID_05: |
5e39cf497
|
270 |
case FAN53555_CHIP_ID_08: |
ee30928ab
|
271 272 273 274 275 276 277 278 279 280 281 282 283 |
di->vsel_min = 600000; di->vsel_step = 10000; break; case FAN53555_CHIP_ID_04: di->vsel_min = 603000; di->vsel_step = 12826; break; default: dev_err(di->dev, "Chip ID %d not supported! ", di->chip_id); return -EINVAL; } |
f2a9eb975
|
284 |
di->vsel_count = FAN53555_NVOLTAGES; |
ee30928ab
|
285 286 287 288 289 290 291 292 |
return 0; } static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) { /* Init voltage range and step */ switch (di->chip_id) { case SILERGY_SYR82X: |
5365e3df4
|
293 |
case SILERGY_SYR83X: |
ee30928ab
|
294 295 296 297 298 299 300 301 302 |
di->vsel_min = 712500; di->vsel_step = 12500; break; default: dev_err(di->dev, "Chip ID %d not supported! ", di->chip_id); return -EINVAL; } |
f2a9eb975
|
303 |
di->vsel_count = FAN53555_NVOLTAGES; |
ee30928ab
|
304 305 |
return 0; } |
49d8c5992
|
306 307 308 309 310 311 312 313 |
/* For 00,01,03,05 options: * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. * For 04 option: * VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V. * */ static int fan53555_device_setup(struct fan53555_device_info *di, struct fan53555_platform_data *pdata) { |
ee30928ab
|
314 |
int ret = 0; |
49d8c5992
|
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
/* Setup voltage control register */ switch (pdata->sleep_vsel_id) { case FAN53555_VSEL_ID_0: di->sleep_reg = FAN53555_VSEL0; di->vol_reg = FAN53555_VSEL1; break; case FAN53555_VSEL_ID_1: di->sleep_reg = FAN53555_VSEL1; di->vol_reg = FAN53555_VSEL0; break; default: dev_err(di->dev, "Invalid VSEL ID! "); return -EINVAL; } |
ee30928ab
|
330 |
|
f2a9eb975
|
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
/* Setup mode control register */ switch (di->vendor) { case FAN53526_VENDOR_FAIRCHILD: di->mode_reg = FAN53555_CONTROL; switch (pdata->sleep_vsel_id) { case FAN53555_VSEL_ID_0: di->mode_mask = CTL_MODE_VSEL1_MODE; break; case FAN53555_VSEL_ID_1: di->mode_mask = CTL_MODE_VSEL0_MODE; break; } break; case FAN53555_VENDOR_FAIRCHILD: case FAN53555_VENDOR_SILERGY: di->mode_reg = di->vol_reg; di->mode_mask = VSEL_MODE; break; default: dev_err(di->dev, "vendor %d not supported! ", di->vendor); return -EINVAL; } /* Setup voltage range */ |
ee30928ab
|
357 |
switch (di->vendor) { |
f2a9eb975
|
358 359 360 |
case FAN53526_VENDOR_FAIRCHILD: ret = fan53526_voltages_setup_fairchild(di); break; |
ee30928ab
|
361 362 |
case FAN53555_VENDOR_FAIRCHILD: ret = fan53555_voltages_setup_fairchild(di); |
49d8c5992
|
363 |
break; |
ee30928ab
|
364 365 |
case FAN53555_VENDOR_SILERGY: ret = fan53555_voltages_setup_silergy(di); |
49d8c5992
|
366 367 |
break; default: |
fe230531b
|
368 369 |
dev_err(di->dev, "vendor %d not supported! ", di->vendor); |
49d8c5992
|
370 371 |
return -EINVAL; } |
dd7e71fbe
|
372 |
|
ee30928ab
|
373 |
return ret; |
49d8c5992
|
374 375 376 377 378 379 |
} static int fan53555_regulator_register(struct fan53555_device_info *di, struct regulator_config *config) { struct regulator_desc *rdesc = &di->desc; |
a69929c7a
|
380 |
struct regulator_dev *rdev; |
49d8c5992
|
381 382 |
rdesc->name = "fan53555-reg"; |
3415d6011
|
383 |
rdesc->supply_name = "vin"; |
49d8c5992
|
384 385 |
rdesc->ops = &fan53555_regulator_ops; rdesc->type = REGULATOR_VOLTAGE; |
f2a9eb975
|
386 |
rdesc->n_voltages = di->vsel_count; |
49d8c5992
|
387 388 389 390 391 |
rdesc->enable_reg = di->vol_reg; rdesc->enable_mask = VSEL_BUCK_EN; rdesc->min_uV = di->vsel_min; rdesc->uV_step = di->vsel_step; rdesc->vsel_reg = di->vol_reg; |
f2a9eb975
|
392 |
rdesc->vsel_mask = di->vsel_count - 1; |
49d8c5992
|
393 |
rdesc->owner = THIS_MODULE; |
a69929c7a
|
394 395 |
rdev = devm_regulator_register(di->dev, &di->desc, config); return PTR_ERR_OR_ZERO(rdev); |
49d8c5992
|
396 |
} |
121b567d8
|
397 |
static const struct regmap_config fan53555_regmap_config = { |
49d8c5992
|
398 399 400 |
.reg_bits = 8, .val_bits = 8, }; |
91f23d8fb
|
401 |
static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, |
072e78b12
|
402 403 |
struct device_node *np, const struct regulator_desc *desc) |
91f23d8fb
|
404 405 406 407 408 409 410 411 |
{ struct fan53555_platform_data *pdata; int ret; u32 tmp; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return NULL; |
072e78b12
|
412 |
pdata->regulator = of_get_regulator_init_data(dev, np, desc); |
91f23d8fb
|
413 414 415 416 417 418 419 420 |
ret = of_property_read_u32(np, "fcs,suspend-voltage-selector", &tmp); if (!ret) pdata->sleep_vsel_id = tmp; return pdata; } |
5e97d7e80
|
421 |
static const struct of_device_id __maybe_unused fan53555_dt_ids[] = { |
91f23d8fb
|
422 |
{ |
f2a9eb975
|
423 424 425 |
.compatible = "fcs,fan53526", .data = (void *)FAN53526_VENDOR_FAIRCHILD, }, { |
91f23d8fb
|
426 |
.compatible = "fcs,fan53555", |
ee30928ab
|
427 428 429 430 431 432 433 |
.data = (void *)FAN53555_VENDOR_FAIRCHILD }, { .compatible = "silergy,syr827", .data = (void *)FAN53555_VENDOR_SILERGY, }, { .compatible = "silergy,syr828", .data = (void *)FAN53555_VENDOR_SILERGY, |
91f23d8fb
|
434 435 436 437 |
}, { } }; MODULE_DEVICE_TABLE(of, fan53555_dt_ids); |
a5023574d
|
438 |
static int fan53555_regulator_probe(struct i2c_client *client, |
49d8c5992
|
439 440 |
const struct i2c_device_id *id) { |
91f23d8fb
|
441 |
struct device_node *np = client->dev.of_node; |
49d8c5992
|
442 443 444 |
struct fan53555_device_info *di; struct fan53555_platform_data *pdata; struct regulator_config config = { }; |
a69929c7a
|
445 |
struct regmap *regmap; |
49d8c5992
|
446 447 |
unsigned int val; int ret; |
072e78b12
|
448 449 450 451 |
di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info), GFP_KERNEL); if (!di) return -ENOMEM; |
dff91d0b7
|
452 |
pdata = dev_get_platdata(&client->dev); |
91f23d8fb
|
453 |
if (!pdata) |
072e78b12
|
454 |
pdata = fan53555_parse_dt(&client->dev, np, &di->desc); |
91f23d8fb
|
455 |
|
49d8c5992
|
456 457 458 459 460 |
if (!pdata || !pdata->regulator) { dev_err(&client->dev, "Platform data not found! "); return -ENODEV; } |
e13426bf2
|
461 |
di->regulator = pdata->regulator; |
ee30928ab
|
462 |
if (client->dev.of_node) { |
d110e3e92
|
463 464 |
di->vendor = (unsigned long)of_device_get_match_data(&client->dev); |
ee30928ab
|
465 |
} else { |
91f23d8fb
|
466 467 |
/* if no ramp constraint set, get the pdata ramp_delay */ if (!di->regulator->constraints.ramp_delay) { |
87919e0cf
|
468 469 470 471 472 |
if (pdata->slew_rate >= ARRAY_SIZE(slew_rates)) { dev_err(&client->dev, "Invalid slew_rate "); return -EINVAL; } |
dd7e71fbe
|
473 |
|
91f23d8fb
|
474 |
di->regulator->constraints.ramp_delay |
87919e0cf
|
475 |
= slew_rates[pdata->slew_rate]; |
91f23d8fb
|
476 |
} |
ee30928ab
|
477 478 |
di->vendor = id->driver_data; |
dd7e71fbe
|
479 |
} |
a69929c7a
|
480 481 |
regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config); if (IS_ERR(regmap)) { |
49d8c5992
|
482 483 |
dev_err(&client->dev, "Failed to allocate regmap! "); |
a69929c7a
|
484 |
return PTR_ERR(regmap); |
49d8c5992
|
485 486 |
} di->dev = &client->dev; |
49d8c5992
|
487 488 |
i2c_set_clientdata(client, di); /* Get chip ID */ |
a69929c7a
|
489 |
ret = regmap_read(regmap, FAN53555_ID1, &val); |
49d8c5992
|
490 491 492 |
if (ret < 0) { dev_err(&client->dev, "Failed to get chip ID! "); |
145fe1e1d
|
493 |
return ret; |
49d8c5992
|
494 495 496 |
} di->chip_id = val & DIE_ID; /* Get chip revision */ |
a69929c7a
|
497 |
ret = regmap_read(regmap, FAN53555_ID2, &val); |
49d8c5992
|
498 499 500 |
if (ret < 0) { dev_err(&client->dev, "Failed to get chip Rev! "); |
145fe1e1d
|
501 |
return ret; |
49d8c5992
|
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 |
} di->chip_rev = val & DIE_REV; dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected! ", di->chip_id, di->chip_rev); /* Device init */ ret = fan53555_device_setup(di, pdata); if (ret < 0) { dev_err(&client->dev, "Failed to setup device! "); return ret; } /* Register regulator */ config.dev = di->dev; config.init_data = di->regulator; |
a69929c7a
|
517 |
config.regmap = regmap; |
49d8c5992
|
518 |
config.driver_data = di; |
91f23d8fb
|
519 |
config.of_node = np; |
49d8c5992
|
520 521 522 523 524 525 526 |
ret = fan53555_regulator_register(di, &config); if (ret < 0) dev_err(&client->dev, "Failed to register regulator! "); return ret; } |
49d8c5992
|
527 |
static const struct i2c_device_id fan53555_id[] = { |
ee30928ab
|
528 |
{ |
f2a9eb975
|
529 530 531 |
.name = "fan53526", .driver_data = FAN53526_VENDOR_FAIRCHILD }, { |
ee30928ab
|
532 533 534 |
.name = "fan53555", .driver_data = FAN53555_VENDOR_FAIRCHILD }, { |
fc1111b88
|
535 536 537 538 |
.name = "syr827", .driver_data = FAN53555_VENDOR_SILERGY }, { .name = "syr828", |
ee30928ab
|
539 540 |
.driver_data = FAN53555_VENDOR_SILERGY }, |
49d8c5992
|
541 542 |
{ }, }; |
e80c47bd7
|
543 |
MODULE_DEVICE_TABLE(i2c, fan53555_id); |
49d8c5992
|
544 545 546 547 |
static struct i2c_driver fan53555_regulator_driver = { .driver = { .name = "fan53555-regulator", |
91f23d8fb
|
548 |
.of_match_table = of_match_ptr(fan53555_dt_ids), |
49d8c5992
|
549 550 |
}, .probe = fan53555_regulator_probe, |
49d8c5992
|
551 552 553 554 555 556 557 558 |
.id_table = fan53555_id, }; module_i2c_driver(fan53555_regulator_driver); MODULE_AUTHOR("Yunfan Zhang <yfzhang@marvell.com>"); MODULE_DESCRIPTION("FAN53555 regulator driver"); MODULE_LICENSE("GPL v2"); |