18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Regulator driver for LP873X PMIC 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 78c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2 as 88c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any 118c2ecf20Sopenharmony_ci * kind, whether expressed or implied; without even the implied warranty 128c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138c2ecf20Sopenharmony_ci * GNU General Public License version 2 for more details. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/mfd/lp873x.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define LP873X_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, _er, _em, \ 238c2ecf20Sopenharmony_ci _delay, _lr, _cr) \ 248c2ecf20Sopenharmony_ci [_id] = { \ 258c2ecf20Sopenharmony_ci .desc = { \ 268c2ecf20Sopenharmony_ci .name = _name, \ 278c2ecf20Sopenharmony_ci .supply_name = _of "-in", \ 288c2ecf20Sopenharmony_ci .id = _id, \ 298c2ecf20Sopenharmony_ci .of_match = of_match_ptr(_of), \ 308c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("regulators"),\ 318c2ecf20Sopenharmony_ci .ops = &_ops, \ 328c2ecf20Sopenharmony_ci .n_voltages = _n, \ 338c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 348c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 358c2ecf20Sopenharmony_ci .vsel_reg = _vr, \ 368c2ecf20Sopenharmony_ci .vsel_mask = _vm, \ 378c2ecf20Sopenharmony_ci .enable_reg = _er, \ 388c2ecf20Sopenharmony_ci .enable_mask = _em, \ 398c2ecf20Sopenharmony_ci .ramp_delay = _delay, \ 408c2ecf20Sopenharmony_ci .linear_ranges = _lr, \ 418c2ecf20Sopenharmony_ci .n_linear_ranges = ARRAY_SIZE(_lr), \ 428c2ecf20Sopenharmony_ci .curr_table = lp873x_buck_uA, \ 438c2ecf20Sopenharmony_ci .n_current_limits = ARRAY_SIZE(lp873x_buck_uA), \ 448c2ecf20Sopenharmony_ci .csel_reg = (_cr), \ 458c2ecf20Sopenharmony_ci .csel_mask = LP873X_BUCK0_CTRL_2_BUCK0_ILIM,\ 468c2ecf20Sopenharmony_ci }, \ 478c2ecf20Sopenharmony_ci .ctrl2_reg = _cr, \ 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct lp873x_regulator { 518c2ecf20Sopenharmony_ci struct regulator_desc desc; 528c2ecf20Sopenharmony_ci unsigned int ctrl2_reg; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic const struct lp873x_regulator regulators[]; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic const struct linear_range buck0_buck1_ranges[] = { 588c2ecf20Sopenharmony_ci REGULATOR_LINEAR_RANGE(0, 0x0, 0x13, 0), 598c2ecf20Sopenharmony_ci REGULATOR_LINEAR_RANGE(700000, 0x14, 0x17, 10000), 608c2ecf20Sopenharmony_ci REGULATOR_LINEAR_RANGE(735000, 0x18, 0x9d, 5000), 618c2ecf20Sopenharmony_ci REGULATOR_LINEAR_RANGE(1420000, 0x9e, 0xff, 20000), 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const struct linear_range ldo0_ldo1_ranges[] = { 658c2ecf20Sopenharmony_ci REGULATOR_LINEAR_RANGE(800000, 0x0, 0x19, 100000), 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const unsigned int lp873x_buck_ramp_delay[] = { 698c2ecf20Sopenharmony_ci 30000, 15000, 10000, 7500, 3800, 1900, 940, 470 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* LP873X BUCK current limit */ 738c2ecf20Sopenharmony_cistatic const unsigned int lp873x_buck_uA[] = { 748c2ecf20Sopenharmony_ci 1500000, 2000000, 2500000, 3000000, 3500000, 4000000, 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int lp873x_buck_set_ramp_delay(struct regulator_dev *rdev, 788c2ecf20Sopenharmony_ci int ramp_delay) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 818c2ecf20Sopenharmony_ci struct lp873x *lp873 = rdev_get_drvdata(rdev); 828c2ecf20Sopenharmony_ci unsigned int reg; 838c2ecf20Sopenharmony_ci int ret; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (ramp_delay <= 470) 868c2ecf20Sopenharmony_ci reg = 7; 878c2ecf20Sopenharmony_ci else if (ramp_delay <= 940) 888c2ecf20Sopenharmony_ci reg = 6; 898c2ecf20Sopenharmony_ci else if (ramp_delay <= 1900) 908c2ecf20Sopenharmony_ci reg = 5; 918c2ecf20Sopenharmony_ci else if (ramp_delay <= 3800) 928c2ecf20Sopenharmony_ci reg = 4; 938c2ecf20Sopenharmony_ci else if (ramp_delay <= 7500) 948c2ecf20Sopenharmony_ci reg = 3; 958c2ecf20Sopenharmony_ci else if (ramp_delay <= 10000) 968c2ecf20Sopenharmony_ci reg = 2; 978c2ecf20Sopenharmony_ci else if (ramp_delay <= 15000) 988c2ecf20Sopenharmony_ci reg = 1; 998c2ecf20Sopenharmony_ci else 1008c2ecf20Sopenharmony_ci reg = 0; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci ret = regmap_update_bits(lp873->regmap, regulators[id].ctrl2_reg, 1038c2ecf20Sopenharmony_ci LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE, 1048c2ecf20Sopenharmony_ci reg << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE)); 1058c2ecf20Sopenharmony_ci if (ret) { 1068c2ecf20Sopenharmony_ci dev_err(lp873->dev, "SLEW RATE write failed: %d\n", ret); 1078c2ecf20Sopenharmony_ci return ret; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci rdev->constraints->ramp_delay = lp873x_buck_ramp_delay[reg]; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* Operations permitted on BUCK0, BUCK1 */ 1168c2ecf20Sopenharmony_cistatic const struct regulator_ops lp873x_buck01_ops = { 1178c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 1188c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 1198c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 1208c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 1218c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 1228c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 1238c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear_range, 1248c2ecf20Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 1258c2ecf20Sopenharmony_ci .set_ramp_delay = lp873x_buck_set_ramp_delay, 1268c2ecf20Sopenharmony_ci .set_current_limit = regulator_set_current_limit_regmap, 1278c2ecf20Sopenharmony_ci .get_current_limit = regulator_get_current_limit_regmap, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* Operations permitted on LDO0 and LDO1 */ 1318c2ecf20Sopenharmony_cistatic const struct regulator_ops lp873x_ldo01_ops = { 1328c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 1338c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 1348c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 1358c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 1368c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 1378c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 1388c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear_range, 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic const struct lp873x_regulator regulators[] = { 1428c2ecf20Sopenharmony_ci LP873X_REGULATOR("BUCK0", LP873X_BUCK_0, "buck0", lp873x_buck01_ops, 1438c2ecf20Sopenharmony_ci 256, LP873X_REG_BUCK0_VOUT, 1448c2ecf20Sopenharmony_ci LP873X_BUCK0_VOUT_BUCK0_VSET, LP873X_REG_BUCK0_CTRL_1, 1458c2ecf20Sopenharmony_ci LP873X_BUCK0_CTRL_1_BUCK0_EN, 10000, 1468c2ecf20Sopenharmony_ci buck0_buck1_ranges, LP873X_REG_BUCK0_CTRL_2), 1478c2ecf20Sopenharmony_ci LP873X_REGULATOR("BUCK1", LP873X_BUCK_1, "buck1", lp873x_buck01_ops, 1488c2ecf20Sopenharmony_ci 256, LP873X_REG_BUCK1_VOUT, 1498c2ecf20Sopenharmony_ci LP873X_BUCK1_VOUT_BUCK1_VSET, LP873X_REG_BUCK1_CTRL_1, 1508c2ecf20Sopenharmony_ci LP873X_BUCK1_CTRL_1_BUCK1_EN, 10000, 1518c2ecf20Sopenharmony_ci buck0_buck1_ranges, LP873X_REG_BUCK1_CTRL_2), 1528c2ecf20Sopenharmony_ci LP873X_REGULATOR("LDO0", LP873X_LDO_0, "ldo0", lp873x_ldo01_ops, 26, 1538c2ecf20Sopenharmony_ci LP873X_REG_LDO0_VOUT, LP873X_LDO0_VOUT_LDO0_VSET, 1548c2ecf20Sopenharmony_ci LP873X_REG_LDO0_CTRL, 1558c2ecf20Sopenharmony_ci LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 0xFF), 1568c2ecf20Sopenharmony_ci LP873X_REGULATOR("LDO1", LP873X_LDO_1, "ldo1", lp873x_ldo01_ops, 26, 1578c2ecf20Sopenharmony_ci LP873X_REG_LDO1_VOUT, LP873X_LDO1_VOUT_LDO1_VSET, 1588c2ecf20Sopenharmony_ci LP873X_REG_LDO1_CTRL, 1598c2ecf20Sopenharmony_ci LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 0xFF), 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int lp873x_regulator_probe(struct platform_device *pdev) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct lp873x *lp873 = dev_get_drvdata(pdev->dev.parent); 1658c2ecf20Sopenharmony_ci struct regulator_config config = { }; 1668c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 1678c2ecf20Sopenharmony_ci int i; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, lp873); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci config.dev = &pdev->dev; 1728c2ecf20Sopenharmony_ci config.dev->of_node = lp873->dev->of_node; 1738c2ecf20Sopenharmony_ci config.driver_data = lp873; 1748c2ecf20Sopenharmony_ci config.regmap = lp873->regmap; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regulators); i++) { 1778c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, ®ulators[i].desc, 1788c2ecf20Sopenharmony_ci &config); 1798c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 1808c2ecf20Sopenharmony_ci dev_err(lp873->dev, "failed to register %s regulator\n", 1818c2ecf20Sopenharmony_ci pdev->name); 1828c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic const struct platform_device_id lp873x_regulator_id_table[] = { 1908c2ecf20Sopenharmony_ci { "lp873x-regulator", }, 1918c2ecf20Sopenharmony_ci { /* sentinel */ } 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, lp873x_regulator_id_table); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic struct platform_driver lp873x_regulator_driver = { 1968c2ecf20Sopenharmony_ci .driver = { 1978c2ecf20Sopenharmony_ci .name = "lp873x-pmic", 1988c2ecf20Sopenharmony_ci }, 1998c2ecf20Sopenharmony_ci .probe = lp873x_regulator_probe, 2008c2ecf20Sopenharmony_ci .id_table = lp873x_regulator_id_table, 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_cimodule_platform_driver(lp873x_regulator_driver); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ciMODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>"); 2058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LP873X voltage regulator driver"); 2068c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:lp873x-pmic"); 2078c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 208