162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Regulator driver for TPS68470 PMIC 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) 2021 Red Hat Inc. 662306a36Sopenharmony_ci// Copyright (C) 2018 Intel Corporation 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// Authors: 962306a36Sopenharmony_ci// Hans de Goede <hdegoede@redhat.com> 1062306a36Sopenharmony_ci// Zaikuo Wang <zaikuo.wang@intel.com> 1162306a36Sopenharmony_ci// Tianshu Qiu <tian.shu.qiu@intel.com> 1262306a36Sopenharmony_ci// Jian Xu Zheng <jian.xu.zheng@intel.com> 1362306a36Sopenharmony_ci// Yuning Pu <yuning.pu@intel.com> 1462306a36Sopenharmony_ci// Rajmohan Mani <rajmohan.mani@intel.com> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/clk.h> 1762306a36Sopenharmony_ci#include <linux/device.h> 1862306a36Sopenharmony_ci#include <linux/err.h> 1962306a36Sopenharmony_ci#include <linux/init.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/mfd/tps68470.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/platform_data/tps68470.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include <linux/regulator/driver.h> 2662306a36Sopenharmony_ci#include <linux/regulator/machine.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct tps68470_regulator_data { 2962306a36Sopenharmony_ci struct clk *clk; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define TPS68470_REGULATOR(_name, _id, _ops, _n, \ 3362306a36Sopenharmony_ci _vr, _vm, _er, _em, _lr, _nlr) \ 3462306a36Sopenharmony_ci [TPS68470_ ## _name] = { \ 3562306a36Sopenharmony_ci .name = # _name, \ 3662306a36Sopenharmony_ci .id = _id, \ 3762306a36Sopenharmony_ci .ops = &_ops, \ 3862306a36Sopenharmony_ci .n_voltages = _n, \ 3962306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 4062306a36Sopenharmony_ci .owner = THIS_MODULE, \ 4162306a36Sopenharmony_ci .vsel_reg = _vr, \ 4262306a36Sopenharmony_ci .vsel_mask = _vm, \ 4362306a36Sopenharmony_ci .enable_reg = _er, \ 4462306a36Sopenharmony_ci .enable_mask = _em, \ 4562306a36Sopenharmony_ci .linear_ranges = _lr, \ 4662306a36Sopenharmony_ci .n_linear_ranges = _nlr, \ 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic const struct linear_range tps68470_ldo_ranges[] = { 5062306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(875000, 0, 125, 17800), 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const struct linear_range tps68470_core_ranges[] = { 5462306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(900000, 0, 42, 25000), 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int tps68470_regulator_enable(struct regulator_dev *rdev) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct tps68470_regulator_data *data = rdev->reg_data; 6062306a36Sopenharmony_ci int ret; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* The Core buck regulator needs the PMIC's PLL to be enabled */ 6362306a36Sopenharmony_ci if (rdev->desc->id == TPS68470_CORE) { 6462306a36Sopenharmony_ci ret = clk_prepare_enable(data->clk); 6562306a36Sopenharmony_ci if (ret) { 6662306a36Sopenharmony_ci dev_err(&rdev->dev, "Error enabling TPS68470 clock\n"); 6762306a36Sopenharmony_ci return ret; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return regulator_enable_regmap(rdev); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int tps68470_regulator_disable(struct regulator_dev *rdev) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct tps68470_regulator_data *data = rdev->reg_data; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (rdev->desc->id == TPS68470_CORE) 7962306a36Sopenharmony_ci clk_disable_unprepare(data->clk); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return regulator_disable_regmap(rdev); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */ 8562306a36Sopenharmony_cistatic const struct regulator_ops tps68470_regulator_ops = { 8662306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 8762306a36Sopenharmony_ci .enable = tps68470_regulator_enable, 8862306a36Sopenharmony_ci .disable = tps68470_regulator_disable, 8962306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 9062306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 9162306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 9262306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear_range, 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic const struct regulator_ops tps68470_always_on_reg_ops = { 9662306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 9762306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 9862306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 9962306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear_range, 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic const struct regulator_desc regulators[] = { 10362306a36Sopenharmony_ci TPS68470_REGULATOR(CORE, TPS68470_CORE, tps68470_regulator_ops, 43, 10462306a36Sopenharmony_ci TPS68470_REG_VDVAL, TPS68470_VDVAL_DVOLT_MASK, 10562306a36Sopenharmony_ci TPS68470_REG_VDCTL, TPS68470_VDCTL_EN_MASK, 10662306a36Sopenharmony_ci tps68470_core_ranges, ARRAY_SIZE(tps68470_core_ranges)), 10762306a36Sopenharmony_ci TPS68470_REGULATOR(ANA, TPS68470_ANA, tps68470_regulator_ops, 126, 10862306a36Sopenharmony_ci TPS68470_REG_VAVAL, TPS68470_VAVAL_AVOLT_MASK, 10962306a36Sopenharmony_ci TPS68470_REG_VACTL, TPS68470_VACTL_EN_MASK, 11062306a36Sopenharmony_ci tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), 11162306a36Sopenharmony_ci TPS68470_REGULATOR(VCM, TPS68470_VCM, tps68470_regulator_ops, 126, 11262306a36Sopenharmony_ci TPS68470_REG_VCMVAL, TPS68470_VCMVAL_VCVOLT_MASK, 11362306a36Sopenharmony_ci TPS68470_REG_VCMCTL, TPS68470_VCMCTL_EN_MASK, 11462306a36Sopenharmony_ci tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), 11562306a36Sopenharmony_ci TPS68470_REGULATOR(VIO, TPS68470_VIO, tps68470_always_on_reg_ops, 126, 11662306a36Sopenharmony_ci TPS68470_REG_VIOVAL, TPS68470_VIOVAL_IOVOLT_MASK, 11762306a36Sopenharmony_ci 0, 0, 11862306a36Sopenharmony_ci tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), 11962306a36Sopenharmony_ci/* 12062306a36Sopenharmony_ci * (1) This regulator must have the same voltage as VIO if S_IO LDO is used to 12162306a36Sopenharmony_ci * power a sensor/VCM which I2C is daisy chained behind the PMIC. 12262306a36Sopenharmony_ci * (2) If there is no I2C daisy chain it can be set freely. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci TPS68470_REGULATOR(VSIO, TPS68470_VSIO, tps68470_regulator_ops, 126, 12562306a36Sopenharmony_ci TPS68470_REG_VSIOVAL, TPS68470_VSIOVAL_IOVOLT_MASK, 12662306a36Sopenharmony_ci TPS68470_REG_S_I2C_CTL, TPS68470_S_I2C_CTL_EN_MASK, 12762306a36Sopenharmony_ci tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), 12862306a36Sopenharmony_ci TPS68470_REGULATOR(AUX1, TPS68470_AUX1, tps68470_regulator_ops, 126, 12962306a36Sopenharmony_ci TPS68470_REG_VAUX1VAL, TPS68470_VAUX1VAL_AUX1VOLT_MASK, 13062306a36Sopenharmony_ci TPS68470_REG_VAUX1CTL, TPS68470_VAUX1CTL_EN_MASK, 13162306a36Sopenharmony_ci tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), 13262306a36Sopenharmony_ci TPS68470_REGULATOR(AUX2, TPS68470_AUX2, tps68470_regulator_ops, 126, 13362306a36Sopenharmony_ci TPS68470_REG_VAUX2VAL, TPS68470_VAUX2VAL_AUX2VOLT_MASK, 13462306a36Sopenharmony_ci TPS68470_REG_VAUX2CTL, TPS68470_VAUX2CTL_EN_MASK, 13562306a36Sopenharmony_ci tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)), 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int tps68470_regulator_probe(struct platform_device *pdev) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 14162306a36Sopenharmony_ci struct tps68470_regulator_platform_data *pdata = dev_get_platdata(dev); 14262306a36Sopenharmony_ci struct tps68470_regulator_data *data; 14362306a36Sopenharmony_ci struct regulator_config config = { }; 14462306a36Sopenharmony_ci struct regulator_dev *rdev; 14562306a36Sopenharmony_ci int i; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 14862306a36Sopenharmony_ci if (!data) 14962306a36Sopenharmony_ci return -ENOMEM; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci data->clk = devm_clk_get(dev, "tps68470-clk"); 15262306a36Sopenharmony_ci if (IS_ERR(data->clk)) 15362306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(data->clk), "getting tps68470-clk\n"); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci config.dev = dev->parent; 15662306a36Sopenharmony_ci config.regmap = dev_get_drvdata(dev->parent); 15762306a36Sopenharmony_ci config.driver_data = data; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci for (i = 0; i < TPS68470_NUM_REGULATORS; i++) { 16062306a36Sopenharmony_ci if (pdata) 16162306a36Sopenharmony_ci config.init_data = pdata->reg_init_data[i]; 16262306a36Sopenharmony_ci else 16362306a36Sopenharmony_ci config.init_data = NULL; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci rdev = devm_regulator_register(dev, ®ulators[i], &config); 16662306a36Sopenharmony_ci if (IS_ERR(rdev)) 16762306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(rdev), 16862306a36Sopenharmony_ci "registering %s regulator\n", 16962306a36Sopenharmony_ci regulators[i].name); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic struct platform_driver tps68470_regulator_driver = { 17662306a36Sopenharmony_ci .driver = { 17762306a36Sopenharmony_ci .name = "tps68470-regulator", 17862306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 17962306a36Sopenharmony_ci }, 18062306a36Sopenharmony_ci .probe = tps68470_regulator_probe, 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* 18462306a36Sopenharmony_ci * The ACPI tps68470 probe-ordering depends on the clk/gpio/regulator drivers 18562306a36Sopenharmony_ci * registering before the drivers for the camera-sensors which use them bind. 18662306a36Sopenharmony_ci * subsys_initcall() ensures this when the drivers are builtin. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_cistatic int __init tps68470_regulator_init(void) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci return platform_driver_register(&tps68470_regulator_driver); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_cisubsys_initcall(tps68470_regulator_init); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void __exit tps68470_regulator_exit(void) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci platform_driver_unregister(&tps68470_regulator_driver); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_cimodule_exit(tps68470_regulator_exit); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ciMODULE_ALIAS("platform:tps68470-regulator"); 20162306a36Sopenharmony_ciMODULE_DESCRIPTION("TPS68470 voltage regulator driver"); 20262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 203