162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Regulator driver for LP87565 PMIC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/regmap.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/mfd/lp87565.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cienum LP87565_regulator_id { 1562306a36Sopenharmony_ci /* BUCK's */ 1662306a36Sopenharmony_ci LP87565_BUCK_0, 1762306a36Sopenharmony_ci LP87565_BUCK_1, 1862306a36Sopenharmony_ci LP87565_BUCK_2, 1962306a36Sopenharmony_ci LP87565_BUCK_3, 2062306a36Sopenharmony_ci LP87565_BUCK_10, 2162306a36Sopenharmony_ci LP87565_BUCK_23, 2262306a36Sopenharmony_ci LP87565_BUCK_3210, 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define LP87565_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, \ 2662306a36Sopenharmony_ci _er, _em, _ev, _delay, _lr, _cr) \ 2762306a36Sopenharmony_ci [_id] = { \ 2862306a36Sopenharmony_ci .desc = { \ 2962306a36Sopenharmony_ci .name = _name, \ 3062306a36Sopenharmony_ci .supply_name = _of "-in", \ 3162306a36Sopenharmony_ci .id = _id, \ 3262306a36Sopenharmony_ci .of_match = _of, \ 3362306a36Sopenharmony_ci .regulators_node = "regulators", \ 3462306a36Sopenharmony_ci .ops = &_ops, \ 3562306a36Sopenharmony_ci .n_voltages = _n, \ 3662306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 3762306a36Sopenharmony_ci .owner = THIS_MODULE, \ 3862306a36Sopenharmony_ci .vsel_reg = _vr, \ 3962306a36Sopenharmony_ci .vsel_mask = _vm, \ 4062306a36Sopenharmony_ci .enable_reg = _er, \ 4162306a36Sopenharmony_ci .enable_mask = _em, \ 4262306a36Sopenharmony_ci .enable_val = _ev, \ 4362306a36Sopenharmony_ci .ramp_delay = _delay, \ 4462306a36Sopenharmony_ci .linear_ranges = _lr, \ 4562306a36Sopenharmony_ci .n_linear_ranges = ARRAY_SIZE(_lr), \ 4662306a36Sopenharmony_ci .curr_table = lp87565_buck_uA, \ 4762306a36Sopenharmony_ci .n_current_limits = ARRAY_SIZE(lp87565_buck_uA),\ 4862306a36Sopenharmony_ci .csel_reg = (_cr), \ 4962306a36Sopenharmony_ci .csel_mask = LP87565_BUCK_CTRL_2_ILIM, \ 5062306a36Sopenharmony_ci }, \ 5162306a36Sopenharmony_ci .ctrl2_reg = _cr, \ 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct lp87565_regulator { 5562306a36Sopenharmony_ci struct regulator_desc desc; 5662306a36Sopenharmony_ci unsigned int ctrl2_reg; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic const struct lp87565_regulator regulators[]; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic const struct linear_range buck0_1_2_3_ranges[] = { 6262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(600000, 0xA, 0x17, 10000), 6362306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(735000, 0x18, 0x9d, 5000), 6462306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1420000, 0x9e, 0xff, 20000), 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic const unsigned int lp87565_buck_ramp_delay[] = { 6862306a36Sopenharmony_ci 30000, 15000, 10000, 7500, 3800, 1900, 940, 470 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* LP87565 BUCK current limit */ 7262306a36Sopenharmony_cistatic const unsigned int lp87565_buck_uA[] = { 7362306a36Sopenharmony_ci 1500000, 2000000, 2500000, 3000000, 3500000, 4000000, 4500000, 5000000, 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev, 7762306a36Sopenharmony_ci int ramp_delay) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci int id = rdev_get_id(rdev); 8062306a36Sopenharmony_ci unsigned int reg; 8162306a36Sopenharmony_ci int ret; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (ramp_delay <= 470) 8462306a36Sopenharmony_ci reg = 7; 8562306a36Sopenharmony_ci else if (ramp_delay <= 940) 8662306a36Sopenharmony_ci reg = 6; 8762306a36Sopenharmony_ci else if (ramp_delay <= 1900) 8862306a36Sopenharmony_ci reg = 5; 8962306a36Sopenharmony_ci else if (ramp_delay <= 3800) 9062306a36Sopenharmony_ci reg = 4; 9162306a36Sopenharmony_ci else if (ramp_delay <= 7500) 9262306a36Sopenharmony_ci reg = 3; 9362306a36Sopenharmony_ci else if (ramp_delay <= 10000) 9462306a36Sopenharmony_ci reg = 2; 9562306a36Sopenharmony_ci else if (ramp_delay <= 15000) 9662306a36Sopenharmony_ci reg = 1; 9762306a36Sopenharmony_ci else 9862306a36Sopenharmony_ci reg = 0; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, regulators[id].ctrl2_reg, 10162306a36Sopenharmony_ci LP87565_BUCK_CTRL_2_SLEW_RATE, 10262306a36Sopenharmony_ci reg << __ffs(LP87565_BUCK_CTRL_2_SLEW_RATE)); 10362306a36Sopenharmony_ci if (ret) { 10462306a36Sopenharmony_ci dev_err(&rdev->dev, "SLEW RATE write failed: %d\n", ret); 10562306a36Sopenharmony_ci return ret; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci rdev->constraints->ramp_delay = lp87565_buck_ramp_delay[reg]; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Conservatively give a 15% margin */ 11162306a36Sopenharmony_ci rdev->constraints->ramp_delay = 11262306a36Sopenharmony_ci rdev->constraints->ramp_delay * 85 / 100; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* Operations permitted on BUCKs */ 11862306a36Sopenharmony_cistatic const struct regulator_ops lp87565_buck_ops = { 11962306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 12062306a36Sopenharmony_ci .enable = regulator_enable_regmap, 12162306a36Sopenharmony_ci .disable = regulator_disable_regmap, 12262306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 12362306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 12462306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 12562306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear_range, 12662306a36Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 12762306a36Sopenharmony_ci .set_ramp_delay = lp87565_buck_set_ramp_delay, 12862306a36Sopenharmony_ci .set_current_limit = regulator_set_current_limit_regmap, 12962306a36Sopenharmony_ci .get_current_limit = regulator_get_current_limit_regmap, 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic const struct lp87565_regulator regulators[] = { 13362306a36Sopenharmony_ci LP87565_REGULATOR("BUCK0", LP87565_BUCK_0, "buck0", lp87565_buck_ops, 13462306a36Sopenharmony_ci 256, LP87565_REG_BUCK0_VOUT, LP87565_BUCK_VSET, 13562306a36Sopenharmony_ci LP87565_REG_BUCK0_CTRL_1, 13662306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN | 13762306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN_PIN_CTRL, 13862306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN, 3230, 13962306a36Sopenharmony_ci buck0_1_2_3_ranges, LP87565_REG_BUCK0_CTRL_2), 14062306a36Sopenharmony_ci LP87565_REGULATOR("BUCK1", LP87565_BUCK_1, "buck1", lp87565_buck_ops, 14162306a36Sopenharmony_ci 256, LP87565_REG_BUCK1_VOUT, LP87565_BUCK_VSET, 14262306a36Sopenharmony_ci LP87565_REG_BUCK1_CTRL_1, 14362306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN | 14462306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN_PIN_CTRL, 14562306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN, 3230, 14662306a36Sopenharmony_ci buck0_1_2_3_ranges, LP87565_REG_BUCK1_CTRL_2), 14762306a36Sopenharmony_ci LP87565_REGULATOR("BUCK2", LP87565_BUCK_2, "buck2", lp87565_buck_ops, 14862306a36Sopenharmony_ci 256, LP87565_REG_BUCK2_VOUT, LP87565_BUCK_VSET, 14962306a36Sopenharmony_ci LP87565_REG_BUCK2_CTRL_1, 15062306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN | 15162306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN_PIN_CTRL, 15262306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN, 3230, 15362306a36Sopenharmony_ci buck0_1_2_3_ranges, LP87565_REG_BUCK2_CTRL_2), 15462306a36Sopenharmony_ci LP87565_REGULATOR("BUCK3", LP87565_BUCK_3, "buck3", lp87565_buck_ops, 15562306a36Sopenharmony_ci 256, LP87565_REG_BUCK3_VOUT, LP87565_BUCK_VSET, 15662306a36Sopenharmony_ci LP87565_REG_BUCK3_CTRL_1, 15762306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN | 15862306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN_PIN_CTRL, 15962306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN, 3230, 16062306a36Sopenharmony_ci buck0_1_2_3_ranges, LP87565_REG_BUCK3_CTRL_2), 16162306a36Sopenharmony_ci LP87565_REGULATOR("BUCK10", LP87565_BUCK_10, "buck10", lp87565_buck_ops, 16262306a36Sopenharmony_ci 256, LP87565_REG_BUCK0_VOUT, LP87565_BUCK_VSET, 16362306a36Sopenharmony_ci LP87565_REG_BUCK0_CTRL_1, 16462306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN | 16562306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN_PIN_CTRL | 16662306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_FPWM_MP_0_2, 16762306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN | 16862306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_FPWM_MP_0_2, 3230, 16962306a36Sopenharmony_ci buck0_1_2_3_ranges, LP87565_REG_BUCK0_CTRL_2), 17062306a36Sopenharmony_ci LP87565_REGULATOR("BUCK23", LP87565_BUCK_23, "buck23", lp87565_buck_ops, 17162306a36Sopenharmony_ci 256, LP87565_REG_BUCK2_VOUT, LP87565_BUCK_VSET, 17262306a36Sopenharmony_ci LP87565_REG_BUCK2_CTRL_1, 17362306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN | 17462306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN_PIN_CTRL, 17562306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN, 3230, 17662306a36Sopenharmony_ci buck0_1_2_3_ranges, LP87565_REG_BUCK2_CTRL_2), 17762306a36Sopenharmony_ci LP87565_REGULATOR("BUCK3210", LP87565_BUCK_3210, "buck3210", 17862306a36Sopenharmony_ci lp87565_buck_ops, 256, LP87565_REG_BUCK0_VOUT, 17962306a36Sopenharmony_ci LP87565_BUCK_VSET, LP87565_REG_BUCK0_CTRL_1, 18062306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN | 18162306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN_PIN_CTRL | 18262306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_FPWM_MP_0_2, 18362306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_EN | 18462306a36Sopenharmony_ci LP87565_BUCK_CTRL_1_FPWM_MP_0_2, 3230, 18562306a36Sopenharmony_ci buck0_1_2_3_ranges, LP87565_REG_BUCK0_CTRL_2), 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int lp87565_regulator_probe(struct platform_device *pdev) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct lp87565 *lp87565 = dev_get_drvdata(pdev->dev.parent); 19162306a36Sopenharmony_ci struct regulator_config config = { }; 19262306a36Sopenharmony_ci struct regulator_dev *rdev; 19362306a36Sopenharmony_ci int i, min_idx, max_idx; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci platform_set_drvdata(pdev, lp87565); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci config.dev = &pdev->dev; 19862306a36Sopenharmony_ci config.dev->of_node = lp87565->dev->of_node; 19962306a36Sopenharmony_ci config.driver_data = lp87565; 20062306a36Sopenharmony_ci config.regmap = lp87565->regmap; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci switch (lp87565->dev_type) { 20362306a36Sopenharmony_ci case LP87565_DEVICE_TYPE_LP87565_Q1: 20462306a36Sopenharmony_ci min_idx = LP87565_BUCK_10; 20562306a36Sopenharmony_ci max_idx = LP87565_BUCK_23; 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci case LP87565_DEVICE_TYPE_LP87561_Q1: 20862306a36Sopenharmony_ci min_idx = LP87565_BUCK_3210; 20962306a36Sopenharmony_ci max_idx = LP87565_BUCK_3210; 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci default: 21262306a36Sopenharmony_ci min_idx = LP87565_BUCK_0; 21362306a36Sopenharmony_ci max_idx = LP87565_BUCK_3; 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci for (i = min_idx; i <= max_idx; i++) { 21862306a36Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, ®ulators[i].desc, 21962306a36Sopenharmony_ci &config); 22062306a36Sopenharmony_ci if (IS_ERR(rdev)) { 22162306a36Sopenharmony_ci dev_err(lp87565->dev, "failed to register %s regulator\n", 22262306a36Sopenharmony_ci pdev->name); 22362306a36Sopenharmony_ci return PTR_ERR(rdev); 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic const struct platform_device_id lp87565_regulator_id_table[] = { 23162306a36Sopenharmony_ci { "lp87565-regulator", }, 23262306a36Sopenharmony_ci { "lp87565-q1-regulator", }, 23362306a36Sopenharmony_ci { /* sentinel */ } 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, lp87565_regulator_id_table); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic struct platform_driver lp87565_regulator_driver = { 23862306a36Sopenharmony_ci .driver = { 23962306a36Sopenharmony_ci .name = "lp87565-pmic", 24062306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 24162306a36Sopenharmony_ci }, 24262306a36Sopenharmony_ci .probe = lp87565_regulator_probe, 24362306a36Sopenharmony_ci .id_table = lp87565_regulator_id_table, 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_cimodule_platform_driver(lp87565_regulator_driver); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ciMODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>"); 24862306a36Sopenharmony_ciMODULE_DESCRIPTION("LP87565 voltage regulator driver"); 24962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 250