548 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// pv88080-regulator.c - Regulator device driver for PV880804// Copyright (C) 2016 Powerventure Semiconductor Ltd.5 6#include <linux/err.h>7#include <linux/i2c.h>8#include <linux/mod_devicetable.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/init.h>12#include <linux/slab.h>13#include <linux/regulator/driver.h>14#include <linux/regulator/machine.h>15#include <linux/regmap.h>16#include <linux/irq.h>17#include <linux/interrupt.h>18#include <linux/regulator/of_regulator.h>19#include "pv88080-regulator.h"20 21#define PV88080_MAX_REGULATORS 422 23/* PV88080 REGULATOR IDs */24enum {25 /* BUCKs */26 PV88080_ID_BUCK1,27 PV88080_ID_BUCK2,28 PV88080_ID_BUCK3,29 PV88080_ID_HVBUCK,30};31 32struct pv88080_regulator {33 struct regulator_desc desc;34 unsigned int mode_reg;35 unsigned int conf2;36 unsigned int conf5;37};38 39struct pv88080 {40 struct device *dev;41 struct regmap *regmap;42 struct regulator_dev *rdev[PV88080_MAX_REGULATORS];43 unsigned long type;44 const struct pv88080_compatible_regmap *regmap_config;45};46 47struct pv88080_buck_voltage {48 int min_uV;49 int max_uV;50 int uV_step;51};52 53struct pv88080_buck_regmap {54 /* REGS */55 int buck_enable_reg;56 int buck_vsel_reg;57 int buck_mode_reg;58 int buck_limit_reg;59 int buck_vdac_range_reg;60 int buck_vrange_gain_reg;61 /* MASKS */62 int buck_enable_mask;63 int buck_vsel_mask;64 int buck_limit_mask;65};66 67struct pv88080_compatible_regmap {68 /* BUCK1, 2, 3 */69 struct pv88080_buck_regmap buck_regmap[PV88080_MAX_REGULATORS-1];70 /* HVBUCK */71 int hvbuck_enable_reg;72 int hvbuck_vsel_reg;73 int hvbuck_enable_mask;74 int hvbuck_vsel_mask;75};76 77static const struct regmap_config pv88080_regmap_config = {78 .reg_bits = 8,79 .val_bits = 8,80};81 82/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.83 * Entry indexes corresponds to register values.84 */85 86static const unsigned int pv88080_buck1_limits[] = {87 3230000, 5130000, 6960000, 879000088};89 90static const unsigned int pv88080_buck23_limits[] = {91 1496000, 2393000, 3291000, 418900092};93 94static const struct pv88080_buck_voltage pv88080_buck_vol[2] = {95 {96 .min_uV = 600000,97 .max_uV = 1393750,98 .uV_step = 6250,99 },100 {101 .min_uV = 1400000,102 .max_uV = 2193750,103 .uV_step = 6250,104 },105};106 107static const struct pv88080_compatible_regmap pv88080_aa_regs = {108 /* BUCK1 */109 .buck_regmap[0] = {110 .buck_enable_reg = PV88080AA_REG_BUCK1_CONF0,111 .buck_vsel_reg = PV88080AA_REG_BUCK1_CONF0,112 .buck_mode_reg = PV88080AA_REG_BUCK1_CONF1,113 .buck_limit_reg = PV88080AA_REG_BUCK1_CONF1,114 .buck_vdac_range_reg = PV88080AA_REG_BUCK1_CONF2,115 .buck_vrange_gain_reg = PV88080AA_REG_BUCK1_CONF5,116 .buck_enable_mask = PV88080_BUCK1_EN,117 .buck_vsel_mask = PV88080_VBUCK1_MASK,118 .buck_limit_mask = PV88080_BUCK1_ILIM_MASK,119 },120 /* BUCK2 */121 .buck_regmap[1] = {122 .buck_enable_reg = PV88080AA_REG_BUCK2_CONF0,123 .buck_vsel_reg = PV88080AA_REG_BUCK2_CONF0,124 .buck_mode_reg = PV88080AA_REG_BUCK2_CONF1,125 .buck_limit_reg = PV88080AA_REG_BUCK2_CONF1,126 .buck_vdac_range_reg = PV88080AA_REG_BUCK2_CONF2,127 .buck_vrange_gain_reg = PV88080AA_REG_BUCK2_CONF5,128 .buck_enable_mask = PV88080_BUCK2_EN,129 .buck_vsel_mask = PV88080_VBUCK2_MASK,130 .buck_limit_mask = PV88080_BUCK2_ILIM_MASK,131 },132 /* BUCK3 */133 .buck_regmap[2] = {134 .buck_enable_reg = PV88080AA_REG_BUCK3_CONF0,135 .buck_vsel_reg = PV88080AA_REG_BUCK3_CONF0,136 .buck_mode_reg = PV88080AA_REG_BUCK3_CONF1,137 .buck_limit_reg = PV88080AA_REG_BUCK3_CONF1,138 .buck_vdac_range_reg = PV88080AA_REG_BUCK3_CONF2,139 .buck_vrange_gain_reg = PV88080AA_REG_BUCK3_CONF5,140 .buck_enable_mask = PV88080_BUCK3_EN,141 .buck_vsel_mask = PV88080_VBUCK3_MASK,142 .buck_limit_mask = PV88080_BUCK3_ILIM_MASK,143 },144 /* HVBUCK */145 .hvbuck_enable_reg = PV88080AA_REG_HVBUCK_CONF2,146 .hvbuck_vsel_reg = PV88080AA_REG_HVBUCK_CONF1,147 .hvbuck_enable_mask = PV88080_HVBUCK_EN,148 .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK,149};150 151static const struct pv88080_compatible_regmap pv88080_ba_regs = {152 /* BUCK1 */153 .buck_regmap[0] = {154 .buck_enable_reg = PV88080BA_REG_BUCK1_CONF0,155 .buck_vsel_reg = PV88080BA_REG_BUCK1_CONF0,156 .buck_mode_reg = PV88080BA_REG_BUCK1_CONF1,157 .buck_limit_reg = PV88080BA_REG_BUCK1_CONF1,158 .buck_vdac_range_reg = PV88080BA_REG_BUCK1_CONF2,159 .buck_vrange_gain_reg = PV88080BA_REG_BUCK1_CONF5,160 .buck_enable_mask = PV88080_BUCK1_EN,161 .buck_vsel_mask = PV88080_VBUCK1_MASK,162 .buck_limit_mask = PV88080_BUCK1_ILIM_MASK,163 },164 /* BUCK2 */165 .buck_regmap[1] = {166 .buck_enable_reg = PV88080BA_REG_BUCK2_CONF0,167 .buck_vsel_reg = PV88080BA_REG_BUCK2_CONF0,168 .buck_mode_reg = PV88080BA_REG_BUCK2_CONF1,169 .buck_limit_reg = PV88080BA_REG_BUCK2_CONF1,170 .buck_vdac_range_reg = PV88080BA_REG_BUCK2_CONF2,171 .buck_vrange_gain_reg = PV88080BA_REG_BUCK2_CONF5,172 .buck_enable_mask = PV88080_BUCK2_EN,173 .buck_vsel_mask = PV88080_VBUCK2_MASK,174 .buck_limit_mask = PV88080_BUCK2_ILIM_MASK,175 },176 /* BUCK3 */177 .buck_regmap[2] = {178 .buck_enable_reg = PV88080BA_REG_BUCK3_CONF0,179 .buck_vsel_reg = PV88080BA_REG_BUCK3_CONF0,180 .buck_mode_reg = PV88080BA_REG_BUCK3_CONF1,181 .buck_limit_reg = PV88080BA_REG_BUCK3_CONF1,182 .buck_vdac_range_reg = PV88080BA_REG_BUCK3_CONF2,183 .buck_vrange_gain_reg = PV88080BA_REG_BUCK3_CONF5,184 .buck_enable_mask = PV88080_BUCK3_EN,185 .buck_vsel_mask = PV88080_VBUCK3_MASK,186 .buck_limit_mask = PV88080_BUCK3_ILIM_MASK,187 },188 /* HVBUCK */189 .hvbuck_enable_reg = PV88080BA_REG_HVBUCK_CONF2,190 .hvbuck_vsel_reg = PV88080BA_REG_HVBUCK_CONF1,191 .hvbuck_enable_mask = PV88080_HVBUCK_EN,192 .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK,193};194 195static unsigned int pv88080_buck_get_mode(struct regulator_dev *rdev)196{197 struct pv88080_regulator *info = rdev_get_drvdata(rdev);198 unsigned int data;199 int ret, mode = 0;200 201 ret = regmap_read(rdev->regmap, info->mode_reg, &data);202 if (ret < 0)203 return ret;204 205 switch (data & PV88080_BUCK1_MODE_MASK) {206 case PV88080_BUCK_MODE_SYNC:207 mode = REGULATOR_MODE_FAST;208 break;209 case PV88080_BUCK_MODE_AUTO:210 mode = REGULATOR_MODE_NORMAL;211 break;212 case PV88080_BUCK_MODE_SLEEP:213 mode = REGULATOR_MODE_STANDBY;214 break;215 default:216 return -EINVAL;217 }218 219 return mode;220}221 222static int pv88080_buck_set_mode(struct regulator_dev *rdev,223 unsigned int mode)224{225 struct pv88080_regulator *info = rdev_get_drvdata(rdev);226 int val = 0;227 228 switch (mode) {229 case REGULATOR_MODE_FAST:230 val = PV88080_BUCK_MODE_SYNC;231 break;232 case REGULATOR_MODE_NORMAL:233 val = PV88080_BUCK_MODE_AUTO;234 break;235 case REGULATOR_MODE_STANDBY:236 val = PV88080_BUCK_MODE_SLEEP;237 break;238 default:239 return -EINVAL;240 }241 242 return regmap_update_bits(rdev->regmap, info->mode_reg,243 PV88080_BUCK1_MODE_MASK, val);244}245 246static const struct regulator_ops pv88080_buck_ops = {247 .get_mode = pv88080_buck_get_mode,248 .set_mode = pv88080_buck_set_mode,249 .enable = regulator_enable_regmap,250 .disable = regulator_disable_regmap,251 .is_enabled = regulator_is_enabled_regmap,252 .set_voltage_sel = regulator_set_voltage_sel_regmap,253 .get_voltage_sel = regulator_get_voltage_sel_regmap,254 .list_voltage = regulator_list_voltage_linear,255 .set_current_limit = regulator_set_current_limit_regmap,256 .get_current_limit = regulator_get_current_limit_regmap,257};258 259static const struct regulator_ops pv88080_hvbuck_ops = {260 .enable = regulator_enable_regmap,261 .disable = regulator_disable_regmap,262 .is_enabled = regulator_is_enabled_regmap,263 .set_voltage_sel = regulator_set_voltage_sel_regmap,264 .get_voltage_sel = regulator_get_voltage_sel_regmap,265 .list_voltage = regulator_list_voltage_linear,266};267 268#define PV88080_BUCK(chip, regl_name, min, step, max, limits_array) \269{\270 .desc = {\271 .id = chip##_ID_##regl_name,\272 .name = __stringify(chip##_##regl_name),\273 .of_match = of_match_ptr(#regl_name),\274 .regulators_node = of_match_ptr("regulators"),\275 .type = REGULATOR_VOLTAGE,\276 .owner = THIS_MODULE,\277 .ops = &pv88080_buck_ops,\278 .min_uV = min, \279 .uV_step = step, \280 .n_voltages = ((max) - (min))/(step) + 1, \281 .curr_table = limits_array, \282 .n_current_limits = ARRAY_SIZE(limits_array), \283 },\284}285 286#define PV88080_HVBUCK(chip, regl_name, min, step, max) \287{\288 .desc = {\289 .id = chip##_ID_##regl_name,\290 .name = __stringify(chip##_##regl_name),\291 .of_match = of_match_ptr(#regl_name),\292 .regulators_node = of_match_ptr("regulators"),\293 .type = REGULATOR_VOLTAGE,\294 .owner = THIS_MODULE,\295 .ops = &pv88080_hvbuck_ops,\296 .min_uV = min, \297 .uV_step = step, \298 .n_voltages = ((max) - (min))/(step) + 1, \299 },\300}301 302static struct pv88080_regulator pv88080_regulator_info[] = {303 PV88080_BUCK(PV88080, BUCK1, 600000, 6250, 1393750,304 pv88080_buck1_limits),305 PV88080_BUCK(PV88080, BUCK2, 600000, 6250, 1393750,306 pv88080_buck23_limits),307 PV88080_BUCK(PV88080, BUCK3, 600000, 6250, 1393750,308 pv88080_buck23_limits),309 PV88080_HVBUCK(PV88080, HVBUCK, 0, 5000, 1275000),310};311 312static irqreturn_t pv88080_irq_handler(int irq, void *data)313{314 struct pv88080 *chip = data;315 int i, reg_val, err, ret = IRQ_NONE;316 317 err = regmap_read(chip->regmap, PV88080_REG_EVENT_A, ®_val);318 if (err < 0)319 goto error_i2c;320 321 if (reg_val & PV88080_E_VDD_FLT) {322 for (i = 0; i < PV88080_MAX_REGULATORS; i++) {323 if (chip->rdev[i] != NULL)324 regulator_notifier_call_chain(chip->rdev[i],325 REGULATOR_EVENT_UNDER_VOLTAGE,326 NULL);327 }328 329 err = regmap_write(chip->regmap, PV88080_REG_EVENT_A,330 PV88080_E_VDD_FLT);331 if (err < 0)332 goto error_i2c;333 334 ret = IRQ_HANDLED;335 }336 337 if (reg_val & PV88080_E_OVER_TEMP) {338 for (i = 0; i < PV88080_MAX_REGULATORS; i++) {339 if (chip->rdev[i] != NULL)340 regulator_notifier_call_chain(chip->rdev[i],341 REGULATOR_EVENT_OVER_TEMP,342 NULL);343 }344 345 err = regmap_write(chip->regmap, PV88080_REG_EVENT_A,346 PV88080_E_OVER_TEMP);347 if (err < 0)348 goto error_i2c;349 350 ret = IRQ_HANDLED;351 }352 353 return ret;354 355error_i2c:356 dev_err(chip->dev, "I2C error : %d\n", err);357 return IRQ_NONE;358}359 360/*361 * I2C driver interface functions362 */363static int pv88080_i2c_probe(struct i2c_client *i2c)364{365 struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);366 struct pv88080 *chip;367 const struct pv88080_compatible_regmap *regmap_config;368 struct regulator_config config = { };369 int i, error, ret;370 unsigned int conf2, conf5;371 372 chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88080), GFP_KERNEL);373 if (!chip)374 return -ENOMEM;375 376 chip->dev = &i2c->dev;377 chip->regmap = devm_regmap_init_i2c(i2c, &pv88080_regmap_config);378 if (IS_ERR(chip->regmap)) {379 error = PTR_ERR(chip->regmap);380 dev_err(chip->dev, "Failed to allocate register map: %d\n",381 error);382 return error;383 }384 385 chip->regmap_config = i2c_get_match_data(i2c);386 if (!chip->regmap_config)387 return -ENODEV;388 389 i2c_set_clientdata(i2c, chip);390 391 if (i2c->irq != 0) {392 ret = regmap_write(chip->regmap, PV88080_REG_MASK_A, 0xFF);393 if (ret < 0) {394 dev_err(chip->dev,395 "Failed to mask A reg: %d\n", ret);396 return ret;397 }398 ret = regmap_write(chip->regmap, PV88080_REG_MASK_B, 0xFF);399 if (ret < 0) {400 dev_err(chip->dev,401 "Failed to mask B reg: %d\n", ret);402 return ret;403 }404 ret = regmap_write(chip->regmap, PV88080_REG_MASK_C, 0xFF);405 if (ret < 0) {406 dev_err(chip->dev,407 "Failed to mask C reg: %d\n", ret);408 return ret;409 }410 411 ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,412 pv88080_irq_handler,413 IRQF_TRIGGER_LOW|IRQF_ONESHOT,414 "pv88080", chip);415 if (ret != 0) {416 dev_err(chip->dev, "Failed to request IRQ: %d\n",417 i2c->irq);418 return ret;419 }420 421 ret = regmap_update_bits(chip->regmap, PV88080_REG_MASK_A,422 PV88080_M_VDD_FLT | PV88080_M_OVER_TEMP, 0);423 if (ret < 0) {424 dev_err(chip->dev,425 "Failed to update mask reg: %d\n", ret);426 return ret;427 }428 } else {429 dev_warn(chip->dev, "No IRQ configured\n");430 }431 432 regmap_config = chip->regmap_config;433 config.dev = chip->dev;434 config.regmap = chip->regmap;435 436 /* Registeration for BUCK1, 2, 3 */437 for (i = 0; i < PV88080_MAX_REGULATORS-1; i++) {438 if (init_data)439 config.init_data = &init_data[i];440 441 pv88080_regulator_info[i].desc.csel_reg442 = regmap_config->buck_regmap[i].buck_limit_reg;443 pv88080_regulator_info[i].desc.csel_mask444 = regmap_config->buck_regmap[i].buck_limit_mask;445 pv88080_regulator_info[i].mode_reg446 = regmap_config->buck_regmap[i].buck_mode_reg;447 pv88080_regulator_info[i].conf2448 = regmap_config->buck_regmap[i].buck_vdac_range_reg;449 pv88080_regulator_info[i].conf5450 = regmap_config->buck_regmap[i].buck_vrange_gain_reg;451 pv88080_regulator_info[i].desc.enable_reg452 = regmap_config->buck_regmap[i].buck_enable_reg;453 pv88080_regulator_info[i].desc.enable_mask454 = regmap_config->buck_regmap[i].buck_enable_mask;455 pv88080_regulator_info[i].desc.vsel_reg456 = regmap_config->buck_regmap[i].buck_vsel_reg;457 pv88080_regulator_info[i].desc.vsel_mask458 = regmap_config->buck_regmap[i].buck_vsel_mask;459 460 ret = regmap_read(chip->regmap,461 pv88080_regulator_info[i].conf2, &conf2);462 if (ret < 0)463 return ret;464 conf2 = ((conf2 >> PV88080_BUCK_VDAC_RANGE_SHIFT) &465 PV88080_BUCK_VDAC_RANGE_MASK);466 467 ret = regmap_read(chip->regmap,468 pv88080_regulator_info[i].conf5, &conf5);469 if (ret < 0)470 return ret;471 conf5 = ((conf5 >> PV88080_BUCK_VRANGE_GAIN_SHIFT) &472 PV88080_BUCK_VRANGE_GAIN_MASK);473 474 pv88080_regulator_info[i].desc.min_uV =475 pv88080_buck_vol[conf2].min_uV * (conf5+1);476 pv88080_regulator_info[i].desc.uV_step =477 pv88080_buck_vol[conf2].uV_step * (conf5+1);478 pv88080_regulator_info[i].desc.n_voltages =479 ((pv88080_buck_vol[conf2].max_uV * (conf5+1))480 - (pv88080_regulator_info[i].desc.min_uV))481 /(pv88080_regulator_info[i].desc.uV_step) + 1;482 483 config.driver_data = (void *)&pv88080_regulator_info[i];484 chip->rdev[i] = devm_regulator_register(chip->dev,485 &pv88080_regulator_info[i].desc, &config);486 if (IS_ERR(chip->rdev[i])) {487 dev_err(chip->dev,488 "Failed to register PV88080 regulator\n");489 return PTR_ERR(chip->rdev[i]);490 }491 }492 493 pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_reg494 = regmap_config->hvbuck_enable_reg;495 pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_mask496 = regmap_config->hvbuck_enable_mask;497 pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_reg498 = regmap_config->hvbuck_vsel_reg;499 pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_mask500 = regmap_config->hvbuck_vsel_mask;501 502 /* Registeration for HVBUCK */503 if (init_data)504 config.init_data = &init_data[PV88080_ID_HVBUCK];505 506 config.driver_data = (void *)&pv88080_regulator_info[PV88080_ID_HVBUCK];507 chip->rdev[PV88080_ID_HVBUCK] = devm_regulator_register(chip->dev,508 &pv88080_regulator_info[PV88080_ID_HVBUCK].desc, &config);509 if (IS_ERR(chip->rdev[PV88080_ID_HVBUCK])) {510 dev_err(chip->dev, "Failed to register PV88080 regulator\n");511 return PTR_ERR(chip->rdev[PV88080_ID_HVBUCK]);512 }513 514 return 0;515}516 517static const struct of_device_id pv88080_dt_ids[] = {518 { .compatible = "pvs,pv88080", .data = &pv88080_aa_regs },519 { .compatible = "pvs,pv88080-aa", .data = &pv88080_aa_regs },520 { .compatible = "pvs,pv88080-ba", .data = &pv88080_ba_regs },521 {}522};523MODULE_DEVICE_TABLE(of, pv88080_dt_ids);524 525static const struct i2c_device_id pv88080_i2c_id[] = {526 { "pv88080", (kernel_ulong_t)&pv88080_aa_regs },527 { "pv88080-aa", (kernel_ulong_t)&pv88080_aa_regs },528 { "pv88080-ba", (kernel_ulong_t)&pv88080_ba_regs },529 {}530};531MODULE_DEVICE_TABLE(i2c, pv88080_i2c_id);532 533static struct i2c_driver pv88080_regulator_driver = {534 .driver = {535 .name = "pv88080",536 .probe_type = PROBE_PREFER_ASYNCHRONOUS,537 .of_match_table = pv88080_dt_ids,538 },539 .probe = pv88080_i2c_probe,540 .id_table = pv88080_i2c_id,541};542 543module_i2c_driver(pv88080_regulator_driver);544 545MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");546MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88080");547MODULE_LICENSE("GPL");548