| .. | .. |
|---|
| 1 | | -/* |
|---|
| 2 | | - * Linear Technology LTC3589,LTC3589-1 regulator support |
|---|
| 3 | | - * |
|---|
| 4 | | - * Copyright (c) 2014 Philipp Zabel <p.zabel@pengutronix.de>, Pengutronix |
|---|
| 5 | | - * |
|---|
| 6 | | - * See file CREDITS for list of people who contributed to this |
|---|
| 7 | | - * project. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License version 2 |
|---|
| 11 | | - * as published by the Free Software Foundation. |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 16 | | - * GNU General Public License for more details. |
|---|
| 17 | | - * |
|---|
| 18 | | - */ |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 2 | +// |
|---|
| 3 | +// Linear Technology LTC3589,LTC3589-1 regulator support |
|---|
| 4 | +// |
|---|
| 5 | +// Copyright (c) 2014 Philipp Zabel <p.zabel@pengutronix.de>, Pengutronix |
|---|
| 6 | + |
|---|
| 19 | 7 | #include <linux/i2c.h> |
|---|
| 20 | 8 | #include <linux/init.h> |
|---|
| 21 | 9 | #include <linux/interrupt.h> |
|---|
| .. | .. |
|---|
| 84 | 72 | LTC3589_NUM_REGULATORS, |
|---|
| 85 | 73 | }; |
|---|
| 86 | 74 | |
|---|
| 87 | | -struct ltc3589_regulator { |
|---|
| 88 | | - struct regulator_desc desc; |
|---|
| 89 | | - |
|---|
| 90 | | - /* External feedback voltage divider */ |
|---|
| 91 | | - unsigned int r1; |
|---|
| 92 | | - unsigned int r2; |
|---|
| 93 | | -}; |
|---|
| 94 | | - |
|---|
| 95 | 75 | struct ltc3589 { |
|---|
| 96 | 76 | struct regmap *regmap; |
|---|
| 97 | 77 | struct device *dev; |
|---|
| 98 | 78 | enum ltc3589_variant variant; |
|---|
| 99 | | - struct ltc3589_regulator regulator_descs[LTC3589_NUM_REGULATORS]; |
|---|
| 79 | + struct regulator_desc regulator_descs[LTC3589_NUM_REGULATORS]; |
|---|
| 100 | 80 | struct regulator_dev *regulators[LTC3589_NUM_REGULATORS]; |
|---|
| 101 | 81 | }; |
|---|
| 102 | 82 | |
|---|
| .. | .. |
|---|
| 196 | 176 | .get_voltage_sel = regulator_get_voltage_sel_regmap, |
|---|
| 197 | 177 | }; |
|---|
| 198 | 178 | |
|---|
| 179 | +static inline unsigned int ltc3589_scale(unsigned int uV, u32 r1, u32 r2) |
|---|
| 180 | +{ |
|---|
| 181 | + uint64_t tmp; |
|---|
| 199 | 182 | |
|---|
| 200 | | -#define LTC3589_REG(_name, _ops, en_bit, dtv1_reg, dtv_mask, go_bit) \ |
|---|
| 201 | | - [LTC3589_ ## _name] = { \ |
|---|
| 202 | | - .desc = { \ |
|---|
| 203 | | - .name = #_name, \ |
|---|
| 204 | | - .n_voltages = (dtv_mask) + 1, \ |
|---|
| 205 | | - .min_uV = (go_bit) ? 362500 : 0, \ |
|---|
| 206 | | - .uV_step = (go_bit) ? 12500 : 0, \ |
|---|
| 207 | | - .ramp_delay = (go_bit) ? 1750 : 0, \ |
|---|
| 208 | | - .fixed_uV = (dtv_mask) ? 0 : 800000, \ |
|---|
| 209 | | - .ops = <c3589_ ## _ops ## _regulator_ops, \ |
|---|
| 210 | | - .type = REGULATOR_VOLTAGE, \ |
|---|
| 211 | | - .id = LTC3589_ ## _name, \ |
|---|
| 212 | | - .owner = THIS_MODULE, \ |
|---|
| 213 | | - .vsel_reg = (dtv1_reg), \ |
|---|
| 214 | | - .vsel_mask = (dtv_mask), \ |
|---|
| 215 | | - .apply_reg = (go_bit) ? LTC3589_VCCR : 0, \ |
|---|
| 216 | | - .apply_bit = (go_bit), \ |
|---|
| 217 | | - .enable_reg = (en_bit) ? LTC3589_OVEN : 0, \ |
|---|
| 218 | | - .enable_mask = (en_bit), \ |
|---|
| 219 | | - }, \ |
|---|
| 183 | + if (uV == 0) |
|---|
| 184 | + return 0; |
|---|
| 185 | + |
|---|
| 186 | + tmp = (uint64_t)uV * r1; |
|---|
| 187 | + do_div(tmp, r2); |
|---|
| 188 | + return uV + (unsigned int)tmp; |
|---|
| 189 | +} |
|---|
| 190 | + |
|---|
| 191 | +static int ltc3589_of_parse_cb(struct device_node *np, |
|---|
| 192 | + const struct regulator_desc *desc, |
|---|
| 193 | + struct regulator_config *config) |
|---|
| 194 | +{ |
|---|
| 195 | + struct ltc3589 *ltc3589 = config->driver_data; |
|---|
| 196 | + struct regulator_desc *rdesc = <c3589->regulator_descs[desc->id]; |
|---|
| 197 | + u32 r[2]; |
|---|
| 198 | + int ret; |
|---|
| 199 | + |
|---|
| 200 | + /* Parse feedback voltage dividers. LDO3 and LDO4 don't have them */ |
|---|
| 201 | + if (desc->id >= LTC3589_LDO3) |
|---|
| 202 | + return 0; |
|---|
| 203 | + |
|---|
| 204 | + ret = of_property_read_u32_array(np, "lltc,fb-voltage-divider", r, 2); |
|---|
| 205 | + if (ret) { |
|---|
| 206 | + dev_err(ltc3589->dev, "Failed to parse voltage divider: %d\n", |
|---|
| 207 | + ret); |
|---|
| 208 | + return ret; |
|---|
| 220 | 209 | } |
|---|
| 221 | 210 | |
|---|
| 222 | | -#define LTC3589_LINEAR_REG(_name, _dtv1) \ |
|---|
| 223 | | - LTC3589_REG(_name, linear, LTC3589_OVEN_ ## _name, \ |
|---|
| 211 | + if (!r[0] || !r[1]) |
|---|
| 212 | + return 0; |
|---|
| 213 | + |
|---|
| 214 | + rdesc->min_uV = ltc3589_scale(desc->min_uV, r[0], r[1]); |
|---|
| 215 | + rdesc->uV_step = ltc3589_scale(desc->uV_step, r[0], r[1]); |
|---|
| 216 | + rdesc->fixed_uV = ltc3589_scale(desc->fixed_uV, r[0], r[1]); |
|---|
| 217 | + |
|---|
| 218 | + return 0; |
|---|
| 219 | +} |
|---|
| 220 | + |
|---|
| 221 | +#define LTC3589_REG(_name, _of_name, _ops, en_bit, dtv1_reg, dtv_mask, go_bit)\ |
|---|
| 222 | + [LTC3589_ ## _name] = { \ |
|---|
| 223 | + .name = #_name, \ |
|---|
| 224 | + .of_match = of_match_ptr(#_of_name), \ |
|---|
| 225 | + .regulators_node = of_match_ptr("regulators"), \ |
|---|
| 226 | + .of_parse_cb = ltc3589_of_parse_cb, \ |
|---|
| 227 | + .n_voltages = (dtv_mask) + 1, \ |
|---|
| 228 | + .min_uV = (go_bit) ? 362500 : 0, \ |
|---|
| 229 | + .uV_step = (go_bit) ? 12500 : 0, \ |
|---|
| 230 | + .ramp_delay = (go_bit) ? 1750 : 0, \ |
|---|
| 231 | + .fixed_uV = (dtv_mask) ? 0 : 800000, \ |
|---|
| 232 | + .ops = <c3589_ ## _ops ## _regulator_ops, \ |
|---|
| 233 | + .type = REGULATOR_VOLTAGE, \ |
|---|
| 234 | + .id = LTC3589_ ## _name, \ |
|---|
| 235 | + .owner = THIS_MODULE, \ |
|---|
| 236 | + .vsel_reg = (dtv1_reg), \ |
|---|
| 237 | + .vsel_mask = (dtv_mask), \ |
|---|
| 238 | + .apply_reg = (go_bit) ? LTC3589_VCCR : 0, \ |
|---|
| 239 | + .apply_bit = (go_bit), \ |
|---|
| 240 | + .enable_reg = (en_bit) ? LTC3589_OVEN : 0, \ |
|---|
| 241 | + .enable_mask = (en_bit), \ |
|---|
| 242 | + } |
|---|
| 243 | + |
|---|
| 244 | +#define LTC3589_LINEAR_REG(_name, _of_name, _dtv1) \ |
|---|
| 245 | + LTC3589_REG(_name, _of_name, linear, LTC3589_OVEN_ ## _name, \ |
|---|
| 224 | 246 | LTC3589_ ## _dtv1, 0x1f, \ |
|---|
| 225 | 247 | LTC3589_VCCR_ ## _name ## _GO) |
|---|
| 226 | 248 | |
|---|
| 227 | | -#define LTC3589_FIXED_REG(_name) \ |
|---|
| 228 | | - LTC3589_REG(_name, fixed, LTC3589_OVEN_ ## _name, 0, 0, 0) |
|---|
| 249 | +#define LTC3589_FIXED_REG(_name, _of_name) \ |
|---|
| 250 | + LTC3589_REG(_name, _of_name, fixed, LTC3589_OVEN_ ## _name, 0, 0, 0) |
|---|
| 229 | 251 | |
|---|
| 230 | | -static struct ltc3589_regulator ltc3589_regulators[LTC3589_NUM_REGULATORS] = { |
|---|
| 231 | | - LTC3589_LINEAR_REG(SW1, B1DTV1), |
|---|
| 232 | | - LTC3589_LINEAR_REG(SW2, B2DTV1), |
|---|
| 233 | | - LTC3589_LINEAR_REG(SW3, B3DTV1), |
|---|
| 234 | | - LTC3589_FIXED_REG(BB_OUT), |
|---|
| 235 | | - LTC3589_REG(LDO1, fixed_standby, 0, 0, 0, 0), |
|---|
| 236 | | - LTC3589_LINEAR_REG(LDO2, L2DTV1), |
|---|
| 237 | | - LTC3589_FIXED_REG(LDO3), |
|---|
| 238 | | - LTC3589_REG(LDO4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2, 0x60, 0), |
|---|
| 252 | +static const struct regulator_desc ltc3589_regulators[] = { |
|---|
| 253 | + LTC3589_LINEAR_REG(SW1, sw1, B1DTV1), |
|---|
| 254 | + LTC3589_LINEAR_REG(SW2, sw2, B2DTV1), |
|---|
| 255 | + LTC3589_LINEAR_REG(SW3, sw3, B3DTV1), |
|---|
| 256 | + LTC3589_FIXED_REG(BB_OUT, bb-out), |
|---|
| 257 | + LTC3589_REG(LDO1, ldo1, fixed_standby, 0, 0, 0, 0), |
|---|
| 258 | + LTC3589_LINEAR_REG(LDO2, ldo2, L2DTV1), |
|---|
| 259 | + LTC3589_FIXED_REG(LDO3, ldo3), |
|---|
| 260 | + LTC3589_REG(LDO4, ldo4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2, |
|---|
| 261 | + 0x60, 0), |
|---|
| 239 | 262 | }; |
|---|
| 240 | | - |
|---|
| 241 | | -#ifdef CONFIG_OF |
|---|
| 242 | | -static struct of_regulator_match ltc3589_matches[LTC3589_NUM_REGULATORS] = { |
|---|
| 243 | | - { .name = "sw1", }, |
|---|
| 244 | | - { .name = "sw2", }, |
|---|
| 245 | | - { .name = "sw3", }, |
|---|
| 246 | | - { .name = "bb-out", }, |
|---|
| 247 | | - { .name = "ldo1", }, /* standby */ |
|---|
| 248 | | - { .name = "ldo2", }, |
|---|
| 249 | | - { .name = "ldo3", }, |
|---|
| 250 | | - { .name = "ldo4", }, |
|---|
| 251 | | -}; |
|---|
| 252 | | - |
|---|
| 253 | | -static int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589) |
|---|
| 254 | | -{ |
|---|
| 255 | | - struct device *dev = ltc3589->dev; |
|---|
| 256 | | - struct device_node *node; |
|---|
| 257 | | - int i, ret; |
|---|
| 258 | | - |
|---|
| 259 | | - node = of_get_child_by_name(dev->of_node, "regulators"); |
|---|
| 260 | | - if (!node) { |
|---|
| 261 | | - dev_err(dev, "regulators node not found\n"); |
|---|
| 262 | | - return -EINVAL; |
|---|
| 263 | | - } |
|---|
| 264 | | - |
|---|
| 265 | | - ret = of_regulator_match(dev, node, ltc3589_matches, |
|---|
| 266 | | - ARRAY_SIZE(ltc3589_matches)); |
|---|
| 267 | | - of_node_put(node); |
|---|
| 268 | | - if (ret < 0) { |
|---|
| 269 | | - dev_err(dev, "Error parsing regulator init data: %d\n", ret); |
|---|
| 270 | | - return ret; |
|---|
| 271 | | - } |
|---|
| 272 | | - if (ret != LTC3589_NUM_REGULATORS) { |
|---|
| 273 | | - dev_err(dev, "Only %d regulators described in device tree\n", |
|---|
| 274 | | - ret); |
|---|
| 275 | | - return -EINVAL; |
|---|
| 276 | | - } |
|---|
| 277 | | - |
|---|
| 278 | | - /* Parse feedback voltage dividers. LDO3 and LDO4 don't have them */ |
|---|
| 279 | | - for (i = 0; i < LTC3589_LDO3; i++) { |
|---|
| 280 | | - struct ltc3589_regulator *desc = <c3589->regulator_descs[i]; |
|---|
| 281 | | - struct device_node *np = ltc3589_matches[i].of_node; |
|---|
| 282 | | - u32 vdiv[2]; |
|---|
| 283 | | - |
|---|
| 284 | | - ret = of_property_read_u32_array(np, "lltc,fb-voltage-divider", |
|---|
| 285 | | - vdiv, 2); |
|---|
| 286 | | - if (ret) { |
|---|
| 287 | | - dev_err(dev, "Failed to parse voltage divider: %d\n", |
|---|
| 288 | | - ret); |
|---|
| 289 | | - return ret; |
|---|
| 290 | | - } |
|---|
| 291 | | - |
|---|
| 292 | | - desc->r1 = vdiv[0]; |
|---|
| 293 | | - desc->r2 = vdiv[1]; |
|---|
| 294 | | - } |
|---|
| 295 | | - |
|---|
| 296 | | - return 0; |
|---|
| 297 | | -} |
|---|
| 298 | | - |
|---|
| 299 | | -static inline struct regulator_init_data *match_init_data(int index) |
|---|
| 300 | | -{ |
|---|
| 301 | | - return ltc3589_matches[index].init_data; |
|---|
| 302 | | -} |
|---|
| 303 | | - |
|---|
| 304 | | -static inline struct device_node *match_of_node(int index) |
|---|
| 305 | | -{ |
|---|
| 306 | | - return ltc3589_matches[index].of_node; |
|---|
| 307 | | -} |
|---|
| 308 | | -#else |
|---|
| 309 | | -static inline int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589) |
|---|
| 310 | | -{ |
|---|
| 311 | | - return 0; |
|---|
| 312 | | -} |
|---|
| 313 | | - |
|---|
| 314 | | -static inline struct regulator_init_data *match_init_data(int index) |
|---|
| 315 | | -{ |
|---|
| 316 | | - return NULL; |
|---|
| 317 | | -} |
|---|
| 318 | | - |
|---|
| 319 | | -static inline struct device_node *match_of_node(int index) |
|---|
| 320 | | -{ |
|---|
| 321 | | - return NULL; |
|---|
| 322 | | -} |
|---|
| 323 | | -#endif |
|---|
| 324 | 263 | |
|---|
| 325 | 264 | static bool ltc3589_writeable_reg(struct device *dev, unsigned int reg) |
|---|
| 326 | 265 | { |
|---|
| .. | .. |
|---|
| 404 | 343 | .max_register = LTC3589_L2DTV2, |
|---|
| 405 | 344 | .reg_defaults = ltc3589_reg_defaults, |
|---|
| 406 | 345 | .num_reg_defaults = ARRAY_SIZE(ltc3589_reg_defaults), |
|---|
| 407 | | - .use_single_rw = true, |
|---|
| 346 | + .use_single_read = true, |
|---|
| 347 | + .use_single_write = true, |
|---|
| 408 | 348 | .cache_type = REGCACHE_RBTREE, |
|---|
| 409 | 349 | }; |
|---|
| 410 | | - |
|---|
| 411 | 350 | |
|---|
| 412 | 351 | static irqreturn_t ltc3589_isr(int irq, void *dev_id) |
|---|
| 413 | 352 | { |
|---|
| .. | .. |
|---|
| 436 | 375 | return IRQ_HANDLED; |
|---|
| 437 | 376 | } |
|---|
| 438 | 377 | |
|---|
| 439 | | -static inline unsigned int ltc3589_scale(unsigned int uV, u32 r1, u32 r2) |
|---|
| 440 | | -{ |
|---|
| 441 | | - uint64_t tmp; |
|---|
| 442 | | - if (uV == 0) |
|---|
| 443 | | - return 0; |
|---|
| 444 | | - tmp = (uint64_t)uV * r1; |
|---|
| 445 | | - do_div(tmp, r2); |
|---|
| 446 | | - return uV + (unsigned int)tmp; |
|---|
| 447 | | -} |
|---|
| 448 | | - |
|---|
| 449 | | -static void ltc3589_apply_fb_voltage_divider(struct ltc3589_regulator *rdesc) |
|---|
| 450 | | -{ |
|---|
| 451 | | - struct regulator_desc *desc = &rdesc->desc; |
|---|
| 452 | | - |
|---|
| 453 | | - if (!rdesc->r1 || !rdesc->r2) |
|---|
| 454 | | - return; |
|---|
| 455 | | - |
|---|
| 456 | | - desc->min_uV = ltc3589_scale(desc->min_uV, rdesc->r1, rdesc->r2); |
|---|
| 457 | | - desc->uV_step = ltc3589_scale(desc->uV_step, rdesc->r1, rdesc->r2); |
|---|
| 458 | | - desc->fixed_uV = ltc3589_scale(desc->fixed_uV, rdesc->r1, rdesc->r2); |
|---|
| 459 | | -} |
|---|
| 460 | | - |
|---|
| 461 | 378 | static int ltc3589_probe(struct i2c_client *client, |
|---|
| 462 | 379 | const struct i2c_device_id *id) |
|---|
| 463 | 380 | { |
|---|
| 464 | 381 | struct device *dev = &client->dev; |
|---|
| 465 | | - struct ltc3589_regulator *descs; |
|---|
| 382 | + struct regulator_desc *descs; |
|---|
| 466 | 383 | struct ltc3589 *ltc3589; |
|---|
| 467 | 384 | int i, ret; |
|---|
| 468 | 385 | |
|---|
| .. | .. |
|---|
| 481 | 398 | descs = ltc3589->regulator_descs; |
|---|
| 482 | 399 | memcpy(descs, ltc3589_regulators, sizeof(ltc3589_regulators)); |
|---|
| 483 | 400 | if (ltc3589->variant == LTC3589) { |
|---|
| 484 | | - descs[LTC3589_LDO3].desc.fixed_uV = 1800000; |
|---|
| 485 | | - descs[LTC3589_LDO4].desc.volt_table = ltc3589_ldo4; |
|---|
| 401 | + descs[LTC3589_LDO3].fixed_uV = 1800000; |
|---|
| 402 | + descs[LTC3589_LDO4].volt_table = ltc3589_ldo4; |
|---|
| 486 | 403 | } else { |
|---|
| 487 | | - descs[LTC3589_LDO3].desc.fixed_uV = 2800000; |
|---|
| 488 | | - descs[LTC3589_LDO4].desc.volt_table = ltc3589_12_ldo4; |
|---|
| 404 | + descs[LTC3589_LDO3].fixed_uV = 2800000; |
|---|
| 405 | + descs[LTC3589_LDO4].volt_table = ltc3589_12_ldo4; |
|---|
| 489 | 406 | } |
|---|
| 490 | 407 | |
|---|
| 491 | 408 | ltc3589->regmap = devm_regmap_init_i2c(client, <c3589_regmap_config); |
|---|
| .. | .. |
|---|
| 495 | 412 | return ret; |
|---|
| 496 | 413 | } |
|---|
| 497 | 414 | |
|---|
| 498 | | - ret = ltc3589_parse_regulators_dt(ltc3589); |
|---|
| 499 | | - if (ret) |
|---|
| 500 | | - return ret; |
|---|
| 501 | | - |
|---|
| 502 | 415 | for (i = 0; i < LTC3589_NUM_REGULATORS; i++) { |
|---|
| 503 | | - struct ltc3589_regulator *rdesc = <c3589->regulator_descs[i]; |
|---|
| 504 | | - struct regulator_desc *desc = &rdesc->desc; |
|---|
| 505 | | - struct regulator_init_data *init_data; |
|---|
| 416 | + struct regulator_desc *desc = <c3589->regulator_descs[i]; |
|---|
| 506 | 417 | struct regulator_config config = { }; |
|---|
| 507 | 418 | |
|---|
| 508 | | - init_data = match_init_data(i); |
|---|
| 509 | | - |
|---|
| 510 | | - if (i < LTC3589_LDO3) |
|---|
| 511 | | - ltc3589_apply_fb_voltage_divider(rdesc); |
|---|
| 512 | | - |
|---|
| 513 | 419 | config.dev = dev; |
|---|
| 514 | | - config.init_data = init_data; |
|---|
| 515 | 420 | config.driver_data = ltc3589; |
|---|
| 516 | | - config.of_node = match_of_node(i); |
|---|
| 517 | 421 | |
|---|
| 518 | 422 | ltc3589->regulators[i] = devm_regulator_register(dev, desc, |
|---|
| 519 | 423 | &config); |
|---|
| .. | .. |
|---|
| 547 | 451 | }; |
|---|
| 548 | 452 | MODULE_DEVICE_TABLE(i2c, ltc3589_i2c_id); |
|---|
| 549 | 453 | |
|---|
| 550 | | -static const struct of_device_id ltc3589_of_match[] = { |
|---|
| 454 | +static const struct of_device_id __maybe_unused ltc3589_of_match[] = { |
|---|
| 551 | 455 | { |
|---|
| 552 | 456 | .compatible = "lltc,ltc3589", |
|---|
| 553 | 457 | .data = (void *)LTC3589, |
|---|