542 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI LP8788 MFD - buck regulator driver4 *5 * Copyright 2012 Texas Instruments6 *7 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>8 */9 10#include <linux/module.h>11#include <linux/slab.h>12#include <linux/err.h>13#include <linux/platform_device.h>14#include <linux/regulator/driver.h>15#include <linux/mfd/lp8788.h>16#include <linux/gpio/consumer.h>17 18/* register address */19#define LP8788_EN_BUCK 0x0C20#define LP8788_BUCK_DVS_SEL 0x1D21#define LP8788_BUCK1_VOUT0 0x1E22#define LP8788_BUCK1_VOUT1 0x1F23#define LP8788_BUCK1_VOUT2 0x2024#define LP8788_BUCK1_VOUT3 0x2125#define LP8788_BUCK2_VOUT0 0x2226#define LP8788_BUCK2_VOUT1 0x2327#define LP8788_BUCK2_VOUT2 0x2428#define LP8788_BUCK2_VOUT3 0x2529#define LP8788_BUCK3_VOUT 0x2630#define LP8788_BUCK4_VOUT 0x2731#define LP8788_BUCK1_TIMESTEP 0x2832#define LP8788_BUCK_PWM 0x2D33 34/* mask/shift bits */35#define LP8788_EN_BUCK1_M BIT(0) /* Addr 0Ch */36#define LP8788_EN_BUCK2_M BIT(1)37#define LP8788_EN_BUCK3_M BIT(2)38#define LP8788_EN_BUCK4_M BIT(3)39#define LP8788_BUCK1_DVS_SEL_M 0x04 /* Addr 1Dh */40#define LP8788_BUCK1_DVS_M 0x0341#define LP8788_BUCK1_DVS_S 042#define LP8788_BUCK2_DVS_SEL_M 0x4043#define LP8788_BUCK2_DVS_M 0x3044#define LP8788_BUCK2_DVS_S 445#define LP8788_BUCK1_DVS_I2C BIT(2)46#define LP8788_BUCK2_DVS_I2C BIT(6)47#define LP8788_BUCK1_DVS_PIN (0 << 2)48#define LP8788_BUCK2_DVS_PIN (0 << 6)49#define LP8788_VOUT_M 0x1F /* Addr 1Eh ~ 27h */50#define LP8788_STARTUP_TIME_M 0xF8 /* Addr 28h ~ 2Bh */51#define LP8788_STARTUP_TIME_S 352#define LP8788_FPWM_BUCK1_M BIT(0) /* Addr 2Dh */53#define LP8788_FPWM_BUCK1_S 054#define LP8788_FPWM_BUCK2_M BIT(1)55#define LP8788_FPWM_BUCK2_S 156#define LP8788_FPWM_BUCK3_M BIT(2)57#define LP8788_FPWM_BUCK3_S 258#define LP8788_FPWM_BUCK4_M BIT(3)59#define LP8788_FPWM_BUCK4_S 360 61#define INVALID_ADDR 0xFF62#define LP8788_FORCE_PWM 163#define LP8788_AUTO_PWM 064#define PIN_LOW 065#define PIN_HIGH 166#define ENABLE_TIME_USEC 3267 68#define BUCK_FPWM_MASK(x) (1 << (x))69#define BUCK_FPWM_SHIFT(x) (x)70 71enum lp8788_dvs_state {72 DVS_LOW = 0,73 DVS_HIGH = 1,74};75 76enum lp8788_dvs_mode {77 REGISTER,78 EXTPIN,79};80 81enum lp8788_buck_id {82 BUCK1,83 BUCK2,84 BUCK3,85 BUCK4,86};87 88struct lp8788_buck {89 struct lp8788 *lp;90 struct regulator_dev *regulator;91 void *dvs;92 struct gpio_desc *gpio1;93 struct gpio_desc *gpio2; /* Only used on BUCK2 */94};95 96/* BUCK 1 ~ 4 voltage ranges */97static const struct linear_range buck_volt_ranges[] = {98 REGULATOR_LINEAR_RANGE(500000, 0, 0, 0),99 REGULATOR_LINEAR_RANGE(800000, 1, 25, 50000),100};101 102static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)103{104 struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;105 enum lp8788_dvs_state pinstate;106 107 if (!dvs)108 return;109 110 pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH;111 gpiod_set_value(buck->gpio1, pinstate);112}113 114static void lp8788_buck2_set_dvs(struct lp8788_buck *buck)115{116 struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs;117 enum lp8788_dvs_state pin1, pin2;118 119 if (!dvs)120 return;121 122 switch (dvs->vsel) {123 case DVS_SEL_V0:124 pin1 = DVS_LOW;125 pin2 = DVS_LOW;126 break;127 case DVS_SEL_V1:128 pin1 = DVS_HIGH;129 pin2 = DVS_LOW;130 break;131 case DVS_SEL_V2:132 pin1 = DVS_LOW;133 pin2 = DVS_HIGH;134 break;135 case DVS_SEL_V3:136 pin1 = DVS_HIGH;137 pin2 = DVS_HIGH;138 break;139 default:140 return;141 }142 143 gpiod_set_value(buck->gpio1, pin1);144 gpiod_set_value(buck->gpio2, pin2);145}146 147static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)148{149 switch (id) {150 case BUCK1:151 lp8788_buck1_set_dvs(buck);152 break;153 case BUCK2:154 lp8788_buck2_set_dvs(buck);155 break;156 default:157 break;158 }159}160 161static enum lp8788_dvs_mode162lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id)163{164 u8 val, mask;165 166 switch (id) {167 case BUCK1:168 mask = LP8788_BUCK1_DVS_SEL_M;169 break;170 case BUCK2:171 mask = LP8788_BUCK2_DVS_SEL_M;172 break;173 default:174 return REGISTER;175 }176 177 lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);178 179 return val & mask ? REGISTER : EXTPIN;180}181 182static bool lp8788_is_valid_buck_addr(u8 addr)183{184 switch (addr) {185 case LP8788_BUCK1_VOUT0:186 case LP8788_BUCK1_VOUT1:187 case LP8788_BUCK1_VOUT2:188 case LP8788_BUCK1_VOUT3:189 case LP8788_BUCK2_VOUT0:190 case LP8788_BUCK2_VOUT1:191 case LP8788_BUCK2_VOUT2:192 case LP8788_BUCK2_VOUT3:193 return true;194 default:195 return false;196 }197}198 199static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,200 enum lp8788_buck_id id)201{202 enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id);203 u8 val, idx, addr;204 int pin1, pin2;205 206 switch (id) {207 case BUCK1:208 if (mode == EXTPIN) {209 idx = gpiod_get_value(buck->gpio1);210 } else {211 lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);212 idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;213 }214 addr = LP8788_BUCK1_VOUT0 + idx;215 break;216 case BUCK2:217 if (mode == EXTPIN) {218 pin1 = gpiod_get_value(buck->gpio1);219 pin2 = gpiod_get_value(buck->gpio2);220 221 if (pin1 == PIN_LOW && pin2 == PIN_LOW)222 idx = 0;223 else if (pin1 == PIN_LOW && pin2 == PIN_HIGH)224 idx = 2;225 else if (pin1 == PIN_HIGH && pin2 == PIN_LOW)226 idx = 1;227 else228 idx = 3;229 } else {230 lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);231 idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;232 }233 addr = LP8788_BUCK2_VOUT0 + idx;234 break;235 default:236 goto err;237 }238 239 return addr;240err:241 return INVALID_ADDR;242}243 244static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev,245 unsigned selector)246{247 struct lp8788_buck *buck = rdev_get_drvdata(rdev);248 enum lp8788_buck_id id = rdev_get_id(rdev);249 u8 addr;250 251 if (buck->dvs)252 lp8788_set_dvs(buck, id);253 254 addr = lp8788_select_buck_vout_addr(buck, id);255 if (!lp8788_is_valid_buck_addr(addr))256 return -EINVAL;257 258 return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector);259}260 261static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev)262{263 struct lp8788_buck *buck = rdev_get_drvdata(rdev);264 enum lp8788_buck_id id = rdev_get_id(rdev);265 int ret;266 u8 val, addr;267 268 addr = lp8788_select_buck_vout_addr(buck, id);269 if (!lp8788_is_valid_buck_addr(addr))270 return -EINVAL;271 272 ret = lp8788_read_byte(buck->lp, addr, &val);273 if (ret)274 return ret;275 276 return val & LP8788_VOUT_M;277}278 279static int lp8788_buck_enable_time(struct regulator_dev *rdev)280{281 struct lp8788_buck *buck = rdev_get_drvdata(rdev);282 enum lp8788_buck_id id = rdev_get_id(rdev);283 u8 val, addr = LP8788_BUCK1_TIMESTEP + id;284 285 if (lp8788_read_byte(buck->lp, addr, &val))286 return -EINVAL;287 288 val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S;289 290 return ENABLE_TIME_USEC * val;291}292 293static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)294{295 struct lp8788_buck *buck = rdev_get_drvdata(rdev);296 enum lp8788_buck_id id = rdev_get_id(rdev);297 u8 mask, val;298 299 mask = BUCK_FPWM_MASK(id);300 switch (mode) {301 case REGULATOR_MODE_FAST:302 val = LP8788_FORCE_PWM << BUCK_FPWM_SHIFT(id);303 break;304 case REGULATOR_MODE_NORMAL:305 val = LP8788_AUTO_PWM << BUCK_FPWM_SHIFT(id);306 break;307 default:308 return -EINVAL;309 }310 311 return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, mask, val);312}313 314static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)315{316 struct lp8788_buck *buck = rdev_get_drvdata(rdev);317 enum lp8788_buck_id id = rdev_get_id(rdev);318 u8 val;319 int ret;320 321 ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val);322 if (ret)323 return ret;324 325 return val & BUCK_FPWM_MASK(id) ?326 REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;327}328 329static const struct regulator_ops lp8788_buck12_ops = {330 .list_voltage = regulator_list_voltage_linear_range,331 .map_voltage = regulator_map_voltage_linear_range,332 .set_voltage_sel = lp8788_buck12_set_voltage_sel,333 .get_voltage_sel = lp8788_buck12_get_voltage_sel,334 .enable = regulator_enable_regmap,335 .disable = regulator_disable_regmap,336 .is_enabled = regulator_is_enabled_regmap,337 .enable_time = lp8788_buck_enable_time,338 .set_mode = lp8788_buck_set_mode,339 .get_mode = lp8788_buck_get_mode,340};341 342static const struct regulator_ops lp8788_buck34_ops = {343 .list_voltage = regulator_list_voltage_linear_range,344 .map_voltage = regulator_map_voltage_linear_range,345 .set_voltage_sel = regulator_set_voltage_sel_regmap,346 .get_voltage_sel = regulator_get_voltage_sel_regmap,347 .enable = regulator_enable_regmap,348 .disable = regulator_disable_regmap,349 .is_enabled = regulator_is_enabled_regmap,350 .enable_time = lp8788_buck_enable_time,351 .set_mode = lp8788_buck_set_mode,352 .get_mode = lp8788_buck_get_mode,353};354 355static const struct regulator_desc lp8788_buck_desc[] = {356 {357 .name = "buck1",358 .id = BUCK1,359 .ops = &lp8788_buck12_ops,360 .n_voltages = 26,361 .linear_ranges = buck_volt_ranges,362 .n_linear_ranges = ARRAY_SIZE(buck_volt_ranges),363 .type = REGULATOR_VOLTAGE,364 .owner = THIS_MODULE,365 .enable_reg = LP8788_EN_BUCK,366 .enable_mask = LP8788_EN_BUCK1_M,367 },368 {369 .name = "buck2",370 .id = BUCK2,371 .ops = &lp8788_buck12_ops,372 .n_voltages = 26,373 .linear_ranges = buck_volt_ranges,374 .n_linear_ranges = ARRAY_SIZE(buck_volt_ranges),375 .type = REGULATOR_VOLTAGE,376 .owner = THIS_MODULE,377 .enable_reg = LP8788_EN_BUCK,378 .enable_mask = LP8788_EN_BUCK2_M,379 },380 {381 .name = "buck3",382 .id = BUCK3,383 .ops = &lp8788_buck34_ops,384 .n_voltages = 26,385 .linear_ranges = buck_volt_ranges,386 .n_linear_ranges = ARRAY_SIZE(buck_volt_ranges),387 .type = REGULATOR_VOLTAGE,388 .owner = THIS_MODULE,389 .vsel_reg = LP8788_BUCK3_VOUT,390 .vsel_mask = LP8788_VOUT_M,391 .enable_reg = LP8788_EN_BUCK,392 .enable_mask = LP8788_EN_BUCK3_M,393 },394 {395 .name = "buck4",396 .id = BUCK4,397 .ops = &lp8788_buck34_ops,398 .n_voltages = 26,399 .linear_ranges = buck_volt_ranges,400 .n_linear_ranges = ARRAY_SIZE(buck_volt_ranges),401 .type = REGULATOR_VOLTAGE,402 .owner = THIS_MODULE,403 .vsel_reg = LP8788_BUCK4_VOUT,404 .vsel_mask = LP8788_VOUT_M,405 .enable_reg = LP8788_EN_BUCK,406 .enable_mask = LP8788_EN_BUCK4_M,407 },408};409 410static int lp8788_dvs_gpio_request(struct platform_device *pdev,411 struct lp8788_buck *buck,412 enum lp8788_buck_id id)413{414 struct lp8788_platform_data *pdata = buck->lp->pdata;415 struct device *dev = &pdev->dev;416 417 switch (id) {418 case BUCK1:419 buck->gpio1 = devm_gpiod_get(dev, "dvs", GPIOD_OUT_LOW);420 if (IS_ERR(buck->gpio1))421 return PTR_ERR(buck->gpio1);422 gpiod_set_consumer_name(buck->gpio1, "LP8788_B1_DVS");423 424 buck->dvs = pdata->buck1_dvs;425 break;426 case BUCK2:427 buck->gpio1 = devm_gpiod_get_index(dev, "dvs", 0, GPIOD_OUT_LOW);428 if (IS_ERR(buck->gpio1))429 return PTR_ERR(buck->gpio1);430 gpiod_set_consumer_name(buck->gpio1, "LP8788_B2_DVS1");431 432 buck->gpio2 = devm_gpiod_get_index(dev, "dvs", 1, GPIOD_OUT_LOW);433 if (IS_ERR(buck->gpio2))434 return PTR_ERR(buck->gpio2);435 gpiod_set_consumer_name(buck->gpio2, "LP8788_B2_DVS2");436 437 buck->dvs = pdata->buck2_dvs;438 break;439 default:440 break;441 }442 443 return 0;444}445 446static int lp8788_init_dvs(struct platform_device *pdev,447 struct lp8788_buck *buck, enum lp8788_buck_id id)448{449 struct lp8788_platform_data *pdata = buck->lp->pdata;450 u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };451 u8 val[] = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN };452 u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };453 454 /* no dvs for buck3, 4 */455 if (id > BUCK2)456 return 0;457 458 /* no dvs platform data, then dvs will be selected by I2C registers */459 if (!pdata)460 goto set_default_dvs_mode;461 462 if ((id == BUCK1 && !pdata->buck1_dvs) ||463 (id == BUCK2 && !pdata->buck2_dvs))464 goto set_default_dvs_mode;465 466 if (lp8788_dvs_gpio_request(pdev, buck, id))467 goto set_default_dvs_mode;468 469 return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],470 val[id]);471 472set_default_dvs_mode:473 return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],474 default_dvs_mode[id]);475}476 477static int lp8788_buck_probe(struct platform_device *pdev)478{479 struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);480 int id = pdev->id;481 struct lp8788_buck *buck;482 struct regulator_config cfg = { };483 struct regulator_dev *rdev;484 int ret;485 486 if (id >= LP8788_NUM_BUCKS)487 return -EINVAL;488 489 buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL);490 if (!buck)491 return -ENOMEM;492 493 buck->lp = lp;494 495 ret = lp8788_init_dvs(pdev, buck, id);496 if (ret)497 return ret;498 499 cfg.dev = pdev->dev.parent;500 cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;501 cfg.driver_data = buck;502 cfg.regmap = lp->regmap;503 504 rdev = devm_regulator_register(&pdev->dev, &lp8788_buck_desc[id], &cfg);505 if (IS_ERR(rdev)) {506 ret = PTR_ERR(rdev);507 dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n",508 id + 1, ret);509 return ret;510 }511 512 buck->regulator = rdev;513 platform_set_drvdata(pdev, buck);514 515 return 0;516}517 518static struct platform_driver lp8788_buck_driver = {519 .probe = lp8788_buck_probe,520 .driver = {521 .name = LP8788_DEV_BUCK,522 .probe_type = PROBE_PREFER_ASYNCHRONOUS,523 },524};525 526static int __init lp8788_buck_init(void)527{528 return platform_driver_register(&lp8788_buck_driver);529}530subsys_initcall(lp8788_buck_init);531 532static void __exit lp8788_buck_exit(void)533{534 platform_driver_unregister(&lp8788_buck_driver);535}536module_exit(lp8788_buck_exit);537 538MODULE_DESCRIPTION("TI LP8788 BUCK Driver");539MODULE_AUTHOR("Milo Kim");540MODULE_LICENSE("GPL");541MODULE_ALIAS("platform:lp8788-buck");542