diff options
Diffstat (limited to 'drivers/regulator')
107 files changed, 4673 insertions, 1633 deletions
diff --git a/drivers/regulator/88pm886-regulator.c b/drivers/regulator/88pm886-regulator.c new file mode 100644 index 000000000000..a38bd4f312b7 --- /dev/null +++ b/drivers/regulator/88pm886-regulator.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +#include <linux/mfd/88pm886.h> + +static const struct regmap_config pm886_regulator_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PM886_REG_BUCK5_VOUT, +}; + +static const struct regulator_ops pm886_ldo_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_ops pm886_buck_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const unsigned int pm886_ldo_volt_table1[] = { + 1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000, +}; + +static const unsigned int pm886_ldo_volt_table2[] = { + 1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000, + 2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000, +}; + +static const unsigned int pm886_ldo_volt_table3[] = { + 1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2700000, 2800000, +}; + +static const struct linear_range pm886_buck_volt_ranges1[] = { + REGULATOR_LINEAR_RANGE(600000, 0, 79, 12500), + REGULATOR_LINEAR_RANGE(1600000, 80, 84, 50000), +}; + +static const struct linear_range pm886_buck_volt_ranges2[] = { + REGULATOR_LINEAR_RANGE(600000, 0, 79, 12500), + REGULATOR_LINEAR_RANGE(1600000, 80, 114, 50000), +}; + +static struct regulator_desc pm886_regulators[] = { + { + .name = "LDO1", + .regulators_node = "regulators", + .of_match = "ldo1", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN1, + .enable_mask = BIT(0), + .volt_table = pm886_ldo_volt_table1, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table1), + .vsel_reg = PM886_REG_LDO1_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO2", + .regulators_node = "regulators", + .of_match = "ldo2", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN1, + .enable_mask = BIT(1), + .volt_table = pm886_ldo_volt_table1, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table1), + .vsel_reg = PM886_REG_LDO2_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO3", + .regulators_node = "regulators", + .of_match = "ldo3", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN1, + .enable_mask = BIT(2), + .volt_table = pm886_ldo_volt_table1, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table1), + .vsel_reg = PM886_REG_LDO3_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO4", + .regulators_node = "regulators", + .of_match = "ldo4", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN1, + .enable_mask = BIT(3), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO4_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO5", + .regulators_node = "regulators", + .of_match = "ldo5", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN1, + .enable_mask = BIT(4), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO5_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO6", + .regulators_node = "regulators", + .of_match = "ldo6", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN1, + .enable_mask = BIT(5), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO6_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO7", + .regulators_node = "regulators", + .of_match = "ldo7", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN1, + .enable_mask = BIT(6), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO7_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO8", + .regulators_node = "regulators", + .of_match = "ldo8", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN1, + .enable_mask = BIT(7), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO8_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO9", + .regulators_node = "regulators", + .of_match = "ldo9", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN2, + .enable_mask = BIT(0), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO9_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO10", + .regulators_node = "regulators", + .of_match = "ldo10", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN2, + .enable_mask = BIT(1), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO10_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO11", + .regulators_node = "regulators", + .of_match = "ldo11", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN2, + .enable_mask = BIT(2), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO11_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO12", + .regulators_node = "regulators", + .of_match = "ldo12", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN2, + .enable_mask = BIT(3), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO12_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO13", + .regulators_node = "regulators", + .of_match = "ldo13", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN2, + .enable_mask = BIT(4), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO13_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO14", + .regulators_node = "regulators", + .of_match = "ldo14", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN2, + .enable_mask = BIT(5), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO14_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO15", + .regulators_node = "regulators", + .of_match = "ldo15", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN2, + .enable_mask = BIT(6), + .volt_table = pm886_ldo_volt_table2, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), + .vsel_reg = PM886_REG_LDO15_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "LDO16", + .regulators_node = "regulators", + .of_match = "ldo16", + .ops = &pm886_ldo_ops, + .type = REGULATOR_VOLTAGE, + .enable_reg = PM886_REG_LDO_EN2, + .enable_mask = BIT(7), + .volt_table = pm886_ldo_volt_table3, + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table3), + .vsel_reg = PM886_REG_LDO16_VOUT, + .vsel_mask = PM886_LDO_VSEL_MASK, + }, + { + .name = "buck1", + .regulators_node = "regulators", + .of_match = "buck1", + .ops = &pm886_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 85, + .linear_ranges = pm886_buck_volt_ranges1, + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges1), + .vsel_reg = PM886_REG_BUCK1_VOUT, + .vsel_mask = PM886_BUCK_VSEL_MASK, + .enable_reg = PM886_REG_BUCK_EN, + .enable_mask = BIT(0), + }, + { + .name = "buck2", + .regulators_node = "regulators", + .of_match = "buck2", + .ops = &pm886_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 115, + .linear_ranges = pm886_buck_volt_ranges2, + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges2), + .vsel_reg = PM886_REG_BUCK2_VOUT, + .vsel_mask = PM886_BUCK_VSEL_MASK, + .enable_reg = PM886_REG_BUCK_EN, + .enable_mask = BIT(1), + }, + { + .name = "buck3", + .regulators_node = "regulators", + .of_match = "buck3", + .ops = &pm886_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 115, + .linear_ranges = pm886_buck_volt_ranges2, + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges2), + .vsel_reg = PM886_REG_BUCK3_VOUT, + .vsel_mask = PM886_BUCK_VSEL_MASK, + .enable_reg = PM886_REG_BUCK_EN, + .enable_mask = BIT(2), + }, + { + .name = "buck4", + .regulators_node = "regulators", + .of_match = "buck4", + .ops = &pm886_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 115, + .linear_ranges = pm886_buck_volt_ranges2, + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges2), + .vsel_reg = PM886_REG_BUCK4_VOUT, + .vsel_mask = PM886_BUCK_VSEL_MASK, + .enable_reg = PM886_REG_BUCK_EN, + .enable_mask = BIT(3), + }, + { + .name = "buck5", + .regulators_node = "regulators", + .of_match = "buck5", + .ops = &pm886_buck_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 115, + .linear_ranges = pm886_buck_volt_ranges2, + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges2), + .vsel_reg = PM886_REG_BUCK5_VOUT, + .vsel_mask = PM886_BUCK_VSEL_MASK, + .enable_reg = PM886_REG_BUCK_EN, + .enable_mask = BIT(4), + }, +}; + +static int pm886_regulator_probe(struct platform_device *pdev) +{ + struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct regulator_config rcfg = { }; + struct device *dev = &pdev->dev; + struct regulator_desc *rdesc; + struct regulator_dev *rdev; + struct i2c_client *page; + struct regmap *regmap; + + page = devm_i2c_new_dummy_device(dev, chip->client->adapter, + chip->client->addr + PM886_PAGE_OFFSET_REGULATORS); + if (IS_ERR(page)) + return dev_err_probe(dev, PTR_ERR(page), + "Failed to initialize regulators client\n"); + + regmap = devm_regmap_init_i2c(page, &pm886_regulator_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to initialize regulators regmap\n"); + rcfg.regmap = regmap; + + rcfg.dev = dev->parent; + + for (int i = 0; i < ARRAY_SIZE(pm886_regulators); i++) { + rdesc = &pm886_regulators[i]; + rdev = devm_regulator_register(dev, rdesc, &rcfg); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), + "Failed to register %s\n", rdesc->name); + } + + return 0; +} + +static const struct platform_device_id pm886_regulator_id_table[] = { + { "88pm886-regulator", }, + { } +}; +MODULE_DEVICE_TABLE(platform, pm886_regulator_id_table); + +static struct platform_driver pm886_regulator_driver = { + .driver = { + .name = "88pm886-regulator", + }, + .probe = pm886_regulator_probe, + .id_table = pm886_regulator_id_table, +}; +module_platform_driver(pm886_regulator_driver); + +MODULE_DESCRIPTION("Marvell 88PM886 PMIC regulator driver"); +MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 550145f82726..39297f7d8177 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -91,6 +91,12 @@ config REGULATOR_88PM8607 help This driver supports 88PM8607 voltage regulator chips. +config REGULATOR_88PM886 + tristate "Marvell 88PM886 voltage regulators" + depends on MFD_88PM886_PMIC + help + This driver implements support for Marvell 88PM886 voltage regulators. + config REGULATOR_ACT8865 tristate "Active-semi act8865 voltage regulator" depends on I2C @@ -268,6 +274,18 @@ config REGULATOR_BD957XMUF This driver can also be built as a module. If so, the module will be called bd9576-regulator. +config REGULATOR_BD96801 + tristate "ROHM BD96801 Power Regulator" + depends on MFD_ROHM_BD96801 + select REGULATOR_ROHM + help + This driver supports voltage regulators on ROHM BD96801 PMIC. + This will enable support for the software controllable buck + and LDO regulators. + + This driver can also be built as a module. If so, the module + will be called bd96801-regulator. + config REGULATOR_CPCAP tristate "Motorola CPCAP regulator" depends on MFD_CPCAP @@ -288,7 +306,7 @@ config REGULATOR_CROS_EC config REGULATOR_DA903X tristate "Dialog Semiconductor DA9030/DA9034 regulators" depends on PMIC_DA903X - depends on !CC_IS_CLANG # https://bugs.llvm.org/show_bug.cgi?id=38789 + depends on !CC_IS_CLANG # https://llvm.org/pr38789 help Say y here to support the BUCKs and LDOs regulators found on Dialog Semiconductor DA9030/DA9034 PMIC. @@ -1027,6 +1045,13 @@ config REGULATOR_PWM This driver supports PWM controlled voltage regulators. PWM duty cycle can increase or decrease the voltage. +config REGULATOR_QCOM_PM8008 + tristate "Qualcomm PM8008 PMIC regulators" + depends on MFD_QCOM_PM8008 + help + Select this option to enable support for the voltage regulators in + Qualcomm PM8008 PMICs. + config REGULATOR_QCOM_REFGEN tristate "Qualcomm REFGEN regulator driver" depends on ARCH_QCOM || COMPILE_TEST @@ -1348,13 +1373,6 @@ config REGULATOR_SLG51000 The SLG51000 is seven compact and customizable low dropout regulators. -config REGULATOR_SM5703 - tristate "Silicon Mitus SM5703 regulators" - depends on MFD_SM5703 - help - This driver provides support for voltage regulators of SM5703 - multi-function device. - config REGULATOR_STM32_BOOSTER tristate "STMicroelectronics STM32 BOOSTER" depends on ARCH_STM32 || COMPILE_TEST @@ -1415,6 +1433,14 @@ config REGULATOR_STW481X_VMMC This driver supports the internal VMMC regulator in the STw481x PMIC chips. +config REGULATOR_SUN20I + tristate "Allwinner D1 internal LDOs" + depends on ARCH_SUNXI || COMPILE_TEST + select MFD_SYSCON + default ARCH_SUNXI + help + This driver supports the internal LDOs in the Allwinner D1 SoC. + config REGULATOR_SY7636A tristate "Silergy SY7636A voltage regulator" depends on MFD_SY7636A @@ -1563,13 +1589,15 @@ config REGULATOR_TPS6594 depends on MFD_TPS6594 && OF default MFD_TPS6594 help - This driver supports TPS6594 voltage regulator chips. + This driver supports TPS6594 series and TPS65224 voltage regulator chips. TPS6594 series of PMICs have 5 BUCKs and 4 LDOs voltage regulators. BUCKs 1,2,3,4 can be used in single phase or multiphase mode. Part number defines which single or multiphase mode is i used. It supports software based voltage control for different voltage domains. + TPS65224 PMIC has 4 BUCKs and 3 LDOs. BUCK12 can be used in dual phase. + All BUCKs and LDOs volatge can be controlled through software. config REGULATOR_TPS6524X tristate "TI TPS6524X Power regulators" @@ -1624,6 +1652,15 @@ config REGULATOR_UNIPHIER help Support for regulators implemented on Socionext UniPhier SoCs. +config REGULATOR_RZG2L_VBCTRL + tristate "Renesas RZ/G2L USB VBUS regulator driver" + depends on RESET_RZG2L_USBPHY_CTRL || COMPILE_TEST + depends on OF + select REGMAP_MMIO + default RESET_RZG2L_USBPHY_CTRL + help + Support for VBUS regulators implemented on Renesas RZ/G2L SoCs. + config REGULATOR_VCTRL tristate "Voltage controlled regulators" depends on OF diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 46fb569e6be8..3d5a803dce8a 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_88PG86X) += 88pg86x.o obj-$(CONFIG_REGULATOR_88PM800) += 88pm800-regulator.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o +obj-$(CONFIG_REGULATOR_88PM886) += 88pm886-regulator.o obj-$(CONFIG_REGULATOR_CROS_EC) += cros-ec-regulator.o obj-$(CONFIG_REGULATOR_CPCAP) += cpcap-regulator.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o @@ -37,6 +38,7 @@ obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o obj-$(CONFIG_REGULATOR_BD957XMUF) += bd9576-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x-regulator.o +obj-$(CONFIG_REGULATOR_BD96801) += bd96801-regulator.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o obj-$(CONFIG_REGULATOR_DA9062) += da9062-regulator.o @@ -112,6 +114,7 @@ obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o +obj-$(CONFIG_REGULATOR_QCOM_PM8008) += qcom-pm8008-regulator.o obj-$(CONFIG_REGULATOR_QCOM_REFGEN) += qcom-refgen-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o @@ -157,12 +160,12 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o -obj-$(CONFIG_REGULATOR_SM5703) += sm5703-regulator.o obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o +obj-$(CONFIG_REGULATOR_SUN20I) += sun20i-regulator.o obj-$(CONFIG_REGULATOR_SY7636A) += sy7636a-regulator.o obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o obj-$(CONFIG_REGULATOR_SY8824X) += sy8824x.o @@ -188,6 +191,7 @@ obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o obj-$(CONFIG_REGULATOR_TPS68470) += tps68470-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o +obj-$(CONFIG_REGULATOR_RZG2L_VBCTRL) += renesas-usb-vbus-regulator.o obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o obj-$(CONFIG_REGULATOR_VQMMC_IPQ4019) += vqmmc-ipq4019-regulator.o diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index a504b01dd99c..0457af23c55a 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -673,9 +673,7 @@ static int act8865_pmic_probe(struct i2c_client *client) type = (unsigned long) id->data; - voltage_select = !!of_get_property(dev->of_node, - "active-semi,vsel-high", - NULL); + voltage_select = of_property_read_bool(dev->of_node, "active-semi,vsel-high"); } else { type = i2c_id->driver_data; pdata = dev_get_platdata(dev); diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 4b54068d4f59..501843996faa 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -375,18 +375,18 @@ static int madera_ldo1_probe(struct platform_device *pdev) static struct platform_driver arizona_ldo1_driver = { .probe = arizona_ldo1_probe, - .remove_new = arizona_ldo1_remove, - .driver = { - .name = "arizona-ldo1", + .remove = arizona_ldo1_remove, + .driver = { + .name = "arizona-ldo1", .probe_type = PROBE_FORCE_SYNCHRONOUS, }, }; static struct platform_driver madera_ldo1_driver = { .probe = madera_ldo1_probe, - .remove_new = arizona_ldo1_remove, - .driver = { - .name = "madera-ldo1", + .remove = arizona_ldo1_remove, + .driver = { + .name = "madera-ldo1", .probe_type = PROBE_FORCE_SYNCHRONOUS, }, }; diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index c657820b0bbb..dca99cfb7cbb 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -138,6 +138,13 @@ #define AXP313A_DCDC_V_OUT_MASK GENMASK(6, 0) #define AXP313A_LDO_V_OUT_MASK GENMASK(4, 0) +#define AXP717_DCDC1_NUM_VOLTAGES 88 +#define AXP717_DCDC2_NUM_VOLTAGES 107 +#define AXP717_DCDC3_NUM_VOLTAGES 103 +#define AXP717_DCDC_V_OUT_MASK GENMASK(6, 0) +#define AXP717_LDO_V_OUT_MASK GENMASK(4, 0) +#define AXP717_BOOST_V_OUT_MASK GENMASK(7, 4) + #define AXP803_PWR_OUT_DCDC1_MASK BIT_MASK(0) #define AXP803_PWR_OUT_DCDC2_MASK BIT_MASK(1) #define AXP803_PWR_OUT_DCDC3_MASK BIT_MASK(2) @@ -364,8 +371,8 @@ .ops = &axp20x_ops, \ } -#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ - _vmask, _ereg, _emask) \ +#define AXP_DESC_DELAY(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _ramp_delay) \ [_family##_##_id] = { \ .name = (_match), \ .supply_name = (_supply), \ @@ -381,9 +388,15 @@ .vsel_mask = (_vmask), \ .enable_reg = (_ereg), \ .enable_mask = (_emask), \ + .ramp_delay = (_ramp_delay), \ .ops = &axp20x_ops, \ } +#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask) \ + AXP_DESC_DELAY(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, 0) + #define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \ [_family##_##_id] = { \ .name = (_match), \ @@ -412,8 +425,8 @@ .ops = &axp20x_ops_fixed \ } -#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \ - _vreg, _vmask, _ereg, _emask) \ +#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, _n_voltages, \ + _vreg, _vmask, _ereg, _emask, _ramp_delay) \ [_family##_##_id] = { \ .name = (_match), \ .supply_name = (_supply), \ @@ -429,9 +442,15 @@ .enable_mask = (_emask), \ .linear_ranges = (_ranges), \ .n_linear_ranges = ARRAY_SIZE(_ranges), \ + .ramp_delay = (_ramp_delay), \ .ops = &axp20x_ops_range, \ } +#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \ + _vreg, _vmask, _ereg, _emask) \ + AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \ + _n_voltages, _vreg, _vmask, _ereg, _emask, 0) + static const int axp209_dcdc2_ldo3_slew_rates[] = { 1600, 800, @@ -733,25 +752,106 @@ static const struct linear_range axp313a_dcdc3_ranges[] = { static const struct regulator_desc axp313a_regulators[] = { AXP_DESC_RANGES(AXP313A, DCDC1, "dcdc1", "vin1", axp313a_dcdc1_ranges, AXP313A_DCDC1_NUM_VOLTAGES, - AXP313A_DCDC1_CONRTOL, AXP313A_DCDC_V_OUT_MASK, + AXP313A_DCDC1_CONTROL, AXP313A_DCDC_V_OUT_MASK, AXP313A_OUTPUT_CONTROL, BIT(0)), AXP_DESC_RANGES(AXP313A, DCDC2, "dcdc2", "vin2", axp313a_dcdc2_ranges, AXP313A_DCDC23_NUM_VOLTAGES, - AXP313A_DCDC2_CONRTOL, AXP313A_DCDC_V_OUT_MASK, + AXP313A_DCDC2_CONTROL, AXP313A_DCDC_V_OUT_MASK, AXP313A_OUTPUT_CONTROL, BIT(1)), AXP_DESC_RANGES(AXP313A, DCDC3, "dcdc3", "vin3", axp313a_dcdc3_ranges, AXP313A_DCDC23_NUM_VOLTAGES, - AXP313A_DCDC3_CONRTOL, AXP313A_DCDC_V_OUT_MASK, + AXP313A_DCDC3_CONTROL, AXP313A_DCDC_V_OUT_MASK, AXP313A_OUTPUT_CONTROL, BIT(2)), AXP_DESC(AXP313A, ALDO1, "aldo1", "vin1", 500, 3500, 100, - AXP313A_ALDO1_CONRTOL, AXP313A_LDO_V_OUT_MASK, + AXP313A_ALDO1_CONTROL, AXP313A_LDO_V_OUT_MASK, AXP313A_OUTPUT_CONTROL, BIT(3)), AXP_DESC(AXP313A, DLDO1, "dldo1", "vin1", 500, 3500, 100, - AXP313A_DLDO1_CONRTOL, AXP313A_LDO_V_OUT_MASK, + AXP313A_DLDO1_CONTROL, AXP313A_LDO_V_OUT_MASK, AXP313A_OUTPUT_CONTROL, BIT(4)), AXP_DESC_FIXED(AXP313A, RTC_LDO, "rtc-ldo", "vin1", 1800), }; +static const struct linear_range axp717_dcdc1_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), + REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000), +}; + +/* + * The manual says that the last voltage is 3.4V, encoded as 0b1101011 (107), + * but every other method proves that this is wrong, so it's really 106 that + * programs the final 3.4V. + */ +static const struct linear_range axp717_dcdc2_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), + REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000), + REGULATOR_LINEAR_RANGE(1600000, 88, 106, 100000), +}; + +static const struct linear_range axp717_dcdc3_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), + REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000), +}; + +static const struct regulator_desc axp717_regulators[] = { + AXP_DESC_RANGES_DELAY(AXP717, DCDC1, "dcdc1", "vin1", + axp717_dcdc1_ranges, AXP717_DCDC1_NUM_VOLTAGES, + AXP717_DCDC1_CONTROL, AXP717_DCDC_V_OUT_MASK, + AXP717_DCDC_OUTPUT_CONTROL, BIT(0), 640), + AXP_DESC_RANGES_DELAY(AXP717, DCDC2, "dcdc2", "vin2", + axp717_dcdc2_ranges, AXP717_DCDC2_NUM_VOLTAGES, + AXP717_DCDC2_CONTROL, AXP717_DCDC_V_OUT_MASK, + AXP717_DCDC_OUTPUT_CONTROL, BIT(1), 640), + AXP_DESC_RANGES_DELAY(AXP717, DCDC3, "dcdc3", "vin3", + axp717_dcdc3_ranges, AXP717_DCDC3_NUM_VOLTAGES, + AXP717_DCDC3_CONTROL, AXP717_DCDC_V_OUT_MASK, + AXP717_DCDC_OUTPUT_CONTROL, BIT(2), 640), + AXP_DESC_DELAY(AXP717, DCDC4, "dcdc4", "vin4", 1000, 3700, 100, + AXP717_DCDC4_CONTROL, AXP717_DCDC_V_OUT_MASK, + AXP717_DCDC_OUTPUT_CONTROL, BIT(3), 6400), + AXP_DESC(AXP717, ALDO1, "aldo1", "aldoin", 500, 3500, 100, + AXP717_ALDO1_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO0_OUTPUT_CONTROL, BIT(0)), + AXP_DESC(AXP717, ALDO2, "aldo2", "aldoin", 500, 3500, 100, + AXP717_ALDO2_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO0_OUTPUT_CONTROL, BIT(1)), + AXP_DESC(AXP717, ALDO3, "aldo3", "aldoin", 500, 3500, 100, + AXP717_ALDO3_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO0_OUTPUT_CONTROL, BIT(2)), + AXP_DESC(AXP717, ALDO4, "aldo4", "aldoin", 500, 3500, 100, + AXP717_ALDO4_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO0_OUTPUT_CONTROL, BIT(3)), + AXP_DESC(AXP717, BLDO1, "bldo1", "bldoin", 500, 3500, 100, + AXP717_BLDO1_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO0_OUTPUT_CONTROL, BIT(4)), + AXP_DESC(AXP717, BLDO2, "bldo2", "bldoin", 500, 3500, 100, + AXP717_BLDO2_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO0_OUTPUT_CONTROL, BIT(5)), + AXP_DESC(AXP717, BLDO3, "bldo3", "bldoin", 500, 3500, 100, + AXP717_BLDO3_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO0_OUTPUT_CONTROL, BIT(6)), + AXP_DESC(AXP717, BLDO4, "bldo4", "bldoin", 500, 3500, 100, + AXP717_BLDO4_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO0_OUTPUT_CONTROL, BIT(7)), + AXP_DESC(AXP717, CLDO1, "cldo1", "cldoin", 500, 3500, 100, + AXP717_CLDO1_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO1_OUTPUT_CONTROL, BIT(0)), + AXP_DESC(AXP717, CLDO2, "cldo2", "cldoin", 500, 3500, 100, + AXP717_CLDO2_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO1_OUTPUT_CONTROL, BIT(1)), + AXP_DESC(AXP717, CLDO3, "cldo3", "cldoin", 500, 3500, 100, + AXP717_CLDO3_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO1_OUTPUT_CONTROL, BIT(2)), + AXP_DESC(AXP717, CLDO4, "cldo4", "cldoin", 500, 3500, 100, + AXP717_CLDO4_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO1_OUTPUT_CONTROL, BIT(3)), + AXP_DESC(AXP717, CPUSLDO, "cpusldo", "vin1", 500, 1400, 50, + AXP717_CPUSLDO_CONTROL, AXP717_LDO_V_OUT_MASK, + AXP717_LDO1_OUTPUT_CONTROL, BIT(4)), + AXP_DESC(AXP717, BOOST, "boost", "vin1", 4550, 5510, 64, + AXP717_BOOST_CONTROL, AXP717_BOOST_V_OUT_MASK, + AXP717_MODULE_EN_CONTROL_2, BIT(4)), +}; + /* DCDC ranges shared with AXP813 */ static const struct linear_range axp803_dcdc234_ranges[] = { REGULATOR_LINEAR_RANGE(500000, @@ -1253,6 +1353,8 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) step = 150; break; case AXP313A_ID: + case AXP323_ID: + case AXP717_ID: case AXP15060_ID: /* The DCDC PWM frequency seems to be fixed to 3 MHz. */ if (dcdcfreq != 0) { @@ -1438,6 +1540,15 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) } break; + case AXP323_ID: + regmap_read(axp20x->regmap, AXP323_DCDC_MODE_CTRL2, ®); + + switch (id) { + case AXP313A_DCDC2: + return !!(reg & BIT(1)); + } + break; + default: return false; } @@ -1476,9 +1587,14 @@ static int axp20x_regulator_probe(struct platform_device *pdev) "x-powers,drive-vbus-en"); break; case AXP313A_ID: + case AXP323_ID: regulators = axp313a_regulators; nregulators = AXP313A_REG_ID_MAX; break; + case AXP717_ID: + regulators = axp717_regulators; + nregulators = AXP717_REG_ID_MAX; + break; case AXP803_ID: regulators = axp803_regulators; nregulators = AXP803_REG_ID_MAX; @@ -1504,7 +1620,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) nregulators = AXP15060_REG_ID_MAX; break; default: - dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n", + dev_err(&pdev->dev, "Unsupported AXP variant: %d\n", axp20x->variant); return -EINVAL; } diff --git a/drivers/regulator/bd71815-regulator.c b/drivers/regulator/bd71815-regulator.c index 26192d55a685..79fbb45297f6 100644 --- a/drivers/regulator/bd71815-regulator.c +++ b/drivers/regulator/bd71815-regulator.c @@ -256,7 +256,7 @@ static int buck12_set_hw_dvs_levels(struct device_node *np, * 10: 2.50mV/usec 10mV 4uS * 11: 1.25mV/usec 10mV 8uS */ -static const unsigned int bd7181x_ramp_table[] = { 1250, 2500, 5000, 10000 }; +static const unsigned int bd7181x_ramp_table[] = { 10000, 5000, 2500, 1250 }; static int bd7181x_led_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA) diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c index 08d4ee369287..dd871ffe979c 100644 --- a/drivers/regulator/bd71828-regulator.c +++ b/drivers/regulator/bd71828-regulator.c @@ -206,14 +206,11 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { .suspend_reg = BD71828_REG_BUCK1_SUSP_VOLT, .suspend_mask = BD71828_MASK_BUCK1267_VOLT, .suspend_on_mask = BD71828_MASK_SUSP_EN, - .lpsr_on_mask = BD71828_MASK_LPSR_EN, /* * LPSR voltage is same as SUSPEND voltage. Allow - * setting it so that regulator can be set enabled at - * LPSR state + * only enabling/disabling regulator for LPSR state */ - .lpsr_reg = BD71828_REG_BUCK1_SUSP_VOLT, - .lpsr_mask = BD71828_MASK_BUCK1267_VOLT, + .lpsr_on_mask = BD71828_MASK_LPSR_EN, }, .reg_inits = buck1_inits, .reg_init_amnt = ARRAY_SIZE(buck1_inits), @@ -288,13 +285,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, .run_reg = BD71828_REG_BUCK3_VOLT, - .idle_reg = BD71828_REG_BUCK3_VOLT, - .suspend_reg = BD71828_REG_BUCK3_VOLT, - .lpsr_reg = BD71828_REG_BUCK3_VOLT, .run_mask = BD71828_MASK_BUCK3_VOLT, - .idle_mask = BD71828_MASK_BUCK3_VOLT, - .suspend_mask = BD71828_MASK_BUCK3_VOLT, - .lpsr_mask = BD71828_MASK_BUCK3_VOLT, .idle_on_mask = BD71828_MASK_IDLE_EN, .suspend_on_mask = BD71828_MASK_SUSP_EN, .lpsr_on_mask = BD71828_MASK_LPSR_EN, @@ -329,13 +320,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, .run_reg = BD71828_REG_BUCK4_VOLT, - .idle_reg = BD71828_REG_BUCK4_VOLT, - .suspend_reg = BD71828_REG_BUCK4_VOLT, - .lpsr_reg = BD71828_REG_BUCK4_VOLT, .run_mask = BD71828_MASK_BUCK4_VOLT, - .idle_mask = BD71828_MASK_BUCK4_VOLT, - .suspend_mask = BD71828_MASK_BUCK4_VOLT, - .lpsr_mask = BD71828_MASK_BUCK4_VOLT, .idle_on_mask = BD71828_MASK_IDLE_EN, .suspend_on_mask = BD71828_MASK_SUSP_EN, .lpsr_on_mask = BD71828_MASK_LPSR_EN, @@ -370,13 +355,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, .run_reg = BD71828_REG_BUCK5_VOLT, - .idle_reg = BD71828_REG_BUCK5_VOLT, - .suspend_reg = BD71828_REG_BUCK5_VOLT, - .lpsr_reg = BD71828_REG_BUCK5_VOLT, .run_mask = BD71828_MASK_BUCK5_VOLT, - .idle_mask = BD71828_MASK_BUCK5_VOLT, - .suspend_mask = BD71828_MASK_BUCK5_VOLT, - .lpsr_mask = BD71828_MASK_BUCK5_VOLT, .idle_on_mask = BD71828_MASK_IDLE_EN, .suspend_on_mask = BD71828_MASK_SUSP_EN, .lpsr_on_mask = BD71828_MASK_LPSR_EN, @@ -493,13 +472,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, .run_reg = BD71828_REG_LDO1_VOLT, - .idle_reg = BD71828_REG_LDO1_VOLT, - .suspend_reg = BD71828_REG_LDO1_VOLT, - .lpsr_reg = BD71828_REG_LDO1_VOLT, .run_mask = BD71828_MASK_LDO_VOLT, - .idle_mask = BD71828_MASK_LDO_VOLT, - .suspend_mask = BD71828_MASK_LDO_VOLT, - .lpsr_mask = BD71828_MASK_LDO_VOLT, .idle_on_mask = BD71828_MASK_IDLE_EN, .suspend_on_mask = BD71828_MASK_SUSP_EN, .lpsr_on_mask = BD71828_MASK_LPSR_EN, @@ -533,13 +506,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, .run_reg = BD71828_REG_LDO2_VOLT, - .idle_reg = BD71828_REG_LDO2_VOLT, - .suspend_reg = BD71828_REG_LDO2_VOLT, - .lpsr_reg = BD71828_REG_LDO2_VOLT, .run_mask = BD71828_MASK_LDO_VOLT, - .idle_mask = BD71828_MASK_LDO_VOLT, - .suspend_mask = BD71828_MASK_LDO_VOLT, - .lpsr_mask = BD71828_MASK_LDO_VOLT, .idle_on_mask = BD71828_MASK_IDLE_EN, .suspend_on_mask = BD71828_MASK_SUSP_EN, .lpsr_on_mask = BD71828_MASK_LPSR_EN, @@ -573,13 +540,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, .run_reg = BD71828_REG_LDO3_VOLT, - .idle_reg = BD71828_REG_LDO3_VOLT, - .suspend_reg = BD71828_REG_LDO3_VOLT, - .lpsr_reg = BD71828_REG_LDO3_VOLT, .run_mask = BD71828_MASK_LDO_VOLT, - .idle_mask = BD71828_MASK_LDO_VOLT, - .suspend_mask = BD71828_MASK_LDO_VOLT, - .lpsr_mask = BD71828_MASK_LDO_VOLT, .idle_on_mask = BD71828_MASK_IDLE_EN, .suspend_on_mask = BD71828_MASK_SUSP_EN, .lpsr_on_mask = BD71828_MASK_LPSR_EN, @@ -614,13 +575,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, .run_reg = BD71828_REG_LDO4_VOLT, - .idle_reg = BD71828_REG_LDO4_VOLT, - .suspend_reg = BD71828_REG_LDO4_VOLT, - .lpsr_reg = BD71828_REG_LDO4_VOLT, .run_mask = BD71828_MASK_LDO_VOLT, - .idle_mask = BD71828_MASK_LDO_VOLT, - .suspend_mask = BD71828_MASK_LDO_VOLT, - .lpsr_mask = BD71828_MASK_LDO_VOLT, .idle_on_mask = BD71828_MASK_IDLE_EN, .suspend_on_mask = BD71828_MASK_SUSP_EN, .lpsr_on_mask = BD71828_MASK_LPSR_EN, @@ -655,13 +610,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, .run_reg = BD71828_REG_LDO5_VOLT, - .idle_reg = BD71828_REG_LDO5_VOLT, - .suspend_reg = BD71828_REG_LDO5_VOLT, - .lpsr_reg = BD71828_REG_LDO5_VOLT, .run_mask = BD71828_MASK_LDO_VOLT, - .idle_mask = BD71828_MASK_LDO_VOLT, - .suspend_mask = BD71828_MASK_LDO_VOLT, - .lpsr_mask = BD71828_MASK_LDO_VOLT, .idle_on_mask = BD71828_MASK_IDLE_EN, .suspend_on_mask = BD71828_MASK_SUSP_EN, .lpsr_on_mask = BD71828_MASK_LPSR_EN, @@ -720,9 +669,6 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { .suspend_reg = BD71828_REG_LDO7_VOLT, .lpsr_reg = BD71828_REG_LDO7_VOLT, .run_mask = BD71828_MASK_LDO_VOLT, - .idle_mask = BD71828_MASK_LDO_VOLT, - .suspend_mask = BD71828_MASK_LDO_VOLT, - .lpsr_mask = BD71828_MASK_LDO_VOLT, .idle_on_mask = BD71828_MASK_IDLE_EN, .suspend_on_mask = BD71828_MASK_SUSP_EN, .lpsr_on_mask = BD71828_MASK_LPSR_EN, diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index c3fb05dce40c..1bb048de3ecd 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -2,6 +2,7 @@ // Copyright (C) 2018 ROHM Semiconductors // bd71837-regulator.c ROHM BD71837MWV/BD71847MWV regulator driver +#include <linux/cleanup.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/interrupt.h> @@ -1635,18 +1636,17 @@ static int get_special_regulators(struct device *dev, unsigned int num_reg_data, int *info) { int ret; - struct device_node *np; - struct device_node *nproot = dev->of_node; int uv; *info = 0; - nproot = of_get_child_by_name(nproot, "regulators"); + struct device_node *nproot __free(device_node) = of_get_child_by_name(dev->of_node, + "regulators"); if (!nproot) { dev_err(dev, "failed to find regulators node\n"); return -ENODEV; } - for_each_child_of_node(nproot, np) { + for_each_child_of_node_scoped(nproot, np) { if (of_property_read_bool(np, "rohm,no-regulator-enable-control")) mark_hw_controlled(dev, np, reg_data, num_reg_data, info); @@ -1656,22 +1656,15 @@ static int get_special_regulators(struct device *dev, if (ret == -EINVAL) continue; else - goto err_out; + return ret; } ret = setup_feedback_loop(dev, np, reg_data, num_reg_data, uv); if (ret) - goto err_out; + return ret; } - of_node_put(nproot); return 0; - -err_out: - of_node_put(np); - of_node_put(nproot); - - return ret; } static int bd718xx_probe(struct platform_device *pdev) diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index c7ceba56e7dc..209beabb5c37 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -356,7 +356,7 @@ static struct platform_driver bd9571mwv_regulator_driver = { .pm = DEV_PM_OPS, }, .probe = bd9571mwv_regulator_probe, - .remove_new = bd9571mwv_regulator_remove, + .remove = bd9571mwv_regulator_remove, .id_table = bd9571mwv_regulator_id_table, }; module_platform_driver(bd9571mwv_regulator_driver); diff --git a/drivers/regulator/bd9576-regulator.c b/drivers/regulator/bd9576-regulator.c index d4ca7b3f4036..bf5f9c3f2c97 100644 --- a/drivers/regulator/bd9576-regulator.c +++ b/drivers/regulator/bd9576-regulator.c @@ -68,25 +68,25 @@ static const struct linear_range voutL1_xvd_ranges[] = { REGULATOR_LINEAR_RANGE(220000, 0x6e, 0x7f, 0), }; -static struct linear_range voutS1_ocw_ranges_internal[] = { +static const struct linear_range voutS1_ocw_ranges_internal[] = { REGULATOR_LINEAR_RANGE(200000, 0x01, 0x04, 0), REGULATOR_LINEAR_RANGE(250000, 0x05, 0x18, 50000), REGULATOR_LINEAR_RANGE(1200000, 0x19, 0x3f, 0), }; -static struct linear_range voutS1_ocw_ranges[] = { +static const struct linear_range voutS1_ocw_ranges[] = { REGULATOR_LINEAR_RANGE(50000, 0x01, 0x04, 0), REGULATOR_LINEAR_RANGE(60000, 0x05, 0x18, 10000), REGULATOR_LINEAR_RANGE(250000, 0x19, 0x3f, 0), }; -static struct linear_range voutS1_ocp_ranges_internal[] = { +static const struct linear_range voutS1_ocp_ranges_internal[] = { REGULATOR_LINEAR_RANGE(300000, 0x01, 0x06, 0), REGULATOR_LINEAR_RANGE(350000, 0x7, 0x1b, 50000), REGULATOR_LINEAR_RANGE(1350000, 0x1c, 0x3f, 0), }; -static struct linear_range voutS1_ocp_ranges[] = { +static const struct linear_range voutS1_ocp_ranges[] = { REGULATOR_LINEAR_RANGE(70000, 0x01, 0x06, 0), REGULATOR_LINEAR_RANGE(80000, 0x7, 0x1b, 10000), REGULATOR_LINEAR_RANGE(280000, 0x1c, 0x3f, 0), diff --git a/drivers/regulator/bd96801-regulator.c b/drivers/regulator/bd96801-regulator.c new file mode 100644 index 000000000000..3a9d772491a8 --- /dev/null +++ b/drivers/regulator/bd96801-regulator.c @@ -0,0 +1,1001 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2024 ROHM Semiconductors +// bd96801-regulator.c ROHM BD96801 regulator driver + +/* + * This version of the "BD86801 scalable PMIC"'s driver supports only very + * basic set of the PMIC features. Most notably, there is no support for + * the configurations which should be done when the PMIC is in STBY mode. + * + * Being able to reliably do the configurations like changing the + * regulator safety limits (like limits for the over/under -voltages, over + * current, thermal protection) would require the configuring driver to be + * synchronized with entity causing the PMIC state transitions. Eg, one + * should be able to ensure the PMIC is in STBY state when the + * configurations are applied to the hardware. How and when the PMIC state + * transitions are to be done is likely to be very system specific, as will + * be the need to configure these safety limits. Hence it's not simple to + * come up with a generic solution. + * + * Users who require the STBY state configurations can have a look at the + * original RFC: + * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ + * which implements some of the safety limit configurations - but leaves the + * state change handling and synchronization to be implemented. + * + * It would be great to hear (and receive a patch!) if you implement the + * STBY configuration support in your downstream driver ;) + */ + +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/linear_range.h> +#include <linux/mfd/rohm-generic.h> +#include <linux/mfd/rohm-bd96801.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/coupler.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/slab.h> +#include <linux/timer.h> + +enum { + BD96801_BUCK1, + BD96801_BUCK2, + BD96801_BUCK3, + BD96801_BUCK4, + BD96801_LDO5, + BD96801_LDO6, + BD96801_LDO7, + BD96801_REGULATOR_AMOUNT, +}; + +enum { + BD96801_PROT_OVP, + BD96801_PROT_UVP, + BD96801_PROT_OCP, + BD96801_PROT_TEMP, + BD96801_NUM_PROT, +}; + +#define BD96801_ALWAYS_ON_REG 0x3c +#define BD96801_REG_ENABLE 0x0b +#define BD96801_BUCK1_EN_MASK BIT(0) +#define BD96801_BUCK2_EN_MASK BIT(1) +#define BD96801_BUCK3_EN_MASK BIT(2) +#define BD96801_BUCK4_EN_MASK BIT(3) +#define BD96801_LDO5_EN_MASK BIT(4) +#define BD96801_LDO6_EN_MASK BIT(5) +#define BD96801_LDO7_EN_MASK BIT(6) + +#define BD96801_BUCK1_VSEL_REG 0x28 +#define BD96801_BUCK2_VSEL_REG 0x29 +#define BD96801_BUCK3_VSEL_REG 0x2a +#define BD96801_BUCK4_VSEL_REG 0x2b +#define BD96801_LDO5_VSEL_REG 0x25 +#define BD96801_LDO6_VSEL_REG 0x26 +#define BD96801_LDO7_VSEL_REG 0x27 +#define BD96801_BUCK_VSEL_MASK 0x1F +#define BD96801_LDO_VSEL_MASK 0xff + +#define BD96801_MASK_RAMP_DELAY 0xc0 +#define BD96801_INT_VOUT_BASE_REG 0x21 +#define BD96801_BUCK_INT_VOUT_MASK 0xff + +#define BD96801_BUCK_VOLTS 256 +#define BD96801_LDO_VOLTS 256 + +#define BD96801_OVP_MASK 0x03 +#define BD96801_MASK_BUCK1_OVP_SHIFT 0x00 +#define BD96801_MASK_BUCK2_OVP_SHIFT 0x02 +#define BD96801_MASK_BUCK3_OVP_SHIFT 0x04 +#define BD96801_MASK_BUCK4_OVP_SHIFT 0x06 +#define BD96801_MASK_LDO5_OVP_SHIFT 0x00 +#define BD96801_MASK_LDO6_OVP_SHIFT 0x02 +#define BD96801_MASK_LDO7_OVP_SHIFT 0x04 + +#define BD96801_PROT_LIMIT_OCP_MIN 0x00 +#define BD96801_PROT_LIMIT_LOW 0x01 +#define BD96801_PROT_LIMIT_MID 0x02 +#define BD96801_PROT_LIMIT_HI 0x03 + +#define BD96801_REG_BUCK1_OCP 0x32 +#define BD96801_REG_BUCK2_OCP 0x32 +#define BD96801_REG_BUCK3_OCP 0x33 +#define BD96801_REG_BUCK4_OCP 0x33 + +#define BD96801_MASK_BUCK1_OCP_SHIFT 0x00 +#define BD96801_MASK_BUCK2_OCP_SHIFT 0x04 +#define BD96801_MASK_BUCK3_OCP_SHIFT 0x00 +#define BD96801_MASK_BUCK4_OCP_SHIFT 0x04 + +#define BD96801_REG_LDO5_OCP 0x34 +#define BD96801_REG_LDO6_OCP 0x34 +#define BD96801_REG_LDO7_OCP 0x34 + +#define BD96801_MASK_LDO5_OCP_SHIFT 0x00 +#define BD96801_MASK_LDO6_OCP_SHIFT 0x02 +#define BD96801_MASK_LDO7_OCP_SHIFT 0x04 + +#define BD96801_MASK_SHD_INTB BIT(7) +#define BD96801_INTB_FATAL BIT(7) + +#define BD96801_NUM_REGULATORS 7 +#define BD96801_NUM_LDOS 4 + +/* + * Ramp rates for bucks are controlled by bits [7:6] as follows: + * 00 => 1 mV/uS + * 01 => 5 mV/uS + * 10 => 10 mV/uS + * 11 => 20 mV/uS + */ +static const unsigned int buck_ramp_table[] = { 1000, 5000, 10000, 20000 }; + +/* + * This is a voltage range that get's appended to selected + * bd96801_buck_init_volts value. The range from 0x0 to 0xF is actually + * bd96801_buck_init_volts + 0 ... bd96801_buck_init_volts + 150mV + * and the range from 0x10 to 0x1f is bd96801_buck_init_volts - 150mV ... + * bd96801_buck_init_volts - 0. But as the members of linear_range + * are all unsigned I will apply offset of -150 mV to value in + * linear_range - which should increase these ranges with + * 150 mV getting all the values to >= 0. + */ +static const struct linear_range bd96801_tune_volts[] = { + REGULATOR_LINEAR_RANGE(150000, 0x00, 0xF, 10000), + REGULATOR_LINEAR_RANGE(0, 0x10, 0x1F, 10000), +}; + +static const struct linear_range bd96801_buck_init_volts[] = { + REGULATOR_LINEAR_RANGE(500000 - 150000, 0x00, 0xc8, 5000), + REGULATOR_LINEAR_RANGE(1550000 - 150000, 0xc9, 0xec, 50000), + REGULATOR_LINEAR_RANGE(3300000 - 150000, 0xed, 0xff, 0), +}; + +static const struct linear_range bd96801_ldo_int_volts[] = { + REGULATOR_LINEAR_RANGE(300000, 0x00, 0x78, 25000), + REGULATOR_LINEAR_RANGE(3300000, 0x79, 0xff, 0), +}; + +#define BD96801_LDO_SD_VOLT_MASK 0x1 +#define BD96801_LDO_MODE_MASK 0x6 +#define BD96801_LDO_MODE_INT 0x0 +#define BD96801_LDO_MODE_SD 0x2 +#define BD96801_LDO_MODE_DDR 0x4 + +static int ldo_ddr_volt_table[] = {500000, 300000}; +static int ldo_sd_volt_table[] = {3300000, 1800000}; + +/* Constant IRQ initialization data (templates) */ +struct bd96801_irqinfo { + int type; + struct regulator_irq_desc irq_desc; + int err_cfg; + int wrn_cfg; + const char *irq_name; +}; + +#define BD96801_IRQINFO(_type, _name, _irqoff_ms, _irqname) \ +{ \ + .type = (_type), \ + .err_cfg = -1, \ + .wrn_cfg = -1, \ + .irq_name = (_irqname), \ + .irq_desc = { \ + .name = (_name), \ + .irq_off_ms = (_irqoff_ms), \ + .map_event = regulator_irq_map_event_simple, \ + }, \ +} + +static const struct bd96801_irqinfo buck1_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-h", 500, + "bd96801-buck1-overcurr-h"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-l", 500, + "bd96801-buck1-overcurr-l"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-n", 500, + "bd96801-buck1-overcurr-n"), + BD96801_IRQINFO(BD96801_PROT_OVP, "buck1-over-voltage", 500, + "bd96801-buck1-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "buck1-under-voltage", 500, + "bd96801-buck1-undervolt"), + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck1-over-temp", 500, + "bd96801-buck1-thermal") +}; + +static const struct bd96801_irqinfo buck2_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-h", 500, + "bd96801-buck2-overcurr-h"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-l", 500, + "bd96801-buck2-overcurr-l"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-n", 500, + "bd96801-buck2-overcurr-n"), + BD96801_IRQINFO(BD96801_PROT_OVP, "buck2-over-voltage", 500, + "bd96801-buck2-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "buck2-under-voltage", 500, + "bd96801-buck2-undervolt"), + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck2-over-temp", 500, + "bd96801-buck2-thermal") +}; + +static const struct bd96801_irqinfo buck3_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-h", 500, + "bd96801-buck3-overcurr-h"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-l", 500, + "bd96801-buck3-overcurr-l"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-n", 500, + "bd96801-buck3-overcurr-n"), + BD96801_IRQINFO(BD96801_PROT_OVP, "buck3-over-voltage", 500, + "bd96801-buck3-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "buck3-under-voltage", 500, + "bd96801-buck3-undervolt"), + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck3-over-temp", 500, + "bd96801-buck3-thermal") +}; + +static const struct bd96801_irqinfo buck4_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-h", 500, + "bd96801-buck4-overcurr-h"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-l", 500, + "bd96801-buck4-overcurr-l"), + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-n", 500, + "bd96801-buck4-overcurr-n"), + BD96801_IRQINFO(BD96801_PROT_OVP, "buck4-over-voltage", 500, + "bd96801-buck4-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "buck4-under-voltage", 500, + "bd96801-buck4-undervolt"), + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck4-over-temp", 500, + "bd96801-buck4-thermal") +}; + +static const struct bd96801_irqinfo ldo5_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo5-overcurr", 500, + "bd96801-ldo5-overcurr"), + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo5-over-voltage", 500, + "bd96801-ldo5-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo5-under-voltage", 500, + "bd96801-ldo5-undervolt"), +}; + +static const struct bd96801_irqinfo ldo6_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo6-overcurr", 500, + "bd96801-ldo6-overcurr"), + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo6-over-voltage", 500, + "bd96801-ldo6-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo6-under-voltage", 500, + "bd96801-ldo6-undervolt"), +}; + +static const struct bd96801_irqinfo ldo7_irqinfo[] = { + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo7-overcurr", 500, + "bd96801-ldo7-overcurr"), + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo7-over-voltage", 500, + "bd96801-ldo7-overvolt"), + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo7-under-voltage", 500, + "bd96801-ldo7-undervolt"), +}; + +struct bd96801_irq_desc { + struct bd96801_irqinfo *irqinfo; + int num_irqs; +}; + +struct bd96801_regulator_data { + struct regulator_desc desc; + const struct linear_range *init_ranges; + int num_ranges; + struct bd96801_irq_desc irq_desc; + int initial_voltage; + int ldo_vol_lvl; + int ldo_errs; +}; + +struct bd96801_pmic_data { + struct bd96801_regulator_data regulator_data[BD96801_NUM_REGULATORS]; + struct regmap *regmap; + int fatal_ind; +}; + +static int ldo_map_notif(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int i; + + for (i = 0; i < rid->num_states; i++) { + struct bd96801_regulator_data *rdata; + struct regulator_dev *rdev; + + rdev = rid->states[i].rdev; + rdata = container_of(rdev->desc, struct bd96801_regulator_data, + desc); + rid->states[i].notifs = regulator_err2notif(rdata->ldo_errs); + rid->states[i].errors = rdata->ldo_errs; + *dev_mask |= BIT(i); + } + return 0; +} + +static int bd96801_list_voltage_lr(struct regulator_dev *rdev, + unsigned int selector) +{ + int voltage; + struct bd96801_regulator_data *data; + + data = container_of(rdev->desc, struct bd96801_regulator_data, desc); + + /* + * The BD096801 has voltage setting in two registers. One giving the + * "initial voltage" (can be changed only when regulator is disabled. + * This driver caches the value and sets it only at startup. The other + * register is voltage tuning value which applies -150 mV ... +150 mV + * offset to the voltage. + * + * Note that the cached initial voltage stored in regulator data is + * 'scaled down' by the 150 mV so that all of our tuning values are + * >= 0. This is done because the linear_ranges uses unsigned values. + * + * As a result, we increase the tuning voltage which we get based on + * the selector by the stored initial_voltage. + */ + voltage = regulator_list_voltage_linear_range(rdev, selector); + if (voltage < 0) + return voltage; + + return voltage + data->initial_voltage; +} + + +static const struct regulator_ops bd96801_ldo_table_ops = { + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static const struct regulator_ops bd96801_buck_ops = { + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = bd96801_list_voltage_lr, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = regulator_set_ramp_delay_regmap, +}; + +static const struct regulator_ops bd96801_ldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static int buck_get_initial_voltage(struct regmap *regmap, struct device *dev, + struct bd96801_regulator_data *data) +{ + int ret = 0, sel, initial_uv; + int reg = BD96801_INT_VOUT_BASE_REG + data->desc.id; + + if (data->num_ranges) { + ret = regmap_read(regmap, reg, &sel); + sel &= BD96801_BUCK_INT_VOUT_MASK; + + ret = linear_range_get_value_array(data->init_ranges, + data->num_ranges, sel, + &initial_uv); + if (ret) + return ret; + + data->initial_voltage = initial_uv; + dev_dbg(dev, "Tune-scaled initial voltage %u\n", + data->initial_voltage); + } + + return 0; +} + +static int get_ldo_initial_voltage(struct regmap *regmap, + struct device *dev, + struct bd96801_regulator_data *data) +{ + int ret; + int cfgreg; + + ret = regmap_read(regmap, data->ldo_vol_lvl, &cfgreg); + if (ret) + return ret; + + switch (cfgreg & BD96801_LDO_MODE_MASK) { + case BD96801_LDO_MODE_DDR: + data->desc.volt_table = ldo_ddr_volt_table; + data->desc.n_voltages = ARRAY_SIZE(ldo_ddr_volt_table); + break; + case BD96801_LDO_MODE_SD: + data->desc.volt_table = ldo_sd_volt_table; + data->desc.n_voltages = ARRAY_SIZE(ldo_sd_volt_table); + break; + default: + dev_info(dev, "Leaving LDO to normal mode"); + return 0; + } + + /* SD or DDR mode => override default ops */ + data->desc.ops = &bd96801_ldo_table_ops, + data->desc.vsel_mask = 1; + data->desc.vsel_reg = data->ldo_vol_lvl; + + return 0; +} + +static int get_initial_voltage(struct device *dev, struct regmap *regmap, + struct bd96801_regulator_data *data) +{ + /* BUCK */ + if (data->desc.id <= BD96801_BUCK4) + return buck_get_initial_voltage(regmap, dev, data); + + /* LDO */ + return get_ldo_initial_voltage(regmap, dev, data); +} + +static int bd96801_walk_regulator_dt(struct device *dev, struct regmap *regmap, + struct bd96801_regulator_data *data, + int num) +{ + int i, ret; + + struct device_node *nproot __free(device_node) = + of_get_child_by_name(dev->parent->of_node, "regulators"); + if (!nproot) { + dev_err(dev, "failed to find regulators node\n"); + return -ENODEV; + } + for_each_child_of_node_scoped(nproot, np) { + for (i = 0; i < num; i++) { + if (!of_node_name_eq(np, data[i].desc.of_match)) + continue; + /* + * If STBY configs are supported, we must pass node + * here to extract the initial voltages from the DT. + * Thus we do the initial voltage getting in this + * loop. + */ + ret = get_initial_voltage(dev, regmap, &data[i]); + if (ret) { + dev_err(dev, + "Initializing voltages for %s failed\n", + data[i].desc.name); + return ret; + } + + if (of_property_read_bool(np, "rohm,keep-on-stby")) { + ret = regmap_set_bits(regmap, + BD96801_ALWAYS_ON_REG, + 1 << data[i].desc.id); + if (ret) { + dev_err(dev, + "failed to set %s on-at-stby\n", + data[i].desc.name); + return ret; + } + } + } + } + + return 0; +} + +/* + * Template for regulator data. Probe will allocate dynamic / driver instance + * struct so we should be on a safe side even if there were multiple PMICs to + * control. Note that there is a plan to allow multiple PMICs to be used so + * systems can scale better. I am however still slightly unsure how the + * multi-PMIC case will be handled. I don't know if the processor will have I2C + * acces to all of the PMICs or only the first one. I'd guess there will be + * access provided to all PMICs for voltage scaling - but the errors will only + * be informed via the master PMIC. Eg, we should prepare to support multiple + * driver instances - either with or without the IRQs... Well, let's first + * just support the simple and clear single-PMIC setup and ponder the multi PMIC + * case later. What we can easly do for preparing is to not use static global + * data for regulators though. + */ +static const struct bd96801_pmic_data bd96801_data = { + .regulator_data = { + { + .desc = { + .name = "buck1", + .of_match = of_match_ptr("buck1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK1, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK1_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK1_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK1_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .init_ranges = bd96801_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck1_irqinfo), + }, + }, { + .desc = { + .name = "buck2", + .of_match = of_match_ptr("buck2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK2, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK2_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK2_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK2_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck2_irqinfo), + }, + .init_ranges = bd96801_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), + }, { + .desc = { + .name = "buck3", + .of_match = of_match_ptr("buck3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK3, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK3_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK3_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK3_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck3_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck3_irqinfo), + }, + .init_ranges = bd96801_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), + }, { + .desc = { + .name = "buck4", + .of_match = of_match_ptr("buck4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK4, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK4_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK4_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK4_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck4_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck4_irqinfo), + }, + .init_ranges = bd96801_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), + }, { + .desc = { + .name = "ldo5", + .of_match = of_match_ptr("ldo5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_LDO5, + .ops = &bd96801_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_ldo_int_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), + .n_voltages = BD96801_LDO_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_LDO5_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_LDO5_VSEL_REG, + .vsel_mask = BD96801_LDO_VSEL_MASK, + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&ldo5_irqinfo[0], + .num_irqs = ARRAY_SIZE(ldo5_irqinfo), + }, + .ldo_vol_lvl = BD96801_LDO5_VOL_LVL_REG, + }, { + .desc = { + .name = "ldo6", + .of_match = of_match_ptr("ldo6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_LDO6, + .ops = &bd96801_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_ldo_int_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), + .n_voltages = BD96801_LDO_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_LDO6_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_LDO6_VSEL_REG, + .vsel_mask = BD96801_LDO_VSEL_MASK, + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&ldo6_irqinfo[0], + .num_irqs = ARRAY_SIZE(ldo6_irqinfo), + }, + .ldo_vol_lvl = BD96801_LDO6_VOL_LVL_REG, + }, { + .desc = { + .name = "ldo7", + .of_match = of_match_ptr("ldo7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_LDO7, + .ops = &bd96801_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_ldo_int_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), + .n_voltages = BD96801_LDO_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_LDO7_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_LDO7_VSEL_REG, + .vsel_mask = BD96801_LDO_VSEL_MASK, + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&ldo7_irqinfo[0], + .num_irqs = ARRAY_SIZE(ldo7_irqinfo), + }, + .ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG, + }, + }, +}; + +static int initialize_pmic_data(struct device *dev, + struct bd96801_pmic_data *pdata) +{ + int r, i; + + /* + * Allocate and initialize IRQ data for all of the regulators. We + * wish to modify IRQ information independently for each driver + * instance. + */ + for (r = 0; r < BD96801_NUM_REGULATORS; r++) { + const struct bd96801_irqinfo *template; + struct bd96801_irqinfo *new; + int num_infos; + + template = pdata->regulator_data[r].irq_desc.irqinfo; + num_infos = pdata->regulator_data[r].irq_desc.num_irqs; + + new = devm_kcalloc(dev, num_infos, sizeof(*new), GFP_KERNEL); + if (!new) + return -ENOMEM; + + pdata->regulator_data[r].irq_desc.irqinfo = new; + + for (i = 0; i < num_infos; i++) + new[i] = template[i]; + } + + return 0; +} + +static int bd96801_map_event_all(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int i; + + for (i = 0; i < rid->num_states; i++) { + rid->states[i].notifs = REGULATOR_EVENT_FAIL; + rid->states[i].errors = REGULATOR_ERROR_FAIL; + *dev_mask |= BIT(i); + } + + return 0; +} + +static int bd96801_rdev_errb_irqs(struct platform_device *pdev, + struct regulator_dev *rdev) +{ + int i; + void *retp; + static const char * const single_out_errb_irqs[] = { + "bd96801-%s-pvin-err", "bd96801-%s-ovp-err", + "bd96801-%s-uvp-err", "bd96801-%s-shdn-err", + }; + + for (i = 0; i < ARRAY_SIZE(single_out_errb_irqs); i++) { + struct regulator_irq_desc id = { + .map_event = bd96801_map_event_all, + .irq_off_ms = 1000, + }; + struct regulator_dev *rdev_arr[1]; + char tmp[255]; + int irq; + + snprintf(tmp, 255, single_out_errb_irqs[i], rdev->desc->name); + tmp[254] = 0; + id.name = tmp; + + irq = platform_get_irq_byname(pdev, tmp); + if (irq < 0) + continue; + + rdev_arr[0] = rdev; + retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0, + REGULATOR_ERROR_FAIL, NULL, + rdev_arr, 1); + if (IS_ERR(retp)) + return PTR_ERR(retp); + + } + return 0; +} + +static int bd96801_global_errb_irqs(struct platform_device *pdev, + struct regulator_dev **rdev, int num_rdev) +{ + int i, num_irqs; + void *retp; + static const char * const global_errb_irqs[] = { + "bd96801-otp-err", "bd96801-dbist-err", "bd96801-eep-err", + "bd96801-abist-err", "bd96801-prstb-err", "bd96801-drmoserr1", + "bd96801-drmoserr2", "bd96801-slave-err", "bd96801-vref-err", + "bd96801-tsd", "bd96801-uvlo-err", "bd96801-ovlo-err", + "bd96801-osc-err", "bd96801-pon-err", "bd96801-poff-err", + "bd96801-cmd-shdn-err", "bd96801-int-shdn-err" + }; + + num_irqs = ARRAY_SIZE(global_errb_irqs); + for (i = 0; i < num_irqs; i++) { + int irq; + struct regulator_irq_desc id = { + .name = global_errb_irqs[i], + .map_event = bd96801_map_event_all, + .irq_off_ms = 1000, + }; + + irq = platform_get_irq_byname(pdev, global_errb_irqs[i]); + if (irq < 0) + continue; + + retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0, + REGULATOR_ERROR_FAIL, NULL, + rdev, num_rdev); + if (IS_ERR(retp)) + return PTR_ERR(retp); + } + + return 0; +} + +static int bd96801_rdev_intb_irqs(struct platform_device *pdev, + struct bd96801_pmic_data *pdata, + struct bd96801_irqinfo *iinfo, + struct regulator_dev *rdev) +{ + struct regulator_dev *rdev_arr[1]; + void *retp; + int err = 0; + int irq; + int err_flags[] = { + [BD96801_PROT_OVP] = REGULATOR_ERROR_REGULATION_OUT, + [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE, + [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT, + [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP, + + }; + int wrn_flags[] = { + [BD96801_PROT_OVP] = REGULATOR_ERROR_OVER_VOLTAGE_WARN, + [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE_WARN, + [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT_WARN, + [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP_WARN, + }; + + /* + * Don't install IRQ handler if both error and warning + * notifications are explicitly disabled + */ + if (!iinfo->err_cfg && !iinfo->wrn_cfg) + return 0; + + if (WARN_ON(iinfo->type >= BD96801_NUM_PROT)) + return -EINVAL; + + if (iinfo->err_cfg) + err = err_flags[iinfo->type]; + else if (iinfo->wrn_cfg) + err = wrn_flags[iinfo->type]; + + iinfo->irq_desc.data = pdata; + irq = platform_get_irq_byname(pdev, iinfo->irq_name); + if (irq < 0) + return irq; + /* Find notifications for this IRQ (WARN/ERR) */ + + rdev_arr[0] = rdev; + retp = devm_regulator_irq_helper(&pdev->dev, + &iinfo->irq_desc, irq, + 0, err, NULL, rdev_arr, + 1); + if (IS_ERR(retp)) + return PTR_ERR(retp); + + return 0; +} + +static int bd96801_probe(struct platform_device *pdev) +{ + struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS]; + struct regulator_dev *all_rdevs[BD96801_NUM_REGULATORS]; + struct bd96801_regulator_data *rdesc; + struct regulator_config config = {}; + int ldo_errs_arr[BD96801_NUM_LDOS]; + struct bd96801_pmic_data *pdata; + int temp_notif_ldos = 0; + struct device *parent; + int i, ret; + bool use_errb; + void *retp; + + parent = pdev->dev.parent; + + pdata = devm_kmemdup(&pdev->dev, &bd96801_data, sizeof(bd96801_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if (initialize_pmic_data(&pdev->dev, pdata)) + return -ENOMEM; + + pdata->regmap = dev_get_regmap(parent, NULL); + if (!pdata->regmap) { + dev_err(&pdev->dev, "No register map found\n"); + return -ENODEV; + } + + rdesc = &pdata->regulator_data[0]; + + config.driver_data = pdata; + config.regmap = pdata->regmap; + config.dev = parent; + + ret = of_property_match_string(pdev->dev.parent->of_node, + "interrupt-names", "errb"); + if (ret < 0) + use_errb = false; + else + use_errb = true; + + ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc, + BD96801_NUM_REGULATORS); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(pdata->regulator_data); i++) { + struct regulator_dev *rdev; + struct bd96801_irq_desc *idesc = &rdesc[i].irq_desc; + int j; + + rdev = devm_regulator_register(&pdev->dev, + &rdesc[i].desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "failed to register %s regulator\n", + rdesc[i].desc.name); + return PTR_ERR(rdev); + } + all_rdevs[i] = rdev; + /* + * LDOs don't have own temperature monitoring. If temperature + * notification was requested for this LDO from DT then we will + * add the regulator to be notified if central IC temperature + * exceeds threshold. + */ + if (rdesc[i].ldo_errs) { + ldo_errs_rdev_arr[temp_notif_ldos] = rdev; + ldo_errs_arr[temp_notif_ldos] = rdesc[i].ldo_errs; + temp_notif_ldos++; + } + + /* Register INTB handlers for configured protections */ + for (j = 0; j < idesc->num_irqs; j++) { + ret = bd96801_rdev_intb_irqs(pdev, pdata, + &idesc->irqinfo[j], rdev); + if (ret) + return ret; + } + /* Register per regulator ERRB notifiers */ + if (use_errb) { + ret = bd96801_rdev_errb_irqs(pdev, rdev); + if (ret) + return ret; + } + } + if (temp_notif_ldos) { + int irq; + struct regulator_irq_desc tw_desc = { + .name = "bd96801-core-thermal", + .irq_off_ms = 500, + .map_event = ldo_map_notif, + }; + + irq = platform_get_irq_byname(pdev, "bd96801-core-thermal"); + if (irq < 0) + return irq; + + retp = devm_regulator_irq_helper(&pdev->dev, &tw_desc, irq, 0, + 0, &ldo_errs_arr[0], + &ldo_errs_rdev_arr[0], + temp_notif_ldos); + if (IS_ERR(retp)) + return PTR_ERR(retp); + } + + if (use_errb) + return bd96801_global_errb_irqs(pdev, all_rdevs, + ARRAY_SIZE(all_rdevs)); + + return 0; +} + +static const struct platform_device_id bd96801_pmic_id[] = { + { "bd96801-regulator", }, + { } +}; +MODULE_DEVICE_TABLE(platform, bd96801_pmic_id); + +static struct platform_driver bd96801_regulator = { + .driver = { + .name = "bd96801-pmic" + }, + .probe = bd96801_probe, + .id_table = bd96801_pmic_id, +}; + +module_platform_driver(bd96801_regulator); + +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_DESCRIPTION("BD96801 voltage regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a968dabb48f5..00a7f3617cd8 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -139,6 +139,8 @@ static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops) * once. If a task, which is calling this function is other * than the one, which initially locked the mutex, it will * wait on mutex. + * + * Return: 0 on success or a negative error number on failure. */ static inline int regulator_lock_nested(struct regulator_dev *rdev, struct ww_acquire_ctx *ww_ctx) @@ -419,72 +421,6 @@ static void regulator_lock_dependent(struct regulator_dev *rdev, mutex_unlock(®ulator_list_mutex); } -/** - * of_get_child_regulator - get a child regulator device node - * based on supply name - * @parent: Parent device node - * @prop_name: Combination regulator supply name and "-supply" - * - * Traverse all child nodes. - * Extract the child regulator device node corresponding to the supply name. - * returns the device node corresponding to the regulator if found, else - * returns NULL. - */ -static struct device_node *of_get_child_regulator(struct device_node *parent, - const char *prop_name) -{ - struct device_node *regnode = NULL; - struct device_node *child = NULL; - - for_each_child_of_node(parent, child) { - regnode = of_parse_phandle(child, prop_name, 0); - - if (!regnode) { - regnode = of_get_child_regulator(child, prop_name); - if (regnode) - goto err_node_put; - } else { - goto err_node_put; - } - } - return NULL; - -err_node_put: - of_node_put(child); - return regnode; -} - -/** - * of_get_regulator - get a regulator device node based on supply name - * @dev: Device pointer for the consumer (of regulator) device - * @supply: regulator supply name - * - * Extract the regulator device node corresponding to the supply name. - * returns the device node corresponding to the regulator if found, else - * returns NULL. - */ -static struct device_node *of_get_regulator(struct device *dev, const char *supply) -{ - struct device_node *regnode = NULL; - char prop_name[64]; /* 64 is max size of property name */ - - dev_dbg(dev, "Looking up %s-supply from device tree\n", supply); - - snprintf(prop_name, 64, "%s-supply", supply); - regnode = of_parse_phandle(dev->of_node, prop_name, 0); - - if (!regnode) { - regnode = of_get_child_regulator(dev->of_node, prop_name); - if (regnode) - return regnode; - - dev_dbg(dev, "Looking up %s property in node %pOF failed\n", - prop_name, dev->of_node); - return NULL; - } - return regnode; -} - /* Platform voltage constraint check */ int regulator_check_voltage(struct regulator_dev *rdev, int *min_uV, int *max_uV) @@ -561,7 +497,8 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, return -EPERM; } - if (*max_uA > rdev->constraints->max_uA) + if (*max_uA > rdev->constraints->max_uA && + rdev->constraints->max_uA) *max_uA = rdev->constraints->max_uA; if (*min_uA < rdev->constraints->min_uA) *min_uA = rdev->constraints->min_uA; @@ -980,6 +917,26 @@ static ssize_t bypass_show(struct device *dev, } static DEVICE_ATTR_RO(bypass); +static ssize_t power_budget_milliwatt_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", rdev->constraints->pw_budget_mW); +} +static DEVICE_ATTR_RO(power_budget_milliwatt); + +static ssize_t power_requested_milliwatt_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", rdev->pw_requested_mW); +} +static DEVICE_ATTR_RO(power_requested_milliwatt); + #define REGULATOR_ERROR_ATTR(name, bit) \ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -1212,6 +1169,10 @@ static void print_constraints_debug(struct regulator_dev *rdev) if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) count += scnprintf(buf + count, len - count, "standby "); + if (constraints->pw_budget_mW) + count += scnprintf(buf + count, len - count, "%d mW budget", + constraints->pw_budget_mW); + if (!count) count = scnprintf(buf, len, "no parameters"); else @@ -1462,6 +1423,8 @@ static int handle_notify_limits(struct regulator_dev *rdev, * Constraints *must* be set by platform code in order for some * regulator operations to proceed i.e. set_voltage, set_current_limit, * set_mode. + * + * Return: 0 on success or a negative error number on failure. */ static int set_machine_constraints(struct regulator_dev *rdev) { @@ -1688,6 +1651,9 @@ static int set_machine_constraints(struct regulator_dev *rdev) rdev->last_off = ktime_get(); } + if (!rdev->constraints->pw_budget_mW) + rdev->constraints->pw_budget_mW = INT_MAX; + print_constraints(rdev); return 0; } @@ -1700,6 +1666,8 @@ static int set_machine_constraints(struct regulator_dev *rdev) * Called by platform initialisation code to set the supply regulator for this * regulator. This ensures that a regulators supply will also be enabled by the * core if it's child is enabled. + * + * Return: 0 on success or a negative error number on failure. */ static int set_supply(struct regulator_dev *rdev, struct regulator_dev *supply_rdev) @@ -1732,6 +1700,8 @@ static int set_supply(struct regulator_dev *rdev, * sources to symbolic names for supplies for use by devices. Devices * should use these symbolic names to request regulators, avoiding the * need to provide board-specific regulator names as platform data. + * + * Return: 0 on success or a negative error number on failure. */ static int set_consumer_device_supply(struct regulator_dev *rdev, const char *consumer_dev_name, @@ -1860,12 +1830,49 @@ static const struct file_operations constraint_flags_fops = { #define REG_STR_SIZE 64 +static void link_and_create_debugfs(struct regulator *regulator, struct regulator_dev *rdev, + struct device *dev) +{ + int err = 0; + + if (dev) { + regulator->dev = dev; + + /* Add a link to the device sysfs entry */ + err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj, + regulator->supply_name); + if (err) { + rdev_dbg(rdev, "could not add device link %s: %pe\n", + dev->kobj.name, ERR_PTR(err)); + /* non-fatal */ + } + } + + if (err != -EEXIST) { + regulator->debugfs = debugfs_create_dir(regulator->supply_name, rdev->debugfs); + if (IS_ERR(regulator->debugfs)) { + rdev_dbg(rdev, "Failed to create debugfs directory\n"); + regulator->debugfs = NULL; + } + } + + if (regulator->debugfs) { + debugfs_create_u32("uA_load", 0444, regulator->debugfs, + ®ulator->uA_load); + debugfs_create_u32("min_uV", 0444, regulator->debugfs, + ®ulator->voltage[PM_SUSPEND_ON].min_uV); + debugfs_create_u32("max_uV", 0444, regulator->debugfs, + ®ulator->voltage[PM_SUSPEND_ON].max_uV); + debugfs_create_file("constraint_flags", 0444, regulator->debugfs, + regulator, &constraint_flags_fops); + } +} + static struct regulator *create_regulator(struct regulator_dev *rdev, struct device *dev, const char *supply_name) { struct regulator *regulator; - int err = 0; lockdep_assert_held_once(&rdev->mutex.base); @@ -1898,33 +1905,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, list_add(®ulator->list, &rdev->consumer_list); - if (dev) { - regulator->dev = dev; - - /* Add a link to the device sysfs entry */ - err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj, - supply_name); - if (err) { - rdev_dbg(rdev, "could not add device link %s: %pe\n", - dev->kobj.name, ERR_PTR(err)); - /* non-fatal */ - } - } - - if (err != -EEXIST) - regulator->debugfs = debugfs_create_dir(supply_name, rdev->debugfs); - if (IS_ERR(regulator->debugfs)) - rdev_dbg(rdev, "Failed to create debugfs directory\n"); - - debugfs_create_u32("uA_load", 0444, regulator->debugfs, - ®ulator->uA_load); - debugfs_create_u32("min_uV", 0444, regulator->debugfs, - ®ulator->voltage[PM_SUSPEND_ON].min_uV); - debugfs_create_u32("max_uV", 0444, regulator->debugfs, - ®ulator->voltage[PM_SUSPEND_ON].max_uV); - debugfs_create_file("constraint_flags", 0444, regulator->debugfs, - regulator, &constraint_flags_fops); - /* * Check now if the regulator is an always on regulator - if * it is then we don't need to do nearly so much work for @@ -1988,44 +1968,47 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name) return dev ? dev_to_rdev(dev) : NULL; } +static struct regulator_dev *regulator_dt_lookup(struct device *dev, + const char *supply) +{ + struct regulator_dev *r = NULL; + + if (dev_of_node(dev)) { + r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply); + if (PTR_ERR(r) == -ENODEV) + r = NULL; + } + + return r; +} + /** * regulator_dev_lookup - lookup a regulator device. * @dev: device for regulator "consumer". * @supply: Supply name or regulator ID. * + * Return: pointer to &struct regulator_dev or ERR_PTR() encoded negative error number. + * * If successful, returns a struct regulator_dev that corresponds to the name * @supply and with the embedded struct device refcount incremented by one. * The refcount must be dropped by calling put_device(). - * On failure one of the following ERR-PTR-encoded values is returned: - * -ENODEV if lookup fails permanently, -EPROBE_DEFER if lookup could succeed + * On failure one of the following ERR_PTR() encoded values is returned: + * -%ENODEV if lookup fails permanently, -%EPROBE_DEFER if lookup could succeed * in the future. */ static struct regulator_dev *regulator_dev_lookup(struct device *dev, const char *supply) { struct regulator_dev *r = NULL; - struct device_node *node; struct regulator_map *map; const char *devname = NULL; regulator_supply_alias(&dev, &supply); /* first do a dt based lookup */ - if (dev && dev->of_node) { - node = of_get_regulator(dev, supply); - if (node) { - r = of_find_regulator_by_node(node); - of_node_put(node); - if (r) - return r; - - /* - * We have a node, but there is no device. - * assume it has not registered yet. - */ - return ERR_PTR(-EPROBE_DEFER); - } - } + r = regulator_dt_lookup(dev, supply); + if (r) + return r; /* if not found, try doing it non-dt way */ if (dev) @@ -2071,7 +2054,17 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) if (rdev->supply) return 0; - r = regulator_dev_lookup(dev, rdev->supply_name); + /* first do a dt based lookup on the node described in the virtual + * device. + */ + r = regulator_dt_lookup(&rdev->dev, rdev->supply_name); + + /* If regulator not found use usual search path in the parent + * device. + */ + if (!r) + r = regulator_dev_lookup(dev, rdev->supply_name); + if (IS_ERR(r)) { ret = PTR_ERR(r); @@ -2081,6 +2074,10 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) if (have_full_constraints()) { r = dummy_regulator_rdev; + if (!r) { + ret = -EPROBE_DEFER; + goto out; + } get_device(&r->dev); } else { dev_err(dev, "Failed to resolve %s-supply for %s\n", @@ -2098,6 +2095,10 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) goto out; } r = dummy_regulator_rdev; + if (!r) { + ret = -EPROBE_DEFER; + goto out; + } get_device(&r->dev); } @@ -2145,6 +2146,9 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) regulator_unlock_two(rdev, r, &ww_ctx); + /* rdev->supply was created in set_supply() */ + link_and_create_debugfs(rdev->supply, r, &rdev->dev); + /* * In set_machine_constraints() we may have turned this regulator on * but we couldn't propagate to the supply if it hadn't been resolved @@ -2163,26 +2167,43 @@ out: return ret; } -/* Internal regulator request function */ -struct regulator *_regulator_get(struct device *dev, const char *id, - enum regulator_get_type get_type) +/* common pre-checks for regulator requests */ +int _regulator_get_common_check(struct device *dev, const char *id, + enum regulator_get_type get_type) { - struct regulator_dev *rdev; - struct regulator *regulator; - struct device_link *link; - int ret; - if (get_type >= MAX_GET_TYPE) { dev_err(dev, "invalid type %d in %s\n", get_type, __func__); - return ERR_PTR(-EINVAL); + return -EINVAL; } if (id == NULL) { - pr_err("get() with no identifier\n"); - return ERR_PTR(-EINVAL); + dev_err(dev, "regulator request with no identifier\n"); + return -EINVAL; } - rdev = regulator_dev_lookup(dev, id); + return 0; +} + +/** + * _regulator_get_common - Common code for regulator requests + * @rdev: regulator device pointer as returned by *regulator_dev_lookup() + * Its reference count is expected to have been incremented. + * @dev: device used for dev_printk messages + * @id: Supply name or regulator ID + * @get_type: enum regulator_get_type value corresponding to type of request + * + * Returns: pointer to struct regulator corresponding to @rdev, or ERR_PTR() + * encoded error. + * + * This function should be chained with *regulator_dev_lookup() functions. + */ +struct regulator *_regulator_get_common(struct regulator_dev *rdev, struct device *dev, + const char *id, enum regulator_get_type get_type) +{ + struct regulator *regulator; + struct device_link *link; + int ret; + if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); @@ -2195,7 +2216,7 @@ struct regulator *_regulator_get(struct device *dev, const char *id, if (!have_full_constraints()) { dev_warn(dev, - "incomplete constraints, dummy supplies not allowed\n"); + "incomplete constraints, dummy supplies not allowed (id=%s)\n", id); return ERR_PTR(-ENODEV); } @@ -2206,14 +2227,16 @@ struct regulator *_regulator_get(struct device *dev, const char *id, * enabled, even if it isn't hooked up, and just * provide a dummy. */ - dev_warn(dev, "supply %s not found, using dummy regulator\n", id); rdev = dummy_regulator_rdev; + if (!rdev) + return ERR_PTR(-EPROBE_DEFER); + dev_warn(dev, "supply %s not found, using dummy regulator\n", id); get_device(&rdev->dev); break; case EXCLUSIVE_GET: dev_warn(dev, - "dummy supplies not allowed for exclusive requests\n"); + "dummy supplies not allowed for exclusive requests (id=%s)\n", id); fallthrough; default: @@ -2266,6 +2289,8 @@ struct regulator *_regulator_get(struct device *dev, const char *id, return regulator; } + link_and_create_debugfs(regulator, rdev, dev); + rdev->open_count++; if (get_type == EXCLUSIVE_GET) { rdev->exclusive = 1; @@ -2274,6 +2299,17 @@ struct regulator *_regulator_get(struct device *dev, const char *id, if (ret > 0) { rdev->use_count = 1; regulator->enable_count = 1; + + /* Propagate the regulator state to its supply */ + if (rdev->supply) { + ret = regulator_enable(rdev->supply); + if (ret < 0) { + destroy_regulator(regulator); + module_put(rdev->owner); + put_device(&rdev->dev); + return ERR_PTR(ret); + } + } } else { rdev->use_count = 0; regulator->enable_count = 0; @@ -2287,18 +2323,33 @@ struct regulator *_regulator_get(struct device *dev, const char *id, return regulator; } +/* Internal regulator request function */ +struct regulator *_regulator_get(struct device *dev, const char *id, + enum regulator_get_type get_type) +{ + struct regulator_dev *rdev; + int ret; + + ret = _regulator_get_common_check(dev, id, get_type); + if (ret) + return ERR_PTR(ret); + + rdev = regulator_dev_lookup(dev, id); + return _regulator_get_common(rdev, dev, id, get_type); +} + /** * regulator_get - lookup and obtain a reference to a regulator. * @dev: device for regulator "consumer" * @id: Supply name or regulator ID. * - * Returns a struct regulator corresponding to the regulator producer, - * or IS_ERR() condition containing errno. - * * Use of supply names configured via set_consumer_device_supply() is * strongly encouraged. It is recommended that the supply name used * should match the name used for the supply and/or the relevant * device pins in the datasheet. + * + * Return: Pointer to a &struct regulator corresponding to the regulator + * producer, or an ERR_PTR() encoded negative error number. */ struct regulator *regulator_get(struct device *dev, const char *id) { @@ -2311,11 +2362,9 @@ EXPORT_SYMBOL_GPL(regulator_get); * @dev: device for regulator "consumer" * @id: Supply name or regulator ID. * - * Returns a struct regulator corresponding to the regulator producer, - * or IS_ERR() condition containing errno. Other consumers will be - * unable to obtain this regulator while this reference is held and the - * use count for the regulator will be initialised to reflect the current - * state of the regulator. + * Other consumers will be unable to obtain this regulator while this + * reference is held and the use count for the regulator will be + * initialised to reflect the current state of the regulator. * * This is intended for use by consumers which cannot tolerate shared * use of the regulator such as those which need to force the @@ -2326,6 +2375,9 @@ EXPORT_SYMBOL_GPL(regulator_get); * strongly encouraged. It is recommended that the supply name used * should match the name used for the supply and/or the relevant * device pins in the datasheet. + * + * Return: Pointer to a &struct regulator corresponding to the regulator + * producer, or an ERR_PTR() encoded negative error number. */ struct regulator *regulator_get_exclusive(struct device *dev, const char *id) { @@ -2338,9 +2390,6 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive); * @dev: device for regulator "consumer" * @id: Supply name or regulator ID. * - * Returns a struct regulator corresponding to the regulator producer, - * or IS_ERR() condition containing errno. - * * This is intended for use by consumers for devices which can have * some supplies unconnected in normal use, such as some MMC devices. * It can allow the regulator core to provide stub supplies for other @@ -2352,6 +2401,9 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive); * strongly encouraged. It is recommended that the supply name used * should match the name used for the supply and/or the relevant * device pins in the datasheet. + * + * Return: Pointer to a &struct regulator corresponding to the regulator + * producer, or an ERR_PTR() encoded negative error number. */ struct regulator *regulator_get_optional(struct device *dev, const char *id) { @@ -2432,6 +2484,8 @@ EXPORT_SYMBOL_GPL(regulator_put); * * All lookups for id on dev will instead be conducted for alias_id on * alias_dev. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_register_supply_alias(struct device *dev, const char *id, struct device *alias_dev, @@ -2491,12 +2545,12 @@ EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); * lookup the supply * @num_id: Number of aliases to register * - * @return 0 on success, an errno on failure. - * * This helper function allows drivers to register several supply * aliases in one operation. If any of the aliases cannot be * registered any aliases that were registered will be removed * before returning to the caller. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_bulk_register_supply_alias(struct device *dev, const char *const *id, @@ -2621,6 +2675,8 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev) * * GPIO is enabled in case of initial use. (enable_count is 0) * GPIO is disabled when it is not shared any more. (enable_count <= 1) + * + * Return: 0 on success or a negative error number on failure. */ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) { @@ -2652,49 +2708,8 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) } /** - * _regulator_delay_helper - a delay helper function - * @delay: time to delay in microseconds - * - * Delay for the requested amount of time as per the guidelines in: - * - * Documentation/timers/timers-howto.rst - * - * The assumption here is that these regulator operations will never used in - * atomic context and therefore sleeping functions can be used. - */ -static void _regulator_delay_helper(unsigned int delay) -{ - unsigned int ms = delay / 1000; - unsigned int us = delay % 1000; - - if (ms > 0) { - /* - * For small enough values, handle super-millisecond - * delays in the usleep_range() call below. - */ - if (ms < 20) - us += ms * 1000; - else - msleep(ms); - } - - /* - * Give the scheduler some room to coalesce with any other - * wakeup sources. For delays shorter than 10 us, don't even - * bother setting up high-resolution timers and just busy- - * loop. - */ - if (us >= 10) - usleep_range(us, us + 100); - else - udelay(us); -} - -/** - * _regulator_check_status_enabled - * - * A helper function to check if the regulator status can be interpreted - * as 'regulator is enabled'. + * _regulator_check_status_enabled - check if regulator status can be + * interpreted as "regulator is enabled" * @rdev: the regulator device to check * * Return: @@ -2744,7 +2759,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) s64 remaining = ktime_us_delta(end, ktime_get_boottime()); if (remaining > 0) - _regulator_delay_helper(remaining); + fsleep(remaining); } if (rdev->ena_pin) { @@ -2778,7 +2793,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) int time_remaining = delay; while (time_remaining > 0) { - _regulator_delay_helper(rdev->desc->poll_enabled_time); + fsleep(rdev->desc->poll_enabled_time); if (rdev->desc->ops->get_status) { ret = _regulator_check_status_enabled(rdev); @@ -2797,7 +2812,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) return -ETIMEDOUT; } } else { - _regulator_delay_helper(delay); + fsleep(delay); } trace_regulator_enable_complete(rdev_get_name(rdev)); @@ -2823,7 +2838,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) * responsible for keeping track of the refcount for a given regulator consumer * and applying / unapplying these things. * - * Returns 0 upon no error; -error upon error. + * Return: 0 on success or negative error number on failure. */ static int _regulator_handle_consumer_enable(struct regulator *regulator) { @@ -2849,7 +2864,7 @@ static int _regulator_handle_consumer_enable(struct regulator *regulator) * * The opposite of _regulator_handle_consumer_enable(). * - * Returns 0 upon no error; -error upon error. + * Return: 0 on success or a negative error number on failure. */ static int _regulator_handle_consumer_disable(struct regulator *regulator) { @@ -2945,6 +2960,8 @@ err_disable_supply: * * NOTE: the output value can be set by other drivers, boot loader or may be * hardwired in the regulator. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_enable(struct regulator *regulator) { @@ -3055,6 +3072,8 @@ static int _regulator_disable(struct regulator *regulator) * NOTE: this will only disable the regulator output if no other consumer * devices have it enabled, the regulator device supports disabling and * machine constraints permit this operation. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_disable(struct regulator *regulator) { @@ -3104,6 +3123,8 @@ static int _regulator_force_disable(struct regulator_dev *rdev) * NOTE: this *will* disable the regulator output even if other consumer * devices have it enabled. This should be used for situations when device * damage will likely occur if the regulator is not disabled (e.g. over temp). + * + * Return: 0 on success or a negative error number on failure. */ int regulator_force_disable(struct regulator *regulator) { @@ -3186,6 +3207,8 @@ static void regulator_disable_work(struct work_struct *work) * NOTE: this will only disable the regulator output if no other consumer * devices have it enabled, the regulator device supports disabling and * machine constraints permit this operation. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_disable_deferred(struct regulator *regulator, int ms) { @@ -3257,13 +3280,13 @@ static int _regulator_list_voltage(struct regulator_dev *rdev, * regulator_is_enabled - is the regulator output enabled * @regulator: regulator source * - * Returns positive if the regulator driver backing the source/client - * has requested that the device be enabled, zero if it hasn't, else a - * negative errno code. - * * Note that the device backing this regulator handle can have multiple * users, so it might be enabled even if regulator_enable() was never * called for this particular source. + * + * Return: Positive if the regulator driver backing the source/client + * has requested that the device be enabled, zero if it hasn't, + * else a negative error number. */ int regulator_is_enabled(struct regulator *regulator) { @@ -3284,9 +3307,10 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled); * regulator_count_voltages - count regulator_list_voltage() selectors * @regulator: regulator source * - * Returns number of selectors, or negative errno. Selectors are - * numbered starting at zero, and typically correspond to bitfields - * in hardware registers. + * Return: Number of selectors for @regulator, or negative error number. + * + * Selectors are numbered starting at zero, and typically correspond to + * bitfields in hardware registers. */ int regulator_count_voltages(struct regulator *regulator) { @@ -3308,9 +3332,9 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages); * @selector: identify voltage to list * Context: can sleep * - * Returns a voltage that can be passed to @regulator_set_voltage(), - * zero if this selector code can't be used on this system, or a - * negative errno. + * Return: Voltage for @selector that can be passed to regulator_set_voltage(), + * 0 if @selector can't be used on this system, or a negative error + * number on failure. */ int regulator_list_voltage(struct regulator *regulator, unsigned selector) { @@ -3322,8 +3346,8 @@ EXPORT_SYMBOL_GPL(regulator_list_voltage); * regulator_get_regmap - get the regulator's register map * @regulator: regulator source * - * Returns the register map for the given regulator, or an ERR_PTR value - * if the regulator doesn't use regmap. + * Return: Pointer to the &struct regmap for @regulator, or ERR_PTR() + * encoded -%EOPNOTSUPP if @regulator doesn't use regmap. */ struct regmap *regulator_get_regmap(struct regulator *regulator) { @@ -3331,6 +3355,7 @@ struct regmap *regulator_get_regmap(struct regulator *regulator) return map ? map : ERR_PTR(-EOPNOTSUPP); } +EXPORT_SYMBOL_GPL(regulator_get_regmap); /** * regulator_get_hardware_vsel_register - get the HW voltage selector register @@ -3343,8 +3368,11 @@ struct regmap *regulator_get_regmap(struct regulator *regulator) * hardware or firmware that can make I2C requests behind the kernel's back, * for example. * + * Return: 0 on success, or -%EOPNOTSUPP if the regulator does not support + * voltage selectors. + * * On success, the output parameters @vsel_reg and @vsel_mask are filled in - * and 0 is returned, otherwise a negative errno is returned. + * and 0 is returned, otherwise a negative error number is returned. */ int regulator_get_hardware_vsel_register(struct regulator *regulator, unsigned *vsel_reg, @@ -3372,7 +3400,9 @@ EXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register); * directly written to the regulator registers. The address of the voltage * register can be determined by calling @regulator_get_hardware_vsel_register. * - * On error a negative errno is returned. + * Return: 0 on success, -%EINVAL if the selector is outside the supported + * range, or -%EOPNOTSUPP if the regulator does not support voltage + * selectors. */ int regulator_list_hardware_vsel(struct regulator *regulator, unsigned selector) @@ -3392,11 +3422,39 @@ int regulator_list_hardware_vsel(struct regulator *regulator, EXPORT_SYMBOL_GPL(regulator_list_hardware_vsel); /** + * regulator_hardware_enable - access the HW for enable/disable regulator + * @regulator: regulator source + * @enable: true for enable, false for disable + * + * Request that the regulator be enabled/disabled with the regulator output at + * the predefined voltage or current value. + * + * Return: 0 on success or a negative error number on failure. + */ +int regulator_hardware_enable(struct regulator *regulator, bool enable) +{ + struct regulator_dev *rdev = regulator->rdev; + const struct regulator_ops *ops = rdev->desc->ops; + int ret = -EOPNOTSUPP; + + if (!rdev->exclusive || !ops || !ops->enable || !ops->disable) + return ret; + + if (enable) + ret = ops->enable(rdev); + else + ret = ops->disable(rdev); + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_hardware_enable); + +/** * regulator_get_linear_step - return the voltage step size between VSEL values * @regulator: regulator source * - * Returns the voltage step size between VSEL values for linear - * regulators, or return 0 if the regulator isn't a linear regulator. + * Return: The voltage step size between VSEL values for linear regulators, + * or 0 if the regulator isn't a linear regulator. */ unsigned int regulator_get_linear_step(struct regulator *regulator) { @@ -3413,7 +3471,9 @@ EXPORT_SYMBOL_GPL(regulator_get_linear_step); * @min_uV: Minimum required voltage in uV. * @max_uV: Maximum required voltage in uV. * - * Returns a boolean. + * Return: 1 if the voltage range is supported, 0 if not, or a negative error + * number if @regulator's voltage can't be changed and voltage readback + * failed. */ int regulator_is_supported_voltage(struct regulator *regulator, int min_uV, int max_uV) @@ -3696,7 +3756,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, } /* Insert any necessary delays */ - _regulator_delay_helper(delay); + fsleep(delay); if (best_val >= 0) { unsigned long data = best_val; @@ -3932,7 +3992,6 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, if (ret < 0) return ret; - possible_uV = desired_min_uV; done = true; goto finish; @@ -4166,6 +4225,8 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, * request voltage that meets the system constraints will be used. * Regulator system constraints must be set for this regulator before * calling this function otherwise this call will fail. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { @@ -4276,6 +4337,8 @@ EXPORT_SYMBOL_GPL(regulator_set_suspend_voltage); * Provided with the starting and ending voltage, this function attempts to * calculate the time in microseconds required to rise or fall to this new * voltage. + * + * Return: ramp time in microseconds, or a negative error number if calculation failed. */ int regulator_set_voltage_time(struct regulator *regulator, int old_uV, int new_uV) @@ -4333,6 +4396,8 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage_time); * * Drivers providing ramp_delay in regulation_constraints can use this as their * set_voltage_time_sel() operation. + * + * Return: ramp time in microseconds, or a negative error number if calculation failed. */ int regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_selector, @@ -4385,6 +4450,8 @@ out: * Re-apply the last configured voltage. This is intended to be used * where some external control source the consumer is cooperating with * has caused the configured voltage to change. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_sync_voltage(struct regulator *regulator) { @@ -4483,7 +4550,7 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage_rdev); * regulator_get_voltage - get regulator output voltage * @regulator: regulator source * - * This returns the current regulator voltage in uV. + * Return: Current regulator voltage in uV, or a negative error number on failure. * * NOTE: If the regulator is disabled it will return the voltage value. This * function should not be used to determine regulator state. @@ -4516,6 +4583,8 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage); * * NOTE: Regulator system constraints must be set for this regulator before * calling this function otherwise this call will fail. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_set_current_limit(struct regulator *regulator, int min_uA, int max_uA) @@ -4567,7 +4636,8 @@ static int _regulator_get_current_limit(struct regulator_dev *rdev) * regulator_get_current_limit - get regulator output current * @regulator: regulator source * - * This returns the current supplied by the specified current sink in uA. + * Return: Current supplied by the specified current sink in uA, + * or a negative error number on failure. * * NOTE: If the regulator is disabled it will return the current value. This * function should not be used to determine regulator state. @@ -4579,6 +4649,87 @@ int regulator_get_current_limit(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_get_current_limit); /** + * regulator_get_unclaimed_power_budget - get regulator unclaimed power budget + * @regulator: regulator source + * + * Return: Unclaimed power budget of the regulator in mW. + */ +int regulator_get_unclaimed_power_budget(struct regulator *regulator) +{ + return regulator->rdev->constraints->pw_budget_mW - + regulator->rdev->pw_requested_mW; +} +EXPORT_SYMBOL_GPL(regulator_get_unclaimed_power_budget); + +/** + * regulator_request_power_budget - request power budget on a regulator + * @regulator: regulator source + * @pw_req: Power requested + * + * Return: 0 on success or a negative error number on failure. + */ +int regulator_request_power_budget(struct regulator *regulator, + unsigned int pw_req) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret = 0, pw_tot_req; + + regulator_lock(rdev); + if (rdev->supply) { + ret = regulator_request_power_budget(rdev->supply, pw_req); + if (ret < 0) + goto out; + } + + pw_tot_req = rdev->pw_requested_mW + pw_req; + if (pw_tot_req > rdev->constraints->pw_budget_mW) { + rdev_warn(rdev, "power requested %d mW out of budget %d mW", + pw_req, + rdev->constraints->pw_budget_mW - rdev->pw_requested_mW); + regulator_notifier_call_chain(rdev, + REGULATOR_EVENT_OVER_CURRENT_WARN, + NULL); + ret = -ERANGE; + goto out; + } + + rdev->pw_requested_mW = pw_tot_req; +out: + regulator_unlock(rdev); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_request_power_budget); + +/** + * regulator_free_power_budget - free power budget on a regulator + * @regulator: regulator source + * @pw: Power to be released. + * + * Return: Power budget of the regulator in mW. + */ +void regulator_free_power_budget(struct regulator *regulator, + unsigned int pw) +{ + struct regulator_dev *rdev = regulator->rdev; + int pw_tot_req; + + regulator_lock(rdev); + if (rdev->supply) + regulator_free_power_budget(rdev->supply, pw); + + pw_tot_req = rdev->pw_requested_mW - pw; + if (pw_tot_req >= 0) + rdev->pw_requested_mW = pw_tot_req; + else + rdev_warn(rdev, + "too much power freed %d mW (already requested %d mW)", + pw, rdev->pw_requested_mW); + + regulator_unlock(rdev); +} +EXPORT_SYMBOL_GPL(regulator_free_power_budget); + +/** * regulator_set_mode - set regulator operating mode * @regulator: regulator source * @mode: operating mode - one of the REGULATOR_MODE constants @@ -4588,6 +4739,8 @@ EXPORT_SYMBOL_GPL(regulator_get_current_limit); * * NOTE: Regulator system constraints must be set for this regulator before * calling this function otherwise this call will fail. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_set_mode(struct regulator *regulator, unsigned int mode) { @@ -4649,6 +4802,9 @@ static unsigned int _regulator_get_mode(struct regulator_dev *rdev) * @regulator: regulator source * * Get the current regulator operating mode. + * + * Return: Current operating mode as %REGULATOR_MODE_* values, + * or a negative error number on failure. */ unsigned int regulator_get_mode(struct regulator *regulator) { @@ -4695,6 +4851,8 @@ static int _regulator_get_error_flags(struct regulator_dev *rdev, * @flags: pointer to store error flags * * Get the current regulator error information. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_get_error_flags(struct regulator *regulator, unsigned int *flags) @@ -4735,7 +4893,7 @@ EXPORT_SYMBOL_GPL(regulator_get_error_flags); * If a regulator is an always-on regulator then an individual consumer's * load will still be removed if that consumer is fully disabled. * - * On error a negative errno is returned. + * Return: 0 on success or a negative error number on failure. */ int regulator_set_load(struct regulator *regulator, int uA_load) { @@ -4767,6 +4925,9 @@ EXPORT_SYMBOL_GPL(regulator_set_load); * for the regulator also enable bypass mode and the machine * constraints allow this. Bypass mode means that the regulator is * simply passing the input directly to the output with no regulation. + * + * Return: 0 on success or if changing bypass is not possible, or + * a negative error number on failure. */ int regulator_allow_bypass(struct regulator *regulator, bool enable) { @@ -4824,6 +4985,8 @@ EXPORT_SYMBOL_GPL(regulator_allow_bypass); * @nb: notifier block * * Register notifier block to receive regulator events. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb) @@ -4839,6 +5002,8 @@ EXPORT_SYMBOL_GPL(regulator_register_notifier); * @nb: notifier block * * Unregister regulator event notifier block. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_unregister_notifier(struct regulator *regulator, struct notifier_block *nb) @@ -4888,7 +5053,7 @@ int _regulator_bulk_get(struct device *dev, int num_consumers, consumers[i].supply, get_type); if (IS_ERR(consumers[i].consumer)) { ret = dev_err_probe(dev, PTR_ERR(consumers[i].consumer), - "Failed to get supply '%s'", + "Failed to get supply '%s'\n", consumers[i].supply); consumers[i].consumer = NULL; goto err; @@ -4920,12 +5085,12 @@ err: * @num_consumers: Number of consumers to register * @consumers: Configuration of consumers; clients are stored here. * - * @return 0 on success, an errno on failure. - * * This helper function allows drivers to get several regulator * consumers in one operation. If any of the regulators cannot be * acquired then any regulators that were allocated will be freed * before returning to the caller. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_bulk_get(struct device *dev, int num_consumers, struct regulator_bulk_data *consumers) @@ -4946,12 +5111,13 @@ static void regulator_bulk_enable_async(void *data, async_cookie_t cookie) * * @num_consumers: Number of consumers * @consumers: Consumer data; clients are stored here. - * @return 0 on success, an errno on failure * * This convenience API allows consumers to enable multiple regulator * clients in a single API call. If any consumers cannot be enabled * then any others that were enabled will be disabled again prior to * return. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_bulk_enable(int num_consumers, struct regulator_bulk_data *consumers) @@ -4995,12 +5161,13 @@ EXPORT_SYMBOL_GPL(regulator_bulk_enable); * * @num_consumers: Number of consumers * @consumers: Consumer data; clients are stored here. - * @return 0 on success, an errno on failure * * This convenience API allows consumers to disable multiple regulator * clients in a single API call. If any consumers cannot be disabled * then any others that were disabled will be enabled again prior to * return. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_bulk_disable(int num_consumers, struct regulator_bulk_data *consumers) @@ -5034,7 +5201,6 @@ EXPORT_SYMBOL_GPL(regulator_bulk_disable); * * @num_consumers: Number of consumers * @consumers: Consumer data; clients are stored here. - * @return 0 on success, an errno on failure * * This convenience API allows consumers to forcibly disable multiple regulator * clients in a single API call. @@ -5042,6 +5208,8 @@ EXPORT_SYMBOL_GPL(regulator_bulk_disable); * likely occur if the regulators are not disabled (e.g. over temp). * Although regulator_force_disable function call for some consumers can * return error numbers, the function is called for all consumers. + * + * Return: 0 on success or a negative error number on failure. */ int regulator_bulk_force_disable(int num_consumers, struct regulator_bulk_data *consumers) @@ -5126,6 +5294,8 @@ static void regulator_handle_critical(struct regulator_dev *rdev, * * Called by regulator drivers to notify clients a regulator event has * occurred. + * + * Return: %NOTIFY_DONE. */ int regulator_notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data) @@ -5144,6 +5314,8 @@ EXPORT_SYMBOL_GPL(regulator_notifier_call_chain); * @mode: Mode to convert * * Convert a regulator mode into a status. + * + * Return: %REGULATOR_STATUS_* value corresponding to given mode. */ int regulator_mode_to_status(unsigned int mode) { @@ -5195,6 +5367,8 @@ static struct attribute *regulator_dev_attrs[] = { &dev_attr_suspend_standby_mode.attr, &dev_attr_suspend_mem_mode.attr, &dev_attr_suspend_disk_mode.attr, + &dev_attr_power_budget_milliwatt.attr, + &dev_attr_power_requested_milliwatt.attr, NULL }; @@ -5276,6 +5450,10 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj, attr == &dev_attr_suspend_disk_mode.attr) return ops->set_suspend_mode ? mode : 0; + if (attr == &dev_attr_power_budget_milliwatt.attr || + attr == &dev_attr_power_requested_milliwatt.attr) + return rdev->constraints->pw_budget_mW != INT_MAX ? mode : 0; + return mode; } @@ -5538,8 +5716,9 @@ static struct regulator_coupler generic_regulator_coupler = { * @cfg: runtime configuration for regulator * * Called by regulator drivers to register a regulator. - * Returns a valid pointer to struct regulator_dev on success - * or an ERR_PTR() on error. + * + * Return: Pointer to a valid &struct regulator_dev on success or + * an ERR_PTR() encoded negative error number on failure. */ struct regulator_dev * regulator_register(struct device *dev, @@ -5615,6 +5794,10 @@ regulator_register(struct device *dev, goto clean; } + /* + * DT may override the config->init_data provided if the platform + * needs to do so. If so, config->init_data is completely ignored. + */ init_data = regulator_of_get_init_data(dev, regulator_desc, config, &rdev->dev.of_node); @@ -5681,6 +5864,12 @@ regulator_register(struct device *dev, goto wash; } + if (regulator_desc->init_cb) { + ret = regulator_desc->init_cb(rdev, config); + if (ret < 0) + goto wash; + } + if ((rdev->supply_name && !rdev->supply) && (rdev->constraints->always_on || rdev->constraints->boot_on)) { @@ -5692,13 +5881,6 @@ regulator_register(struct device *dev, resolved_early = true; } - /* perform any regulator specific init */ - if (init_data && init_data->regulator_init) { - ret = init_data->regulator_init(rdev->reg_data); - if (ret < 0) - goto wash; - } - if (config->ena_gpiod) { ret = regulator_ena_gpio_request(rdev, config); if (ret != 0) { @@ -5833,6 +6015,8 @@ EXPORT_SYMBOL_GPL(regulator_unregister); * @dev: ``&struct device`` pointer that is passed to _regulator_suspend() * * Configure each regulator with it's suspend operating parameters for state. + * + * Return: 0 on success or a negative error number on failure. */ static int regulator_suspend(struct device *dev) { @@ -5891,7 +6075,7 @@ static const struct dev_pm_ops __maybe_unused regulator_pm_ops = { }; #endif -struct class regulator_class = { +const struct class regulator_class = { .name = "regulator", .dev_release = regulator_dev_release, .dev_groups = regulator_dev_groups, @@ -5922,6 +6106,8 @@ EXPORT_SYMBOL_GPL(regulator_has_full_constraints); * * Get rdev regulator driver private data. This call can be used in the * regulator driver context. + * + * Return: Pointer to regulator driver private data. */ void *rdev_get_drvdata(struct regulator_dev *rdev) { @@ -5935,6 +6121,8 @@ EXPORT_SYMBOL_GPL(rdev_get_drvdata); * * Get regulator driver private data. This call can be used in the consumer * driver context when non API regulator specific functions need to be called. + * + * Return: Pointer to regulator driver private data. */ void *regulator_get_drvdata(struct regulator *regulator) { @@ -5956,6 +6144,8 @@ EXPORT_SYMBOL_GPL(regulator_set_drvdata); /** * rdev_get_id - get regulator ID * @rdev: regulator + * + * Return: Regulator ID for @rdev. */ int rdev_get_id(struct regulator_dev *rdev) { diff --git a/drivers/regulator/da903x-regulator.c b/drivers/regulator/da903x-regulator.c index f79337079a45..2f85897183b3 100644 --- a/drivers/regulator/da903x-regulator.c +++ b/drivers/regulator/da903x-regulator.c @@ -61,7 +61,7 @@ #define DA9034_MDTV2 (0x33) #define DA9034_MVRC (0x34) -/* DA9035 Registers. DA9034 Registers are comptabile to DA9035. */ +/* DA9035 Registers. DA9034 Registers are compatible to DA9035. */ #define DA9035_OVER3 (0x12) #define DA9035_VCC2 (0x1f) #define DA9035_3DTV1 (0x2c) diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index ab6f5d61b173..fbebe538a648 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -67,11 +67,11 @@ struct da9052_regulator_info { struct da9052_regulator { struct da9052 *da9052; - struct da9052_regulator_info *info; + const struct da9052_regulator_info *info; struct regulator_dev *rdev; }; -static int verify_range(struct da9052_regulator_info *info, +static int verify_range(const struct da9052_regulator_info *info, int min_uV, int max_uV) { if (min_uV > info->max_uV || max_uV < info->min_uV) @@ -151,7 +151,7 @@ static int da9052_list_voltage(struct regulator_dev *rdev, unsigned int selector) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; + const struct da9052_regulator_info *info = regulator->info; int id = rdev_get_id(rdev); int volt_uV; @@ -175,7 +175,7 @@ static int da9052_map_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; + const struct da9052_regulator_info *info = regulator->info; int id = rdev_get_id(rdev); int ret, sel; @@ -206,7 +206,7 @@ static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; + const struct da9052_regulator_info *info = regulator->info; int id = rdev_get_id(rdev); int ret; @@ -237,7 +237,7 @@ static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int new_sel) { struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; + const struct da9052_regulator_info *info = regulator->info; int id = rdev_get_id(rdev); int ret = 0; @@ -327,7 +327,7 @@ static const struct regulator_ops da9052_ldo_ops = { .activate_bit = (abits),\ } -static struct da9052_regulator_info da9052_regulator_info[] = { +static const struct da9052_regulator_info da9052_regulator_info[] = { DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), @@ -344,7 +344,7 @@ static struct da9052_regulator_info da9052_regulator_info[] = { DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), }; -static struct da9052_regulator_info da9053_regulator_info[] = { +static const struct da9052_regulator_info da9053_regulator_info[] = { DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), @@ -361,10 +361,10 @@ static struct da9052_regulator_info da9053_regulator_info[] = { DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), }; -static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, - int id) +static inline const struct da9052_regulator_info *find_regulator_info(u8 chip_id, + int id) { - struct da9052_regulator_info *info; + const struct da9052_regulator_info *info; int i; switch (chip_id) { diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 8fd9ac787588..a0d3414aa79e 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> @@ -74,7 +73,7 @@ struct da9055_regulator_info { struct da9055_regulator { struct da9055 *da9055; - struct da9055_regulator_info *info; + const struct da9055_regulator_info *info; struct regulator_dev *rdev; enum gpio_select reg_rselect; }; @@ -82,7 +81,7 @@ struct da9055_regulator { static unsigned int da9055_buck_get_mode(struct regulator_dev *rdev) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; int ret, mode = 0; ret = da9055_reg_read(regulator->da9055, info->mode.reg); @@ -108,7 +107,7 @@ static int da9055_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; int val = 0; switch (mode) { @@ -130,7 +129,7 @@ static int da9055_buck_set_mode(struct regulator_dev *rdev, static unsigned int da9055_ldo_get_mode(struct regulator_dev *rdev) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; int ret; ret = da9055_reg_read(regulator->da9055, info->volt.reg_b); @@ -146,7 +145,7 @@ static unsigned int da9055_ldo_get_mode(struct regulator_dev *rdev) static int da9055_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; struct da9055_volt_reg volt = info->volt; int val = 0; @@ -168,7 +167,7 @@ static int da9055_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) static int da9055_regulator_get_voltage_sel(struct regulator_dev *rdev) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; struct da9055_volt_reg volt = info->volt; int ret, sel; @@ -200,7 +199,7 @@ static int da9055_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; int ret; /* @@ -243,7 +242,7 @@ static int da9055_regulator_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; int ret; /* Select register set B for suspend voltage ramping. */ @@ -265,7 +264,7 @@ static int da9055_regulator_set_suspend_voltage(struct regulator_dev *rdev, static int da9055_suspend_enable(struct regulator_dev *rdev) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; /* Select register set B for voltage ramping. */ if (regulator->reg_rselect == NO_GPIO) @@ -278,7 +277,7 @@ static int da9055_suspend_enable(struct regulator_dev *rdev) static int da9055_suspend_disable(struct regulator_dev *rdev) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; /* Diselect register set B. */ if (regulator->reg_rselect == NO_GPIO) @@ -397,7 +396,7 @@ static const struct regulator_ops da9055_ldo_ops = { },\ } -static struct da9055_regulator_info da9055_regulator_info[] = { +static const struct da9055_regulator_info da9055_regulator_info[] = { DA9055_BUCK(BUCK1, 25, 725, 2075, 6, 9, 0xc, 2), DA9055_BUCK(BUCK2, 25, 925, 2500, 6, 0, 3, 0), DA9055_LDO(LDO1, 50, 900, 3300, 6, 2), @@ -413,31 +412,35 @@ static struct da9055_regulator_info da9055_regulator_info[] = { * GPIO can control regulator state and/or select the regulator register * set A/B for voltage ramping. */ -static int da9055_gpio_init(struct da9055_regulator *regulator, +static int da9055_gpio_init(struct device *dev, + struct da9055_regulator *regulator, struct regulator_config *config, struct da9055_pdata *pdata, int id) { - struct da9055_regulator_info *info = regulator->info; + const struct da9055_regulator_info *info = regulator->info; + struct gpio_desc *ren; + struct gpio_desc *ena; + struct gpio_desc *rsel; int ret = 0; - if (!pdata) - return 0; + /* Look for "regulator-enable-gpios" GPIOs in the regulator node */ + ren = devm_gpiod_get_optional(dev, "regulator-enable", GPIOD_IN); + if (IS_ERR(ren)) + return PTR_ERR(ren); - if (pdata->gpio_ren && pdata->gpio_ren[id]) { - char name[18]; - int gpio_mux = pdata->gpio_ren[id]; + if (ren) { + /* This GPIO is not optional at this point */ + ena = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(ena)) + return PTR_ERR(ena); - config->ena_gpiod = pdata->ena_gpiods[id]; + config->ena_gpiod = ena; /* * GPI pin is muxed with regulator to control the * regulator state. */ - sprintf(name, "DA9055 GPI %d", gpio_mux); - ret = devm_gpio_request_one(config->dev, gpio_mux, GPIOF_DIR_IN, - name); - if (ret < 0) - goto err; + gpiod_set_consumer_name(ren, "DA9055 ren GPI"); /* * Let the regulator know that its state is controlled @@ -448,24 +451,22 @@ static int da9055_gpio_init(struct da9055_regulator *regulator, pdata->reg_ren[id] << DA9055_E_GPI_SHIFT); if (ret < 0) - goto err; + return ret; } - if (pdata->gpio_rsel && pdata->gpio_rsel[id]) { - char name[18]; - int gpio_mux = pdata->gpio_rsel[id]; + /* Look for "regulator-select-gpios" GPIOs in the regulator node */ + rsel = devm_gpiod_get_optional(dev, "regulator-select", GPIOD_IN); + if (IS_ERR(rsel)) + return PTR_ERR(rsel); + if (rsel) { regulator->reg_rselect = pdata->reg_rsel[id]; /* * GPI pin is muxed with regulator to select the * regulator register set A/B for voltage ramping. */ - sprintf(name, "DA9055 GPI %d", gpio_mux); - ret = devm_gpio_request_one(config->dev, gpio_mux, GPIOF_DIR_IN, - name); - if (ret < 0) - goto err; + gpiod_set_consumer_name(rsel, "DA9055 rsel GPI"); /* * Let the regulator know that its register set A/B @@ -477,7 +478,6 @@ static int da9055_gpio_init(struct da9055_regulator *regulator, << DA9055_V_GPI_SHIFT); } -err: return ret; } @@ -491,9 +491,9 @@ static irqreturn_t da9055_ldo5_6_oc_irq(int irq, void *data) return IRQ_HANDLED; } -static inline struct da9055_regulator_info *find_regulator_info(int id) +static inline const struct da9055_regulator_info *find_regulator_info(int id) { - struct da9055_regulator_info *info; + const struct da9055_regulator_info *info; int i; for (i = 0; i < ARRAY_SIZE(da9055_regulator_info); i++) { @@ -532,7 +532,7 @@ static int da9055_regulator_probe(struct platform_device *pdev) if (pdata) config.init_data = pdata->regulators[pdev->id]; - ret = da9055_gpio_init(regulator, &config, pdata, pdev->id); + ret = da9055_gpio_init(&pdev->dev, regulator, &config, pdata, pdev->id); if (ret < 0) return ret; diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 82bf321ae06f..9d369cc45d41 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -133,7 +133,7 @@ struct da9063_regulator_info { .suspend_vsel_reg = DA9063_REG_V##regl_name##_B, \ .mode = BFIELD(DA9063_REG_##regl_name##_CFG, DA9063_BUCK_MODE_MASK) -/* Defines asignment of regulators info table to chip model */ +/* Defines assignment of regulators info table to chip model */ struct da9063_dev_model { const struct da9063_regulator_info *regulator_info; unsigned int n_regulators; @@ -715,7 +715,7 @@ static const struct da9063_regulator_info da9063_regulator_info[] = { }; /* Link chip model with regulators info table */ -static struct da9063_dev_model regulators_models[] = { +static const struct da9063_dev_model regulators_models[] = { { .regulator_info = da9063_regulator_info, .n_regulators = ARRAY_SIZE(da9063_regulator_info), diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index b551a400bdd1..17527a3f53b4 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -14,7 +14,6 @@ // Copyright (C) 2020 Dialog Semiconductor #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/gpio/consumer.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/machine.h> @@ -54,7 +53,7 @@ struct da9121_range { int reg_max; }; -static struct da9121_range da9121_10A_2phase_current = { +static const struct da9121_range da9121_10A_2phase_current = { .val_min = 7000000, .val_max = 20000000, .val_stp = 1000000, @@ -62,7 +61,7 @@ static struct da9121_range da9121_10A_2phase_current = { .reg_max = 14, }; -static struct da9121_range da9121_6A_2phase_current = { +static const struct da9121_range da9121_6A_2phase_current = { .val_min = 7000000, .val_max = 12000000, .val_stp = 1000000, @@ -70,7 +69,7 @@ static struct da9121_range da9121_6A_2phase_current = { .reg_max = 6, }; -static struct da9121_range da9121_5A_1phase_current = { +static const struct da9121_range da9121_5A_1phase_current = { .val_min = 3500000, .val_max = 10000000, .val_stp = 500000, @@ -78,7 +77,7 @@ static struct da9121_range da9121_5A_1phase_current = { .reg_max = 14, }; -static struct da9121_range da9121_3A_1phase_current = { +static const struct da9121_range da9121_3A_1phase_current = { .val_min = 3500000, .val_max = 6000000, .val_stp = 500000, @@ -86,7 +85,7 @@ static struct da9121_range da9121_3A_1phase_current = { .reg_max = 6, }; -static struct da9121_range da914x_40A_4phase_current = { +static const struct da9121_range da914x_40A_4phase_current = { .val_min = 26000000, .val_max = 78000000, .val_stp = 4000000, @@ -94,7 +93,7 @@ static struct da9121_range da914x_40A_4phase_current = { .reg_max = 14, }; -static struct da9121_range da914x_20A_2phase_current = { +static const struct da9121_range da914x_20A_2phase_current = { .val_min = 13000000, .val_max = 39000000, .val_stp = 2000000, @@ -105,7 +104,7 @@ static struct da9121_range da914x_20A_2phase_current = { struct da9121_variant_info { int num_bucks; int num_phases; - struct da9121_range *current_range; + const struct da9121_range *current_range; }; static const struct da9121_variant_info variant_parameters[] = { @@ -189,7 +188,7 @@ static int da9121_get_current_limit(struct regulator_dev *rdev) { struct da9121 *chip = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); - struct da9121_range *range = + const struct da9121_range *range = variant_parameters[chip->variant_id].current_range; unsigned int val = 0; int ret = 0; @@ -220,7 +219,7 @@ static int da9121_ceiling_selector(struct regulator_dev *rdev, unsigned int *selector) { struct da9121 *chip = rdev_get_drvdata(rdev); - struct da9121_range *range = + const struct da9121_range *range = variant_parameters[chip->variant_id].current_range; unsigned int level; unsigned int i = 0; @@ -260,7 +259,7 @@ static int da9121_set_current_limit(struct regulator_dev *rdev, { struct da9121 *chip = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); - struct da9121_range *range = + const struct da9121_range *range = variant_parameters[chip->variant_id].current_range; unsigned int sel = 0; int ret = 0; @@ -866,25 +865,25 @@ static const struct regmap_access_table da9121_volatile_table = { }; /* DA9121 regmap config for 1 channel variants */ -static struct regmap_config da9121_1ch_regmap_config = { +static const struct regmap_config da9121_1ch_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = DA9121_REG_OTP_CONFIG_ID, .rd_table = &da9121_1ch_readable_table, .wr_table = &da9121_1ch_writeable_table, .volatile_table = &da9121_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* DA9121 regmap config for 2 channel variants */ -static struct regmap_config da9121_2ch_regmap_config = { +static const struct regmap_config da9121_2ch_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = DA9121_REG_OTP_CONFIG_ID, .rd_table = &da9121_2ch_readable_table, .wr_table = &da9121_2ch_writeable_table, .volatile_table = &da9121_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) @@ -994,7 +993,7 @@ error: static int da9121_assign_chip_model(struct i2c_client *i2c, struct da9121 *chip) { - struct regmap_config *regmap; + const struct regmap_config *regmap; int ret = 0; chip->dev = &i2c->dev; @@ -1193,4 +1192,5 @@ static struct i2c_driver da9121_regulator_driver = { module_i2c_driver(da9121_regulator_driver); +MODULE_DESCRIPTION("Dialog Semiconductor DA9121/DA9122/DA9220/DA9217/DA9130/DA9131/DA9132 regulator driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index 02b85ca4a6fc..39ade0dba40f 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -202,8 +202,8 @@ static int da9210_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id da9210_i2c_id[] = { - {"da9210", 0}, - {}, + { "da9210" }, + {} }; MODULE_DEVICE_TABLE(i2c, da9210_i2c_id); diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index af383ff0fe57..d4f14d7ea8cf 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -68,7 +68,7 @@ static const struct regmap_config da9211_regmap_config = { .val_bits = 8, .max_register = 5 * 128, .volatile_reg = da9211_volatile_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .ranges = da9211_regmap_range, .num_ranges = ARRAY_SIZE(da9211_regmap_range), }; @@ -264,7 +264,7 @@ static const struct regulator_ops da9211_buck_ops = { .of_map_mode = da9211_map_buck_mode,\ } -static struct regulator_desc da9211_regulators[] = { +static const struct regulator_desc da9211_regulators[] = { DA9211_BUCK(BUCKA), DA9211_BUCK(BUCKB), }; diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 1e2d54da1b9a..1ec2e1348891 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -480,7 +480,7 @@ static struct platform_driver db8500_regulator_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = db8500_regulator_probe, - .remove_new = db8500_regulator_remove, + .remove = db8500_regulator_remove, }; static int __init db8500_regulator_init(void) diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index 90bb0d178885..36164aec30e8 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c @@ -145,6 +145,65 @@ struct regulator *devm_regulator_get_optional(struct device *dev, } EXPORT_SYMBOL_GPL(devm_regulator_get_optional); +/** + * devm_regulator_get_enable_read_voltage - Resource managed regulator get and + * enable that returns the voltage + * @dev: device to supply + * @id: supply name or regulator ID. + * + * Get and enable regulator for duration of the device life-time. + * regulator_disable() and regulator_put() are automatically called on driver + * detach. See regulator_get_optional(), regulator_enable(), and + * regulator_get_voltage() for more information. + * + * This is a convenience function for supplies that provide a reference voltage + * where the consumer driver just needs to know the voltage and keep the + * regulator enabled. + * + * In cases where the supply is not strictly required, callers can check for + * -ENODEV error and handle it accordingly. + * + * Returns: voltage in microvolts on success, or an negative error number on failure. + */ +int devm_regulator_get_enable_read_voltage(struct device *dev, const char *id) +{ + struct regulator *r; + int ret; + + /* + * Since we need a real voltage, we use devm_regulator_get_optional() + * rather than getting a dummy regulator with devm_regulator_get() and + * then letting regulator_get_voltage() fail with -EINVAL. This way, the + * caller can handle the -ENODEV negative error number if needed instead + * of the ambiguous -EINVAL. + */ + r = devm_regulator_get_optional(dev, id); + if (IS_ERR(r)) + return PTR_ERR(r); + + ret = regulator_enable(r); + if (ret) + goto err_regulator_put; + + ret = devm_add_action_or_reset(dev, regulator_action_disable, r); + if (ret) + goto err_regulator_put; + + ret = regulator_get_voltage(r); + if (ret < 0) + goto err_release_action; + + return ret; + +err_release_action: + devm_release_action(dev, regulator_action_disable, r); +err_regulator_put: + devm_regulator_put(r); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_regulator_get_enable_read_voltage); + static int devm_regulator_match(struct device *dev, void *res, void *data) { struct regulator **r = res; @@ -217,7 +276,7 @@ static int _devm_regulator_bulk_get(struct device *dev, int num_consumers, * @num_consumers: number of consumers to register * @consumers: configuration of consumers; clients are stored here. * - * @return 0 on success, an errno on failure. + * @return 0 on success, a negative error number on failure. * * This helper function allows drivers to get several regulator * consumers in one operation with management, the regulators will @@ -240,7 +299,7 @@ EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); * @num_consumers: number of consumers to register * @consumers: configuration of consumers; clients are stored here. * - * @return 0 on success, an errno on failure. + * @return 0 on success, a negative error number on failure. * * This helper function allows drivers to exclusively get several * regulator consumers in one operation with management, the regulators @@ -267,7 +326,7 @@ EXPORT_SYMBOL_GPL(devm_regulator_bulk_get_exclusive); * This is a convenience function to allow bulk regulator configuration * to be stored "static const" in files. * - * Return: 0 on success, an errno on failure. + * Return: 0 on success, a negative error number on failure. */ int devm_regulator_bulk_get_const(struct device *dev, int num_consumers, const struct regulator_bulk_data *in_consumers, @@ -334,7 +393,7 @@ static void devm_regulator_bulk_disable(void *res) * @num_consumers: number of consumers to register * @id: list of supply names or regulator IDs * - * @return 0 on success, an errno on failure. + * @return 0 on success, a negative error number on failure. * * This helper function allows drivers to get several regulator * consumers in one operation with management, the regulators will @@ -515,7 +574,7 @@ static void devm_regulator_unregister_supply_alias(struct device *dev, * lookup the supply * @num_id: number of aliases to register * - * @return 0 on success, an errno on failure. + * @return 0 on success, a negative error number on failure. * * This helper function allows drivers to register several supply * aliases in one operation, the aliases will be automatically @@ -667,7 +726,7 @@ static void regulator_irq_helper_drop(void *res) * IRQ. * @rdev_amount: Amount of regulators associated with this IRQ. * - * Return: handle to irq_helper or an ERR_PTR() encoded error code. + * Return: handle to irq_helper or an ERR_PTR() encoded negative error number. */ void *devm_regulator_irq_helper(struct device *dev, const struct regulator_irq_desc *d, int irq, @@ -690,3 +749,42 @@ void *devm_regulator_irq_helper(struct device *dev, return ptr; } EXPORT_SYMBOL_GPL(devm_regulator_irq_helper); + +#if IS_ENABLED(CONFIG_OF) +static struct regulator *_devm_of_regulator_get(struct device *dev, struct device_node *node, + const char *id, int get_type) +{ + struct regulator **ptr, *regulator; + + ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + regulator = _of_regulator_get(dev, node, id, get_type); + if (!IS_ERR(regulator)) { + *ptr = regulator; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return regulator; +} + +/** + * devm_of_regulator_get_optional - Resource managed of_regulator_get_optional() + * @dev: device used for dev_printk() messages and resource lifetime management + * @node: device node for regulator "consumer" + * @id: supply name or regulator ID. + * + * Managed regulator_get_optional(). Regulators returned from this + * function are automatically regulator_put() on driver detach. See + * of_regulator_get_optional() for more information. + */ +struct regulator *devm_of_regulator_get_optional(struct device *dev, struct device_node *node, + const char *id) +{ + return _devm_of_regulator_get(dev, node, id, OPTIONAL_GET); +} +EXPORT_SYMBOL_GPL(devm_of_regulator_get_optional); +#endif diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index 5b9b9e4e762d..9f59889129ab 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -60,7 +60,7 @@ static struct platform_driver dummy_regulator_driver = { .probe = dummy_regulator_probe, .driver = { .name = "reg-dummy", - .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .probe_type = PROBE_FORCE_SYNCHRONOUS, }, }; diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 17c9bf204385..bd9447dac596 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -46,7 +46,7 @@ /* VSEL bit definitions */ #define VSEL_BUCK_EN BIT(7) #define VSEL_MODE BIT(6) -/* Chip ID and Verison */ +/* Chip ID and Version */ #define DIE_ID 0x0F /* ID1 */ #define DIE_REV 0x0F /* ID2 */ /* Control bit definitions */ diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c index 0eb2442456f0..b6cb0aaac3b1 100644 --- a/drivers/regulator/fixed-helper.c +++ b/drivers/regulator/fixed-helper.c @@ -15,7 +15,7 @@ static void regulator_fixed_release(struct device *dev) { struct fixed_regulator_data *data = container_of(dev, struct fixed_regulator_data, pdev.dev); - kfree(data->cfg.supply_name); + kfree_const(data->cfg.supply_name); kfree(data); } @@ -26,6 +26,8 @@ static void regulator_fixed_release(struct device *dev) * @supplies: consumers for this regulator * @num_supplies: number of consumers * @uv: voltage in microvolts + * + * Return: Pointer to registered platform device, or %NULL if memory allocation fails. */ struct platform_device *regulator_register_always_on(int id, const char *name, struct regulator_consumer_supply *supplies, int num_supplies, int uv) @@ -36,7 +38,7 @@ struct platform_device *regulator_register_always_on(int id, const char *name, if (!data) return NULL; - data->cfg.supply_name = kstrdup(name, GFP_KERNEL); + data->cfg.supply_name = kstrdup_const(name, GFP_KERNEL); if (!data->cfg.supply_name) { kfree(data); return NULL; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index cb93e5cdcfa9..1cb647ed70c6 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -129,7 +129,7 @@ static irqreturn_t reg_fixed_under_voltage_irq_handler(int irq, void *data) * If it's an optional IRQ and not found, it returns 0. * Otherwise, it attempts to request the threaded IRQ. * - * Return: 0 on success, or error code on failure. + * Return: 0 on success, or a negative error number on failure. */ static int reg_fixed_get_irqs(struct device *dev, struct fixed_voltage_data *priv) @@ -158,8 +158,10 @@ static int reg_fixed_get_irqs(struct device *dev, * @desc: regulator description * * Populates fixed_voltage_config structure by extracting data from device - * tree node, returns a pointer to the populated structure of NULL if memory - * alloc fails. + * tree node. + * + * Return: Pointer to a populated &struct fixed_voltage_config or %NULL if + * memory allocation fails. */ static struct fixed_voltage_config * of_get_fixed_voltage_config(struct device *dev, diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index d49268336553..0def82eb8b46 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -125,7 +125,7 @@ static int regulator_range_selector_to_index(struct regulator_dev *rdev, * * Regulators that use regmap for their register I/O and use pickable * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask - * fields in their descriptor and then use this as their get_voltage_vsel + * fields in their descriptor and then use this as their get_voltage_sel * operation, saving some code. */ int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev) @@ -161,6 +161,32 @@ int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev) } EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap); +static int write_separate_vsel_and_range(struct regulator_dev *rdev, + unsigned int sel, unsigned int range) +{ + bool range_updated; + int ret; + + ret = regmap_update_bits_base(rdev->regmap, rdev->desc->vsel_range_reg, + rdev->desc->vsel_range_mask, + range, &range_updated, false, false); + if (ret) + return ret; + + /* + * Some PMICs treat the vsel_reg same as apply-bit. Force it to be + * written if the range changed, even if the old selector was same as + * the new one + */ + if (rdev->desc->range_applied_by_vsel && range_updated) + return regmap_write_bits(rdev->regmap, + rdev->desc->vsel_reg, + rdev->desc->vsel_mask, sel); + + return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, sel); +} + /** * regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel * @@ -169,7 +195,7 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap); * * Regulators that use regmap for their register I/O and use pickable * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask - * fields in their descriptor and then use this as their set_voltage_vsel + * fields in their descriptor and then use this as their set_voltage_sel * operation, saving some code. */ int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev, @@ -199,21 +225,12 @@ int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev, range = rdev->desc->linear_range_selectors_bitfield[i]; range <<= ffs(rdev->desc->vsel_range_mask) - 1; - if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) { - ret = regmap_update_bits(rdev->regmap, - rdev->desc->vsel_reg, + if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, rdev->desc->vsel_range_mask | rdev->desc->vsel_mask, sel | range); - } else { - ret = regmap_update_bits(rdev->regmap, - rdev->desc->vsel_range_reg, - rdev->desc->vsel_range_mask, range); - if (ret) - return ret; - - ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, - rdev->desc->vsel_mask, sel); - } + else + ret = write_separate_vsel_and_range(rdev, sel, range); if (ret) return ret; @@ -233,7 +250,7 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_pickable_regmap); * * Regulators that use regmap for their register I/O can set the * vsel_reg and vsel_mask fields in their descriptor and then use this - * as their get_voltage_vsel operation, saving some code. + * as their get_voltage_sel operation, saving some code. */ int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev) { @@ -259,7 +276,7 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap); * * Regulators that use regmap for their register I/O can set the * vsel_reg and vsel_mask fields in their descriptor and then use this - * as their set_voltage_vsel operation, saving some code. + * as their set_voltage_sel operation, saving some code. */ int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel) { diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c index 82e9e364d4d4..69d24728d6a4 100644 --- a/drivers/regulator/hi6421-regulator.c +++ b/drivers/regulator/hi6421-regulator.c @@ -303,7 +303,7 @@ static const struct regulator_ops hi6421_buck345_ops; } /* HI6421 regulator information */ -static struct hi6421_regulator_info +static const struct hi6421_regulator_info hi6421_regulator_info[HI6421_NUM_REGULATORS] = { HI6421_LDO(LDO0, hi6421_vout0, ldo_0_voltages, 0x20, 0x07, 0x20, 0x10, 10000, 0x20, 8000), @@ -384,7 +384,7 @@ static int hi6421_regulator_enable(struct regulator_dev *rdev) static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev) { - struct hi6421_regulator_info *info; + const struct hi6421_regulator_info *info; unsigned int reg_val; info = container_of(rdev->desc, struct hi6421_regulator_info, desc); @@ -397,7 +397,7 @@ static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev) static unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev) { - struct hi6421_regulator_info *info; + const struct hi6421_regulator_info *info; unsigned int reg_val; info = container_of(rdev->desc, struct hi6421_regulator_info, desc); @@ -411,7 +411,7 @@ static unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev) static int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) { - struct hi6421_regulator_info *info; + const struct hi6421_regulator_info *info; unsigned int new_mode; info = container_of(rdev->desc, struct hi6421_regulator_info, desc); @@ -436,7 +436,7 @@ static int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev, static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) { - struct hi6421_regulator_info *info; + const struct hi6421_regulator_info *info; unsigned int new_mode; info = container_of(rdev->desc, struct hi6421_regulator_info, desc); @@ -462,7 +462,7 @@ static unsigned int hi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev, int input_uV, int output_uV, int load_uA) { - struct hi6421_regulator_info *info; + const struct hi6421_regulator_info *info; info = container_of(rdev->desc, struct hi6421_regulator_info, desc); @@ -539,7 +539,7 @@ static int hi6421_regulator_probe(struct platform_device *pdev) { struct hi6421_pmic *pmic = dev_get_drvdata(pdev->dev.parent); struct hi6421_regulator_pdata *pdata; - struct hi6421_regulator_info *info; + const struct hi6421_regulator_info *info; struct regulator_config config = { }; struct regulator_dev *rdev; int i; diff --git a/drivers/regulator/hi6421v530-regulator.c b/drivers/regulator/hi6421v530-regulator.c index 23924ff0c7b2..b3ebd1624814 100644 --- a/drivers/regulator/hi6421v530-regulator.c +++ b/drivers/regulator/hi6421v530-regulator.c @@ -21,12 +21,10 @@ * struct hi6421v530_regulator_info - hi6421v530 regulator information * @desc: regulator description * @mode_mask: ECO mode bitmask of LDOs; for BUCKs, this masks sleep - * @eco_microamp: eco mode load upper limit (in uA), valid for LDOs only */ struct hi6421v530_regulator_info { struct regulator_desc rdesc; u8 mode_mask; - u32 eco_microamp; }; /* HI6421v530 regulators */ @@ -68,10 +66,9 @@ static const struct regulator_ops hi6421v530_ldo_ops; * emask - enable mask * odelay - off/on delay time in uS * ecomask - eco mode mask - * ecoamp - eco mode load uppler limit in uA */ #define HI6421V530_LDO(_ID, v_table, vreg, vmask, ereg, emask, \ - odelay, ecomask, ecoamp) { \ + odelay, ecomask) { \ .rdesc = { \ .name = #_ID, \ .of_match = of_match_ptr(#_ID), \ @@ -90,31 +87,30 @@ static const struct regulator_ops hi6421v530_ldo_ops; .off_on_delay = odelay, \ }, \ .mode_mask = ecomask, \ - .eco_microamp = ecoamp, \ } /* HI6421V530 regulator information */ -static struct hi6421v530_regulator_info hi6421v530_regulator_info[] = { +static const struct hi6421v530_regulator_info hi6421v530_regulator_info[] = { HI6421V530_LDO(LDO3, ldo_3_voltages, 0x061, 0xf, 0x060, 0x2, - 20000, 0x6, 8000), + 20000, 0x6), HI6421V530_LDO(LDO9, ldo_9_11_voltages, 0x06b, 0x7, 0x06a, 0x2, - 40000, 0x6, 8000), + 40000, 0x6), HI6421V530_LDO(LDO11, ldo_9_11_voltages, 0x06f, 0x7, 0x06e, 0x2, - 40000, 0x6, 8000), + 40000, 0x6), HI6421V530_LDO(LDO15, ldo_15_16_voltages, 0x077, 0x7, 0x076, 0x2, - 40000, 0x6, 8000), + 40000, 0x6), HI6421V530_LDO(LDO16, ldo_15_16_voltages, 0x079, 0x7, 0x078, 0x2, - 40000, 0x6, 8000), + 40000, 0x6), }; static unsigned int hi6421v530_regulator_ldo_get_mode( struct regulator_dev *rdev) { - struct hi6421v530_regulator_info *info; + const struct hi6421v530_regulator_info *info; unsigned int reg_val; - info = rdev_get_drvdata(rdev); + info = container_of(rdev->desc, struct hi6421v530_regulator_info, rdesc); regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val); if (reg_val & (info->mode_mask)) @@ -126,10 +122,10 @@ static unsigned int hi6421v530_regulator_ldo_get_mode( static int hi6421v530_regulator_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) { - struct hi6421v530_regulator_info *info; + const struct hi6421v530_regulator_info *info; unsigned int new_mode; - info = rdev_get_drvdata(rdev); + info = container_of(rdev->desc, struct hi6421v530_regulator_info, rdesc); switch (mode) { case REGULATOR_MODE_NORMAL: new_mode = 0; @@ -176,7 +172,6 @@ static int hi6421v530_regulator_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(hi6421v530_regulator_info); i++) { config.dev = pdev->dev.parent; config.regmap = pmic->regmap; - config.driver_data = &hi6421v530_regulator_info[i]; rdev = devm_regulator_register(&pdev->dev, &hi6421v530_regulator_info[i].rdesc, diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c index 4e10daa1e689..e5f6fbfc9016 100644 --- a/drivers/regulator/hi6421v600-regulator.c +++ b/drivers/regulator/hi6421v600-regulator.c @@ -118,7 +118,7 @@ static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev) static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev) { - struct hi6421_spmi_reg_info *sreg; + const struct hi6421_spmi_reg_info *sreg; unsigned int reg_val; sreg = container_of(rdev->desc, struct hi6421_spmi_reg_info, desc); @@ -133,7 +133,7 @@ static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev) static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) { - struct hi6421_spmi_reg_info *sreg; + const struct hi6421_spmi_reg_info *sreg; unsigned int val; sreg = container_of(rdev->desc, struct hi6421_spmi_reg_info, desc); @@ -160,7 +160,7 @@ hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev, int input_uV, int output_uV, int load_uA) { - struct hi6421_spmi_reg_info *sreg; + const struct hi6421_spmi_reg_info *sreg; sreg = container_of(rdev->desc, struct hi6421_spmi_reg_info, desc); @@ -195,7 +195,7 @@ enum hi6421_spmi_regulator_id { hi6421v600_ldo34, }; -static struct hi6421_spmi_reg_info regulator_info[] = { +static const struct hi6421_spmi_reg_info regulator_info[] = { HI6421V600_LDO(ldo3, range_1v5_to_2v0, 0x16, 0x01, 0x51, 20000, 120, @@ -235,7 +235,7 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) struct device *pmic_dev = pdev->dev.parent; struct regulator_config config = { }; struct hi6421_spmi_reg_priv *priv; - struct hi6421_spmi_reg_info *info; + const struct hi6421_spmi_reg_info *info; struct device *dev = &pdev->dev; struct regmap *regmap; struct regulator_dev *rdev; diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index fb4433068d29..b3d48dc38bc4 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -58,20 +58,32 @@ struct regulator { struct dentry *debugfs; }; -extern struct class regulator_class; +extern const struct class regulator_class; static inline struct regulator_dev *dev_to_rdev(struct device *dev) { return container_of(dev, struct regulator_dev, dev); } +enum regulator_get_type { + NORMAL_GET, + EXCLUSIVE_GET, + OPTIONAL_GET, + MAX_GET_TYPE +}; + #ifdef CONFIG_OF -struct regulator_dev *of_find_regulator_by_node(struct device_node *np); +struct regulator_dev *of_regulator_dev_lookup(struct device *dev, + struct device_node *np, + const char *supply); struct regulator_init_data *regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, struct regulator_config *config, struct device_node **node); +struct regulator *_of_regulator_get(struct device *dev, struct device_node *node, + const char *id, enum regulator_get_type get_type); + struct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev, int index); @@ -80,10 +92,11 @@ int of_get_n_coupled(struct regulator_dev *rdev); bool of_check_coupling_data(struct regulator_dev *rdev); #else -static inline struct regulator_dev * -of_find_regulator_by_node(struct device_node *np) +static inline struct regulator_dev *of_regulator_dev_lookup(struct device *dev, + struct device_node *np, + const char *supply) { - return NULL; + return ERR_PTR(-ENODEV); } static inline struct regulator_init_data * @@ -113,13 +126,11 @@ static inline bool of_check_coupling_data(struct regulator_dev *rdev) } #endif -enum regulator_get_type { - NORMAL_GET, - EXCLUSIVE_GET, - OPTIONAL_GET, - MAX_GET_TYPE -}; +int _regulator_get_common_check(struct device *dev, const char *id, + enum regulator_get_type get_type); +struct regulator *_regulator_get_common(struct regulator_dev *rdev, struct device *dev, + const char *id, enum regulator_get_type get_type); struct regulator *_regulator_get(struct device *dev, const char *id, enum regulator_get_type get_type); int _regulator_bulk_get(struct device *dev, int num_consumers, diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c index fe7ae0f3f46a..0aa188b2bbb2 100644 --- a/drivers/regulator/irq_helpers.c +++ b/drivers/regulator/irq_helpers.c @@ -333,7 +333,7 @@ static void init_rdev_errors(struct regulator_irq *h) * IRQ. * @rdev_amount: Amount of regulators associated with this IRQ. * - * Return: handle to irq_helper or an ERR_PTR() encoded error code. + * Return: handle to irq_helper or an ERR_PTR() encoded negative error number. */ void *regulator_irq_helper(struct device *dev, const struct regulator_irq_desc *d, int irq, @@ -352,6 +352,9 @@ void *regulator_irq_helper(struct device *dev, h->irq = irq; h->desc = *d; + h->desc.name = devm_kstrdup(dev, d->name, GFP_KERNEL); + if (!h->desc.name) + return ERR_PTR(-ENOMEM); ret = init_rdev_state(dev, h, rdev, common_errs, per_rdev_errs, rdev_amount); @@ -401,16 +404,21 @@ EXPORT_SYMBOL_GPL(regulator_irq_helper_cancel); /** * regulator_irq_map_event_simple - regulator IRQ notification for trivial IRQs * - * @irq: Number of IRQ that occurred - * @rid: Information about the event IRQ indicates - * @dev_mask: mask indicating the regulator originating the IRQ + * @irq: Number of IRQ that occurred. + * @rid: Information about the event IRQ indicates. + * The function fills in the ®ulator_err_state->notifs + * and ®ulator_err_state->errors fields of + * ®ulator_irq_data->states as output. + * @dev_mask: mask indicating the regulator originating the IRQ. * * Regulators whose IRQ has single, well defined purpose (always indicate * exactly one event, and are relevant to exactly one regulator device) can - * use this function as their map_event callbac for their regulator IRQ - * notification helperk. Exactly one rdev and exactly one error (in + * use this function as their map_event callback for their regulator IRQ + * notification helper. Exactly one rdev and exactly one error (in * "common_errs"-field) can be given at IRQ helper registration for * regulator_irq_map_event_simple() to be viable. + * + * Return: 0. */ int regulator_irq_map_event_simple(int irq, struct regulator_irq_data *rid, unsigned long *dev_mask) diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 69b4afe95e66..7883cd160727 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -138,8 +138,8 @@ static int isl6271a_probe(struct i2c_client *i2c) } static const struct i2c_device_id isl6271a_id[] = { - {.name = "isl6271a", 0 }, - { }, + { .name = "isl6271a", }, + { } }; MODULE_DEVICE_TABLE(i2c, isl6271a_id); diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c index 0f7560093091..5a234f25e6bb 100644 --- a/drivers/regulator/isl9305.c +++ b/drivers/regulator/isl9305.c @@ -134,7 +134,7 @@ static const struct regmap_config isl9305_regmap = { .val_bits = 8, .max_register = ISL9305_MAX_REG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int isl9305_i2c_probe(struct i2c_client *i2c) diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index e1b5c45f97f4..d4dab86fe385 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -439,7 +439,7 @@ static int lp3971_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id lp3971_i2c_id[] = { - { "lp3971", 0 }, + { "lp3971" }, { } }; MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 7bd6f05edd8d..1b918fb72134 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -537,7 +537,7 @@ static int lp3972_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id lp3972_i2c_id[] = { - { "lp3972", 0 }, + { "lp3972" }, { } }; MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id); diff --git a/drivers/regulator/lp873x-regulator.c b/drivers/regulator/lp873x-regulator.c index 8dfdd1db2070..84a134cfcd9c 100644 --- a/drivers/regulator/lp873x-regulator.c +++ b/drivers/regulator/lp873x-regulator.c @@ -5,6 +5,7 @@ * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <linux/bitfield.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -93,7 +94,7 @@ static int lp873x_buck_set_ramp_delay(struct regulator_dev *rdev, ret = regmap_update_bits(lp873->regmap, regulators[id].ctrl2_reg, LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE, - reg << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE)); + FIELD_PREP(LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE, reg)); if (ret) { dev_err(lp873->dev, "SLEW RATE write failed: %d\n", ret); return ret; diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c index 8d01e18046f3..5509bee49bda 100644 --- a/drivers/regulator/lp8755.c +++ b/drivers/regulator/lp8755.c @@ -430,7 +430,7 @@ static void lp8755_remove(struct i2c_client *client) } static const struct i2c_device_id lp8755_id[] = { - {LP8755_NAME, 0}, + { LP8755_NAME }, {} }; diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c index 61ee5cf3f241..1259b5d20153 100644 --- a/drivers/regulator/lp87565-regulator.c +++ b/drivers/regulator/lp87565-regulator.c @@ -5,6 +5,7 @@ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ */ +#include <linux/bitfield.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -99,7 +100,7 @@ static int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev, ret = regmap_update_bits(rdev->regmap, regulators[id].ctrl2_reg, LP87565_BUCK_CTRL_2_SLEW_RATE, - reg << __ffs(LP87565_BUCK_CTRL_2_SLEW_RATE)); + FIELD_PREP(LP87565_BUCK_CTRL_2_SLEW_RATE, reg)); if (ret) { dev_err(&rdev->dev, "SLEW RATE write failed: %d\n", ret); return ret; diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index e97ade09dede..2ade249ab6df 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -13,7 +13,7 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/mfd/lp8788.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> /* register address */ #define LP8788_EN_BUCK 0x0C @@ -69,8 +69,8 @@ #define BUCK_FPWM_SHIFT(x) (x) enum lp8788_dvs_state { - DVS_LOW = GPIOF_OUT_INIT_LOW, - DVS_HIGH = GPIOF_OUT_INIT_HIGH, + DVS_LOW = 0, + DVS_HIGH = 1, }; enum lp8788_dvs_mode { @@ -89,6 +89,8 @@ struct lp8788_buck { struct lp8788 *lp; struct regulator_dev *regulator; void *dvs; + struct gpio_desc *gpio1; + struct gpio_desc *gpio2; /* Only used on BUCK2 */ }; /* BUCK 1 ~ 4 voltage ranges */ @@ -106,8 +108,7 @@ static void lp8788_buck1_set_dvs(struct lp8788_buck *buck) return; pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH; - if (gpio_is_valid(dvs->gpio)) - gpio_set_value(dvs->gpio, pinstate); + gpiod_set_value(buck->gpio1, pinstate); } static void lp8788_buck2_set_dvs(struct lp8788_buck *buck) @@ -139,11 +140,8 @@ static void lp8788_buck2_set_dvs(struct lp8788_buck *buck) return; } - if (gpio_is_valid(dvs->gpio[0])) - gpio_set_value(dvs->gpio[0], pin1); - - if (gpio_is_valid(dvs->gpio[1])) - gpio_set_value(dvs->gpio[1], pin2); + gpiod_set_value(buck->gpio1, pin1); + gpiod_set_value(buck->gpio2, pin2); } static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) @@ -202,19 +200,13 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck, enum lp8788_buck_id id) { enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id); - struct lp8788_buck1_dvs *b1_dvs; - struct lp8788_buck2_dvs *b2_dvs; u8 val, idx, addr; int pin1, pin2; switch (id) { case BUCK1: if (mode == EXTPIN) { - b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs; - if (!b1_dvs) - goto err; - - idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0; + idx = gpiod_get_value(buck->gpio1); } else { lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S; @@ -223,12 +215,8 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck, break; case BUCK2: if (mode == EXTPIN) { - b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs; - if (!b2_dvs) - goto err; - - pin1 = gpio_get_value(b2_dvs->gpio[0]); - pin2 = gpio_get_value(b2_dvs->gpio[1]); + pin1 = gpiod_get_value(buck->gpio1); + pin2 = gpiod_get_value(buck->gpio2); if (pin1 == PIN_LOW && pin2 == PIN_LOW) idx = 0; @@ -424,28 +412,28 @@ static int lp8788_dvs_gpio_request(struct platform_device *pdev, enum lp8788_buck_id id) { struct lp8788_platform_data *pdata = buck->lp->pdata; - char *b1_name = "LP8788_B1_DVS"; - char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" }; - int i, gpio, ret; + struct device *dev = &pdev->dev; switch (id) { case BUCK1: - gpio = pdata->buck1_dvs->gpio; - ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW, - b1_name); - if (ret) - return ret; + buck->gpio1 = devm_gpiod_get(dev, "dvs", GPIOD_OUT_LOW); + if (IS_ERR(buck->gpio1)) + return PTR_ERR(buck->gpio1); + gpiod_set_consumer_name(buck->gpio1, "LP8788_B1_DVS"); buck->dvs = pdata->buck1_dvs; break; case BUCK2: - for (i = 0; i < LP8788_NUM_BUCK2_DVS; i++) { - gpio = pdata->buck2_dvs->gpio[i]; - ret = devm_gpio_request_one(&pdev->dev, gpio, - DVS_LOW, b2_name[i]); - if (ret) - return ret; - } + buck->gpio1 = devm_gpiod_get_index(dev, "dvs", 0, GPIOD_OUT_LOW); + if (IS_ERR(buck->gpio1)) + return PTR_ERR(buck->gpio1); + gpiod_set_consumer_name(buck->gpio1, "LP8788_B2_DVS1"); + + buck->gpio2 = devm_gpiod_get_index(dev, "dvs", 1, GPIOD_OUT_LOW); + if (IS_ERR(buck->gpio2)) + return PTR_ERR(buck->gpio2); + gpiod_set_consumer_name(buck->gpio2, "LP8788_B2_DVS2"); + buck->dvs = pdata->buck2_dvs; break; default: diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 0f133129252e..4242fbb7b147 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -276,7 +276,7 @@ static int max1586_pmic_probe(struct i2c_client *client) } static const struct i2c_device_id max1586_id[] = { - { "max1586", 0 }, + { "max1586" }, { } }; MODULE_DEVICE_TABLE(i2c, max1586_id); diff --git a/drivers/regulator/max20411-regulator.c b/drivers/regulator/max20411-regulator.c index 8c09dc71b16d..02d7009ea0e6 100644 --- a/drivers/regulator/max20411-regulator.c +++ b/drivers/regulator/max20411-regulator.c @@ -145,8 +145,8 @@ static const struct of_device_id of_max20411_match_tbl[] = { MODULE_DEVICE_TABLE(of, of_max20411_match_tbl); static const struct i2c_device_id max20411_id[] = { - { "max20411", 0 }, - { }, + { "max20411" }, + { } }; MODULE_DEVICE_TABLE(i2c, max20411_id); @@ -161,4 +161,5 @@ static struct i2c_driver max20411_i2c_driver = { }; module_i2c_driver(max20411_i2c_driver); +MODULE_DESCRIPTION("Maxim MAX20411 High-Efficiency Single Step-Down Converter driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max5970-regulator.c b/drivers/regulator/max5970-regulator.c index 8bbcd983a74a..fc14177ddf5d 100644 --- a/drivers/regulator/max5970-regulator.c +++ b/drivers/regulator/max5970-regulator.c @@ -70,7 +70,7 @@ static int max5970_read(struct device *dev, enum hwmon_sensor_types type, * millivolts) and then divide it by the maximum value of the 10-bit ADC. */ *val = (*val * ddata->irng) >> 10; - /* Convert the voltage meansurement across shunt resistor to current */ + /* Convert the voltage measurement across shunt resistor to current */ *val = (*val * 1000) / ddata->shunt_micro_ohms; return 0; default: @@ -485,7 +485,7 @@ static int max597x_irq_handler(int irq, struct regulator_irq_data *rid, } static int max597x_adc_range(struct regmap *regmap, const int ch, - u32 *irng, u32 *mon_rng) + int *irng, int *mon_rng) { unsigned int reg; int ret; @@ -552,7 +552,6 @@ static int max597x_setup_irq(struct device *dev, static int max597x_regulator_probe(struct platform_device *pdev) { - struct max5970_data *max597x; struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL); struct max5970_regulator *data; struct i2c_client *i2c = to_i2c_client(pdev->dev.parent); @@ -566,26 +565,18 @@ static int max597x_regulator_probe(struct platform_device *pdev) if (!regmap) return -EPROBE_DEFER; - max597x = devm_kzalloc(&i2c->dev, sizeof(struct max5970_data), GFP_KERNEL); - if (!max597x) - return -ENOMEM; - rdevs = devm_kcalloc(&i2c->dev, MAX5970_NUM_SWITCHES, sizeof(struct regulator_dev *), GFP_KERNEL); if (!rdevs) return -ENOMEM; - i2c_set_clientdata(i2c, max597x); - if (of_device_is_compatible(i2c->dev.of_node, "maxim,max5978")) - max597x->num_switches = MAX5978_NUM_SWITCHES; + num_switches = MAX5978_NUM_SWITCHES; else if (of_device_is_compatible(i2c->dev.of_node, "maxim,max5970")) - max597x->num_switches = MAX5970_NUM_SWITCHES; + num_switches = MAX5970_NUM_SWITCHES; else return -ENODEV; - num_switches = max597x->num_switches; - for (i = 0; i < num_switches; i++) { data = devm_kzalloc(&i2c->dev, sizeof(struct max5970_regulator), @@ -596,13 +587,10 @@ static int max597x_regulator_probe(struct platform_device *pdev) data->num_switches = num_switches; data->regmap = regmap; - ret = max597x_adc_range(regmap, i, &max597x->irng[i], &max597x->mon_rng[i]); + ret = max597x_adc_range(regmap, i, &data->irng, &data->mon_rng); if (ret < 0) return ret; - data->irng = max597x->irng[i]; - data->mon_rng = max597x->mon_rng[i]; - config.dev = &i2c->dev; config.driver_data = (void *)data; config.regmap = data->regmap; @@ -614,7 +602,6 @@ static int max597x_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } rdevs[i] = rdev; - max597x->shunt_micro_ohms[i] = data->shunt_micro_ohms; } if (IS_REACHABLE(CONFIG_HWMON)) { diff --git a/drivers/regulator/max77503-regulator.c b/drivers/regulator/max77503-regulator.c index 4a6ba4dd2acd..c7c94e868fc1 100644 --- a/drivers/regulator/max77503-regulator.c +++ b/drivers/regulator/max77503-regulator.c @@ -25,14 +25,6 @@ #define MAX77503_AD_ENABLED 0x1 #define MAX77503_AD_DISABLED 0x0 -struct max77503_dev { - struct device *dev; - struct device_node *of_node; - struct regulator_desc desc; - struct regulator_dev *rdev; - struct regmap *regmap; -}; - static const struct regmap_config max77503_regmap_config = { .reg_bits = 8, .val_bits = 8, diff --git a/drivers/regulator/max77650-regulator.c b/drivers/regulator/max77650-regulator.c index 94abfbb2bc1e..7368f54f046d 100644 --- a/drivers/regulator/max77650-regulator.c +++ b/drivers/regulator/max77650-regulator.c @@ -43,8 +43,6 @@ struct max77650_regulator_desc { unsigned int regB; }; -static struct max77650_regulator_desc max77651_SBB1_desc; - static const unsigned int max77651_sbb1_volt_range_sel[] = { 0x0, 0x1, 0x2, 0x3 }; @@ -66,11 +64,11 @@ static const unsigned int max77650_current_limit_table[] = { static int max77650_regulator_is_enabled(struct regulator_dev *rdev) { - struct max77650_regulator_desc *rdesc; + const struct max77650_regulator_desc *rdesc; struct regmap *map; int val, rv, en; - rdesc = rdev_get_drvdata(rdev); + rdesc = container_of(rdev->desc, struct max77650_regulator_desc, desc); map = rdev_get_regmap(rdev); rv = regmap_read(map, rdesc->regB, &val); @@ -84,10 +82,10 @@ static int max77650_regulator_is_enabled(struct regulator_dev *rdev) static int max77650_regulator_enable(struct regulator_dev *rdev) { - struct max77650_regulator_desc *rdesc; + const struct max77650_regulator_desc *rdesc; struct regmap *map; - rdesc = rdev_get_drvdata(rdev); + rdesc = container_of(rdev->desc, struct max77650_regulator_desc, desc); map = rdev_get_regmap(rdev); return regmap_update_bits(map, rdesc->regB, @@ -97,10 +95,10 @@ static int max77650_regulator_enable(struct regulator_dev *rdev) static int max77650_regulator_disable(struct regulator_dev *rdev) { - struct max77650_regulator_desc *rdesc; + const struct max77650_regulator_desc *rdesc; struct regmap *map; - rdesc = rdev_get_drvdata(rdev); + rdesc = container_of(rdev->desc, struct max77650_regulator_desc, desc); map = rdev_get_regmap(rdev); return regmap_update_bits(map, rdesc->regB, @@ -145,7 +143,7 @@ static const struct regulator_ops max77651_SBB1_regulator_ops = { .set_active_discharge = regulator_set_active_discharge_regmap, }; -static struct max77650_regulator_desc max77650_LDO_desc = { +static const struct max77650_regulator_desc max77650_LDO_desc = { .desc = { .name = "ldo", .of_match = of_match_ptr("ldo"), @@ -171,7 +169,7 @@ static struct max77650_regulator_desc max77650_LDO_desc = { .regB = MAX77650_REG_CNFG_LDO_B, }; -static struct max77650_regulator_desc max77650_SBB0_desc = { +static const struct max77650_regulator_desc max77650_SBB0_desc = { .desc = { .name = "sbb0", .of_match = of_match_ptr("sbb0"), @@ -201,7 +199,7 @@ static struct max77650_regulator_desc max77650_SBB0_desc = { .regB = MAX77650_REG_CNFG_SBB0_B, }; -static struct max77650_regulator_desc max77650_SBB1_desc = { +static const struct max77650_regulator_desc max77650_SBB1_desc = { .desc = { .name = "sbb1", .of_match = of_match_ptr("sbb1"), @@ -231,7 +229,7 @@ static struct max77650_regulator_desc max77650_SBB1_desc = { .regB = MAX77650_REG_CNFG_SBB1_B, }; -static struct max77650_regulator_desc max77651_SBB1_desc = { +static const struct max77650_regulator_desc max77651_SBB1_desc = { .desc = { .name = "sbb1", .of_match = of_match_ptr("sbb1"), @@ -264,7 +262,7 @@ static struct max77650_regulator_desc max77651_SBB1_desc = { .regB = MAX77650_REG_CNFG_SBB1_B, }; -static struct max77650_regulator_desc max77650_SBB2_desc = { +static const struct max77650_regulator_desc max77650_SBB2_desc = { .desc = { .name = "sbb2", .of_match = of_match_ptr("sbb2"), @@ -294,7 +292,7 @@ static struct max77650_regulator_desc max77650_SBB2_desc = { .regB = MAX77650_REG_CNFG_SBB2_B, }; -static struct max77650_regulator_desc max77651_SBB2_desc = { +static const struct max77650_regulator_desc max77651_SBB2_desc = { .desc = { .name = "sbb2", .of_match = of_match_ptr("sbb2"), @@ -326,8 +324,8 @@ static struct max77650_regulator_desc max77651_SBB2_desc = { static int max77650_regulator_probe(struct platform_device *pdev) { - struct max77650_regulator_desc **rdescs; - struct max77650_regulator_desc *rdesc; + const struct max77650_regulator_desc **rdescs; + const struct max77650_regulator_desc *rdesc; struct regulator_config config = { }; struct device *dev, *parent; struct regulator_dev *rdev; @@ -376,7 +374,6 @@ static int max77650_regulator_probe(struct platform_device *pdev) for (i = 0; i < MAX77650_REGULATOR_NUM_REGULATORS; i++) { rdesc = rdescs[i]; - config.driver_data = rdesc; rdev = devm_regulator_register(dev, &rdesc->desc, &config); if (IS_ERR(rdev)) diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index 69eb6abd2551..b2e87642bec4 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -160,8 +160,8 @@ static unsigned max77802_get_mode(struct regulator_dev *rdev) * Enable Control Logic3 by PWRREQ (LDO 3) * * If setting the regulator mode fails, the function only warns but does - * not return an error code to avoid the regulator core to stop setting - * the operating mode for the remaining regulators. + * not return a negative error number to avoid the regulator core to stop + * setting the operating mode for the remaining regulators. */ static int max77802_set_suspend_mode(struct regulator_dev *rdev, unsigned int mode) diff --git a/drivers/regulator/max77826-regulator.c b/drivers/regulator/max77826-regulator.c index 5590cdf615b7..310bc8ee7af8 100644 --- a/drivers/regulator/max77826-regulator.c +++ b/drivers/regulator/max77826-regulator.c @@ -153,7 +153,6 @@ enum max77826_regulators { struct max77826_regulator_info { struct regmap *regmap; - struct regulator_desc *rdesc; }; static const struct regmap_config max77826_regmap_config = { @@ -187,7 +186,7 @@ static const struct regulator_ops max77826_buck_ops = { .set_voltage_time_sel = max77826_set_voltage_time_sel, }; -static struct regulator_desc max77826_regulators_desc[] = { +static const struct regulator_desc max77826_regulators_desc[] = { MAX77826_LDO(1, NMOS), MAX77826_LDO(2, NMOS), MAX77826_LDO(3, NMOS), @@ -246,7 +245,6 @@ static int max77826_i2c_probe(struct i2c_client *client) if (!info) return -ENOMEM; - info->rdesc = max77826_regulators_desc; regmap = devm_regmap_init_i2c(client, &max77826_regmap_config); if (IS_ERR(regmap)) { dev_err(dev, "Failed to allocate regmap!\n"); diff --git a/drivers/regulator/max77857-regulator.c b/drivers/regulator/max77857-regulator.c index 145ad0281857..1216cc3a6f72 100644 --- a/drivers/regulator/max77857-regulator.c +++ b/drivers/regulator/max77857-regulator.c @@ -67,7 +67,7 @@ static bool max77857_volatile_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config max77857_regmap_config = { +static const struct regmap_config max77857_regmap_config = { .reg_bits = 8, .val_bits = 8, .cache_type = REGCACHE_MAPLE, @@ -427,7 +427,7 @@ static int max77857_probe(struct i2c_client *client) return 0; } -const struct i2c_device_id max77857_id[] = { +static const struct i2c_device_id max77857_id[] = { { "max77831", ID_MAX77831 }, { "max77857", ID_MAX77857 }, { "max77859", ID_MAX77859 }, diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 24e1dfba78c8..f57c588bcf28 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -240,7 +240,7 @@ static int max8649_regulator_probe(struct i2c_client *client) } static const struct i2c_device_id max8649_id[] = { - { "max8649", 0 }, + { "max8649" }, { } }; MODULE_DEVICE_TABLE(i2c, max8649_id); diff --git a/drivers/regulator/max8893.c b/drivers/regulator/max8893.c index 30592425e193..5a90633d8536 100644 --- a/drivers/regulator/max8893.c +++ b/drivers/regulator/max8893.c @@ -162,8 +162,8 @@ MODULE_DEVICE_TABLE(of, max8893_dt_match); #endif static const struct i2c_device_id max8893_ids[] = { - { "max8893", 0 }, - { }, + { "max8893" }, + { } }; MODULE_DEVICE_TABLE(i2c, max8893_ids); diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 0b0b841d214a..1f94315bfb02 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -307,8 +307,8 @@ static int max8952_pmic_probe(struct i2c_client *client) } static const struct i2c_device_id max8952_ids[] = { - { "max8952", 0 }, - { }, + { "max8952" }, + { } }; MODULE_DEVICE_TABLE(i2c, max8952_ids); diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 8d5193207552..f68caa07f546 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -20,9 +20,7 @@ #include <linux/regulator/machine.h> #include <linux/regulator/max8973-regulator.h> #include <linux/regulator/of_regulator.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> -#include <linux/of_gpio.h> #include <linux/i2c.h> #include <linux/slab.h> #include <linux/regmap.h> @@ -102,7 +100,7 @@ struct max8973_chip { struct regulator_desc desc; struct regmap *regmap; bool enable_external_control; - int dvs_gpio; + struct gpio_desc *dvs_gpiod; int lru_index[MAX8973_MAX_VOUT_REG]; int curr_vout_val[MAX8973_MAX_VOUT_REG]; int curr_vout_reg; @@ -184,7 +182,7 @@ static int max8973_dcdc_set_voltage_sel(struct regulator_dev *rdev, * If gpios are available to select the VOUT register then least * recently used register for new configuration. */ - if (gpio_is_valid(max->dvs_gpio)) + if (max->dvs_gpiod) found = find_voltage_set_register(max, vsel, &vout_reg, &gpio_val); @@ -201,8 +199,8 @@ static int max8973_dcdc_set_voltage_sel(struct regulator_dev *rdev, } /* Select proper VOUT register vio gpios */ - if (gpio_is_valid(max->dvs_gpio)) { - gpio_set_value_cansleep(max->dvs_gpio, gpio_val & 0x1); + if (max->dvs_gpiod) { + gpiod_set_value_cansleep(max->dvs_gpiod, gpio_val & 0x1); max->curr_gpio_val = gpio_val; } return 0; @@ -472,8 +470,7 @@ static const struct thermal_zone_device_ops max77621_tz_ops = { static int max8973_thermal_init(struct max8973_chip *mchip) { struct thermal_zone_device *tzd; - struct irq_data *irq_data; - unsigned long irq_flags = 0; + unsigned long irq_flags; int ret; if (mchip->id != MAX77621) @@ -491,9 +488,7 @@ static int max8973_thermal_init(struct max8973_chip *mchip) if (mchip->irq <= 0) return 0; - irq_data = irq_get_irq_data(mchip->irq); - if (irq_data) - irq_flags = irqd_get_trigger_type(irq_data); + irq_flags = irq_get_trigger_type(mchip->irq); ret = devm_request_threaded_irq(mchip->dev, mchip->irq, NULL, max8973_thermal_irq, @@ -512,7 +507,7 @@ static const struct regmap_config max8973_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = MAX8973_CHIPID2, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static struct max8973_regulator_platform_data *max8973_parse_dt( @@ -531,7 +526,6 @@ static struct max8973_regulator_platform_data *max8973_parse_dt( pdata->enable_ext_control = of_property_read_bool(np, "maxim,externally-enable"); - pdata->dvs_gpio = of_get_named_gpio(np, "maxim,dvs-gpio", 0); ret = of_property_read_u32(np, "maxim,dvs-default-state", &pval); if (!ret) @@ -612,13 +606,17 @@ static int max8973_probe(struct i2c_client *client) return -EIO; } - if (pdata->dvs_gpio == -EPROBE_DEFER) - return -EPROBE_DEFER; - max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL); if (!max) return -ENOMEM; + max->dvs_gpiod = devm_gpiod_get_optional(&client->dev, "maxim,dvs", + (pdata->dvs_def_state) ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW); + if (IS_ERR(max->dvs_gpiod)) + return dev_err_probe(&client->dev, PTR_ERR(max->dvs_gpiod), + "failed to obtain dvs gpio\n"); + gpiod_set_consumer_name(max->dvs_gpiod, "max8973-dvs"); + max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config); if (IS_ERR(max->regmap)) { ret = PTR_ERR(max->regmap); @@ -663,7 +661,6 @@ static int max8973_probe(struct i2c_client *client) max->desc.ramp_delay_table = max8973_buck_ramp_table; max->desc.n_ramp_values = ARRAY_SIZE(max8973_buck_ramp_table); - max->dvs_gpio = (pdata->dvs_gpio) ? pdata->dvs_gpio : -EINVAL; max->enable_external_control = pdata->enable_ext_control; max->curr_gpio_val = pdata->dvs_def_state; max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state; @@ -671,21 +668,9 @@ static int max8973_probe(struct i2c_client *client) max->lru_index[0] = max->curr_vout_reg; - if (gpio_is_valid(max->dvs_gpio)) { - int gpio_flags; + if (max->dvs_gpiod) { int i; - gpio_flags = (pdata->dvs_def_state) ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - ret = devm_gpio_request_one(&client->dev, max->dvs_gpio, - gpio_flags, "max8973-dvs"); - if (ret) { - dev_err(&client->dev, - "gpio_request for gpio %d failed, err = %d\n", - max->dvs_gpio, ret); - return ret; - } - /* * Initialize the lru index with vout_reg id * The index 0 will be most recently used and diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c index 0b38eaa73597..e77621b6466c 100644 --- a/drivers/regulator/max8997-regulator.c +++ b/drivers/regulator/max8997-regulator.c @@ -8,9 +8,9 @@ // This driver is based on max8998.c #include <linux/bug.h> +#include <linux/cleanup.h> #include <linux/err.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -32,7 +32,7 @@ struct max8997_data { u8 buck1_vol[8]; u8 buck2_vol[8]; u8 buck5_vol[8]; - int buck125_gpios[3]; + struct gpio_desc *buck125_gpiods[3]; int buck125_gpioindex; bool ignore_gpiodvs_side_effect; @@ -52,9 +52,9 @@ static inline void max8997_set_gpio(struct max8997_data *max8997) int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1; int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1; - gpio_set_value(max8997->buck125_gpios[0], set1); - gpio_set_value(max8997->buck125_gpios[1], set2); - gpio_set_value(max8997->buck125_gpios[2], set3); + gpiod_set_value(max8997->buck125_gpiods[0], set1); + gpiod_set_value(max8997->buck125_gpiods[1], set2); + gpiod_set_value(max8997->buck125_gpiods[2], set3); } struct voltage_map_desc { @@ -873,31 +873,13 @@ static struct regulator_desc regulators[] = { }; #ifdef CONFIG_OF -static int max8997_pmic_dt_parse_dvs_gpio(struct platform_device *pdev, - struct max8997_platform_data *pdata, - struct device_node *pmic_np) -{ - int i, gpio; - - for (i = 0; i < 3; i++) { - gpio = of_get_named_gpio(pmic_np, - "max8997,pmic-buck125-dvs-gpios", i); - if (!gpio_is_valid(gpio)) { - dev_err(&pdev->dev, "invalid gpio[%d]: %d\n", i, gpio); - return -EINVAL; - } - pdata->buck125_gpios[i] = gpio; - } - return 0; -} - static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, struct max8997_platform_data *pdata) { struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct device_node *pmic_np, *regulators_np, *reg_np; + struct device_node *pmic_np, *reg_np; struct max8997_regulator_data *rdata; - unsigned int i, dvs_voltage_nr = 1, ret; + unsigned int i, dvs_voltage_nr = 1; pmic_np = iodev->dev->of_node; if (!pmic_np) { @@ -905,7 +887,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, return -ENODEV; } - regulators_np = of_get_child_by_name(pmic_np, "regulators"); + struct device_node *regulators_np __free(device_node) = of_get_child_by_name(pmic_np, + "regulators"); if (!regulators_np) { dev_err(&pdev->dev, "could not find regulators sub-node\n"); return -EINVAL; @@ -917,10 +900,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, rdata = devm_kcalloc(&pdev->dev, pdata->num_regulators, sizeof(*rdata), GFP_KERNEL); - if (!rdata) { - of_node_put(regulators_np); + if (!rdata) return -ENOMEM; - } pdata->regulators = rdata; for_each_child_of_node(regulators_np, reg_np) { @@ -941,7 +922,6 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, rdata->reg_node = reg_np; rdata++; } - of_node_put(regulators_np); pdata->buck1_gpiodvs = of_property_read_bool(pmic_np, "max8997,pmic-buck1-uses-gpio-dvs"); pdata->buck2_gpiodvs = of_property_read_bool(pmic_np, "max8997,pmic-buck2-uses-gpio-dvs"); @@ -949,10 +929,6 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || pdata->buck5_gpiodvs) { - ret = max8997_pmic_dt_parse_dvs_gpio(pdev, pdata, pmic_np); - if (ret) - return -EINVAL; - if (of_property_read_u32(pmic_np, "max8997,pmic-buck125-default-dvs-idx", &pdata->buck125_default_idx)) { @@ -964,9 +940,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, } } - if (of_get_property(pmic_np, - "max8997,pmic-ignore-gpiodvs-side-effect", NULL)) - pdata->ignore_gpiodvs_side_effect = true; + pdata->ignore_gpiodvs_side_effect = of_property_read_bool(pmic_np, + "max8997,pmic-ignore-gpiodvs-side-effect"); dvs_voltage_nr = 8; } @@ -1039,7 +1014,6 @@ static int max8997_pmic_probe(struct platform_device *pdev) max8997->buck1_gpiodvs = pdata->buck1_gpiodvs; max8997->buck2_gpiodvs = pdata->buck2_gpiodvs; max8997->buck5_gpiodvs = pdata->buck5_gpiodvs; - memcpy(max8997->buck125_gpios, pdata->buck125_gpios, sizeof(int) * 3); max8997->ignore_gpiodvs_side_effect = pdata->ignore_gpiodvs_side_effect; nr_dvs = (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || @@ -1110,38 +1084,27 @@ static int max8997_pmic_probe(struct platform_device *pdev) */ if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || pdata->buck5_gpiodvs) { + const char *gpio_names[3] = {"MAX8997 SET1", "MAX8997 SET2", "MAX8997 SET3"}; - if (!gpio_is_valid(pdata->buck125_gpios[0]) || - !gpio_is_valid(pdata->buck125_gpios[1]) || - !gpio_is_valid(pdata->buck125_gpios[2])) { - dev_err(&pdev->dev, "GPIO NOT VALID\n"); - return -EINVAL; - } - - ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0], - "MAX8997 SET1"); - if (ret) - return ret; - - ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1], - "MAX8997 SET2"); - if (ret) - return ret; + for (i = 0; i < 3; i++) { + enum gpiod_flags flags; - ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2], - "MAX8997 SET3"); - if (ret) - return ret; - - gpio_direction_output(pdata->buck125_gpios[0], - (max8997->buck125_gpioindex >> 2) - & 0x1); /* SET1 */ - gpio_direction_output(pdata->buck125_gpios[1], - (max8997->buck125_gpioindex >> 1) - & 0x1); /* SET2 */ - gpio_direction_output(pdata->buck125_gpios[2], - (max8997->buck125_gpioindex >> 0) - & 0x1); /* SET3 */ + if (max8997->buck125_gpioindex & BIT(2 - i)) + flags = GPIOD_OUT_HIGH; + else + flags = GPIOD_OUT_LOW; + + max8997->buck125_gpiods[i] = devm_gpiod_get_index(iodev->dev, + "max8997,pmic-buck125-dvs", + i, + flags); + if (IS_ERR(max8997->buck125_gpiods[i])) { + ret = PTR_ERR(max8997->buck125_gpiods[i]); + return dev_err_probe(iodev->dev, ret, "cant get GPIO %d (%d)\n", + i, ret); + } + gpiod_set_consumer_name(max8997->buck125_gpiods[i], gpio_names[i]); + } } /* DVS-GPIO disabled */ diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index fadb4717384a..254a77887f66 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -10,12 +10,12 @@ #include <linux/init.h> #include <linux/i2c.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/bits.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> @@ -31,6 +31,9 @@ struct max8998_data { unsigned int buck1_idx; /* index to last changed voltage */ /* value in a set */ unsigned int buck2_idx; + struct gpio_desc *buck1_gpio1; + struct gpio_desc *buck1_gpio2; + struct gpio_desc *buck2_gpio; }; static const unsigned int charger_current_table[] = { @@ -227,15 +230,15 @@ static int max8998_set_voltage_ldo_sel(struct regulator_dev *rdev, return ret; } -static inline void buck1_gpio_set(int gpio1, int gpio2, int v) +static inline void buck1_gpio_set(struct gpio_desc *gpio1, struct gpio_desc *gpio2, int v) { - gpio_set_value(gpio1, v & 0x1); - gpio_set_value(gpio2, (v >> 1) & 0x1); + gpiod_set_value(gpio1, v & 0x1); + gpiod_set_value(gpio2, (v >> 1) & 0x1); } -static inline void buck2_gpio_set(int gpio, int v) +static inline void buck2_gpio_set(struct gpio_desc *gpio, int v) { - gpio_set_value(gpio, v & 0x1); + gpiod_set_value(gpio, v & 0x1); } static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev, @@ -260,16 +263,15 @@ static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev, selector, max8998->buck1_vol[0], max8998->buck1_vol[1], max8998->buck1_vol[2], max8998->buck1_vol[3]); - if (gpio_is_valid(pdata->buck1_set1) && - gpio_is_valid(pdata->buck1_set2)) { + if (max8998->buck1_gpio1 && max8998->buck1_gpio2) { /* check if requested voltage */ /* value is already defined */ for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) { if (max8998->buck1_vol[j] == selector) { max8998->buck1_idx = j; - buck1_gpio_set(pdata->buck1_set1, - pdata->buck1_set2, j); + buck1_gpio_set(max8998->buck1_gpio1, + max8998->buck1_gpio2, j); goto buck1_exit; } } @@ -286,13 +288,13 @@ static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev, &shift, &mask); ret = max8998_write_reg(i2c, reg, selector); - buck1_gpio_set(pdata->buck1_set1, - pdata->buck1_set2, max8998->buck1_idx); + buck1_gpio_set(max8998->buck1_gpio1, + max8998->buck1_gpio2, max8998->buck1_idx); buck1_last_val++; buck1_exit: dev_dbg(max8998->dev, "%s: SET1:%d, SET2:%d\n", - i2c->name, gpio_get_value(pdata->buck1_set1), - gpio_get_value(pdata->buck1_set2)); + i2c->name, gpiod_get_value(max8998->buck1_gpio1), + gpiod_get_value(max8998->buck1_gpio2)); break; } else { ret = max8998_write_reg(i2c, reg, selector); @@ -303,14 +305,13 @@ buck1_exit: dev_dbg(max8998->dev, "BUCK2, selector:%d buck2_vol1:%d, buck2_vol2:%d\n", selector, max8998->buck2_vol[0], max8998->buck2_vol[1]); - if (gpio_is_valid(pdata->buck2_set3)) { - + if (max8998->buck2_gpio) { /* check if requested voltage */ /* value is already defined */ for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) { if (max8998->buck2_vol[j] == selector) { max8998->buck2_idx = j; - buck2_gpio_set(pdata->buck2_set3, j); + buck2_gpio_set(max8998->buck2_gpio, j); goto buck2_exit; } } @@ -322,10 +323,10 @@ buck1_exit: ®, &shift, &mask); ret = max8998_write_reg(i2c, reg, selector); max8998->buck2_vol[max8998->buck2_idx] = selector; - buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx); + buck2_gpio_set(max8998->buck2_gpio, max8998->buck2_idx); buck2_exit: dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name, - gpio_get_value(pdata->buck2_set3)); + gpiod_get_value(max8998->buck2_gpio)); } else { ret = max8998_write_reg(i2c, reg, selector); } @@ -539,36 +540,6 @@ static const struct regulator_desc regulators[] = { charger_current_table, MAX8998_REG_CHGR1, 0x7), }; -static int max8998_pmic_dt_parse_dvs_gpio(struct max8998_dev *iodev, - struct max8998_platform_data *pdata, - struct device_node *pmic_np) -{ - int gpio; - - gpio = of_get_named_gpio(pmic_np, "max8998,pmic-buck1-dvs-gpios", 0); - if (!gpio_is_valid(gpio)) { - dev_err(iodev->dev, "invalid buck1 gpio[0]: %d\n", gpio); - return -EINVAL; - } - pdata->buck1_set1 = gpio; - - gpio = of_get_named_gpio(pmic_np, "max8998,pmic-buck1-dvs-gpios", 1); - if (!gpio_is_valid(gpio)) { - dev_err(iodev->dev, "invalid buck1 gpio[1]: %d\n", gpio); - return -EINVAL; - } - pdata->buck1_set2 = gpio; - - gpio = of_get_named_gpio(pmic_np, "max8998,pmic-buck2-dvs-gpio", 0); - if (!gpio_is_valid(gpio)) { - dev_err(iodev->dev, "invalid buck 2 gpio: %d\n", gpio); - return -EINVAL; - } - pdata->buck2_set3 = gpio; - - return 0; -} - static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev, struct max8998_platform_data *pdata) { @@ -614,10 +585,6 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev, of_node_put(reg_np); of_node_put(regulators_np); - ret = max8998_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); - if (ret) - return -EINVAL; - pdata->buck_voltage_lock = of_property_read_bool(pmic_np, "max8998,pmic-buck-voltage-lock"); ret = of_property_read_u32(pmic_np, @@ -665,6 +632,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) struct regulator_dev *rdev; struct max8998_data *max8998; struct i2c_client *i2c; + enum gpiod_flags flags; int i, ret; unsigned int v; @@ -693,37 +661,38 @@ static int max8998_pmic_probe(struct platform_device *pdev) max8998->buck1_idx = pdata->buck1_default_idx; max8998->buck2_idx = pdata->buck2_default_idx; - /* NOTE: */ - /* For unused GPIO NOT marked as -1 (thereof equal to 0) WARN_ON */ - /* will be displayed */ - /* Check if MAX8998 voltage selection GPIOs are defined */ - if (gpio_is_valid(pdata->buck1_set1) && - gpio_is_valid(pdata->buck1_set2)) { - /* Check if SET1 is not equal to 0 */ - if (!pdata->buck1_set1) { - dev_err(&pdev->dev, - "MAX8998 SET1 GPIO defined as 0 !\n"); - WARN_ON(!pdata->buck1_set1); - return -EIO; - } - /* Check if SET2 is not equal to 0 */ - if (!pdata->buck1_set2) { - dev_err(&pdev->dev, - "MAX8998 SET2 GPIO defined as 0 !\n"); - WARN_ON(!pdata->buck1_set2); - return -EIO; - } - - gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1"); - gpio_direction_output(pdata->buck1_set1, - max8998->buck1_idx & 0x1); - - - gpio_request(pdata->buck1_set2, "MAX8998 BUCK1_SET2"); - gpio_direction_output(pdata->buck1_set2, - (max8998->buck1_idx >> 1) & 0x1); - + flags = (max8998->buck1_idx & BIT(0)) ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + max8998->buck1_gpio1 = devm_gpiod_get_index_optional(iodev->dev, + "max8998,pmic-buck1-dvs", + 0, + flags); + if (IS_ERR(max8998->buck1_gpio1)) + return dev_err_probe(&pdev->dev, PTR_ERR(max8998->buck1_gpio1), + "could not get BUCK1 GPIO1\n"); + gpiod_set_consumer_name(max8998->buck1_gpio1, "MAX8998 BUCK1_SET1"); + + flags = (max8998->buck1_idx & BIT(1)) ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + max8998->buck1_gpio2 = devm_gpiod_get_index_optional(iodev->dev, + "max8998,pmic-buck1-dvs", + 1, + flags); + if (IS_ERR(max8998->buck1_gpio2)) + return dev_err_probe(&pdev->dev, PTR_ERR(max8998->buck1_gpio2), + "could not get BUCK1 GPIO2\n"); + gpiod_set_consumer_name(max8998->buck1_gpio1, "MAX8998 BUCK1_SET2"); + + flags = (max8998->buck2_idx & BIT(0)) ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + max8998->buck2_gpio = devm_gpiod_get_index_optional(iodev->dev, + "max8998,pmic-buck2-dvs", + 0, + flags); + if (IS_ERR(max8998->buck2_gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(max8998->buck2_gpio), + "could not get BUCK2 GPIO\n"); + gpiod_set_consumer_name(max8998->buck1_gpio1, "MAX8998 BUCK2_SET3"); + + if (max8998->buck1_gpio1 && max8998->buck1_gpio2) { /* Set predefined values for BUCK1 registers */ for (v = 0; v < ARRAY_SIZE(pdata->buck1_voltage); ++v) { int index = MAX8998_BUCK1 - MAX8998_LDO2; @@ -742,18 +711,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) } } - if (gpio_is_valid(pdata->buck2_set3)) { - /* Check if SET3 is not equal to 0 */ - if (!pdata->buck2_set3) { - dev_err(&pdev->dev, - "MAX8998 SET3 GPIO defined as 0 !\n"); - WARN_ON(!pdata->buck2_set3); - return -EIO; - } - gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3"); - gpio_direction_output(pdata->buck2_set3, - max8998->buck2_idx & 0x1); - + if (max8998->buck2_gpio) { /* Set predefined values for BUCK2 registers */ for (v = 0; v < ARRAY_SIZE(pdata->buck2_voltage); ++v) { int index = MAX8998_BUCK2 - MAX8998_LDO2; diff --git a/drivers/regulator/mcp16502.c b/drivers/regulator/mcp16502.c index 0c15a19fe83a..b34ae0bbba6f 100644 --- a/drivers/regulator/mcp16502.c +++ b/drivers/regulator/mcp16502.c @@ -107,9 +107,10 @@ static unsigned int mcp16502_of_map_mode(unsigned int mode) return REGULATOR_MODE_INVALID; } -#define MCP16502_REGULATOR(_name, _id, _ranges, _ops, _ramp_table) \ +#define MCP16502_REGULATOR(_name, _id, _sn, _ranges, _ops, _ramp_table) \ [_id] = { \ .name = _name, \ + .supply_name = #_sn, \ .regulators_node = "regulators", \ .id = _id, \ .ops = &(_ops), \ @@ -467,18 +468,18 @@ static const struct linear_range b234_ranges[] = { }; static const struct regulator_desc mcp16502_desc[] = { - /* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops, ramp_table) */ - MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops, + /* MCP16502_REGULATOR(_name, _id, _sn, _ranges, _ops, _ramp_table) */ + MCP16502_REGULATOR("VDD_IO", BUCK1, pvin1, b1l12_ranges, mcp16502_buck_ops, mcp16502_ramp_b1l12), - MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops, + MCP16502_REGULATOR("VDD_DDR", BUCK2, pvin2, b234_ranges, mcp16502_buck_ops, mcp16502_ramp_b234), - MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops, + MCP16502_REGULATOR("VDD_CORE", BUCK3, pvin3, b234_ranges, mcp16502_buck_ops, mcp16502_ramp_b234), - MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops, + MCP16502_REGULATOR("VDD_OTHER", BUCK4, pvin4, b234_ranges, mcp16502_buck_ops, mcp16502_ramp_b234), - MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops, + MCP16502_REGULATOR("LDO1", LDO1, lvin, b1l12_ranges, mcp16502_ldo_ops, mcp16502_ramp_b1l12), - MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops, + MCP16502_REGULATOR("LDO2", LDO2, lvin, b1l12_ranges, mcp16502_ldo_ops, mcp16502_ramp_b1l12) }; @@ -577,7 +578,7 @@ static const struct dev_pm_ops mcp16502_pm_ops = { }; #endif static const struct i2c_device_id mcp16502_i2c_id[] = { - { "mcp16502", 0 }, + { "mcp16502" }, { } }; MODULE_DEVICE_TABLE(i2c, mcp16502_i2c_id); diff --git a/drivers/regulator/mp5416.c b/drivers/regulator/mp5416.c index 3457e650a994..e6794190cb68 100644 --- a/drivers/regulator/mp5416.c +++ b/drivers/regulator/mp5416.c @@ -163,7 +163,7 @@ static const struct regulator_ops mp5416_buck_ops = { .set_ramp_delay = regulator_set_ramp_delay_regmap, }; -static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = { +static const struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = { MP5416BUCK("buck1", 1, mp5416_I_limits1, MP5416_REG_CTL1, BIT(0), 1), MP5416BUCK("buck2", 2, mp5416_I_limits2, MP5416_REG_CTL1, BIT(1), 2), MP5416BUCK("buck3", 3, mp5416_I_limits1, MP5416_REG_CTL1, BIT(2), 1), @@ -174,7 +174,7 @@ static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = { MP5416LDO("ldo4", 4, BIT(1)), }; -static struct regulator_desc mp5496_regulators_desc[MP5416_MAX_REGULATORS] = { +static const struct regulator_desc mp5496_regulators_desc[MP5416_MAX_REGULATORS] = { MP5416BUCK("buck1", 1, mp5416_I_limits1, MP5416_REG_CTL1, BIT(0), 1), MP5416BUCK("buck2", 2, mp5416_I_limits2, MP5416_REG_CTL1, BIT(1), 1), MP5416BUCK("buck3", 3, mp5416_I_limits1, MP5416_REG_CTL1, BIT(2), 1), diff --git a/drivers/regulator/mp8859.c b/drivers/regulator/mp8859.c index b820bd6043e5..ab105ffd6a2e 100644 --- a/drivers/regulator/mp8859.c +++ b/drivers/regulator/mp8859.c @@ -35,6 +35,16 @@ #define MP8859_GO_BIT 0x01 +#define MP8859_IOUT_LIM_MASK 0x7f + +#define MP8859_ENABLE_MASK 0x80 +#define MP8859_DISCHG_EN_MASK 0x10 +#define MP8859_MODE_MASK 0x08 + +#define MP8859_PG_MASK 0x80 +#define MP8859_OTP_MASK 0x40 +#define MP8859_OTW_MASK 0x20 +#define MP8859_CC_CV_MASK 0x10 static int mp8859_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) { @@ -73,21 +83,221 @@ static int mp8859_get_voltage_sel(struct regulator_dev *rdev) return val; } +static int mp8859_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int from, unsigned int to) +{ + int change; + + /* The voltage ramps at 1mV/uS, selectors are 10mV */ + if (from > to) + change = from - to; + else + change = to - from; + + return change * 10 * 1000; +} + +static unsigned int mp8859_get_mode(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, MP8859_CTL1_REG, &val); + if (ret != 0) { + dev_err(&rdev->dev, "Failed to read mode: %d\n", ret); + return 0; + } + + if (val & MP8859_MODE_MASK) + return REGULATOR_MODE_FAST; + else + return REGULATOR_MODE_NORMAL; +} + +static int mp8859_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + unsigned int val; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = MP8859_MODE_MASK; + break; + case REGULATOR_MODE_NORMAL: + val = 0; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(rdev->regmap, MP8859_CTL1_REG, + MP8859_MODE_MASK, val); +} + +static int mp8859_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + unsigned int cur_val, new_val; + int ret, i; + + /* Steps of 50mA */ + new_val = max_uA / 50000; + if (new_val > MP8859_IOUT_LIM_MASK) + return -EINVAL; + if (new_val == 0) + return -EINVAL; + + /* + * If the regulator is limiting then ramp gradually as per + * datasheet, otherwise just set the value directly. + */ + ret = regmap_read(rdev->regmap, MP8859_STATUS_REG, &cur_val); + if (ret != 0) + return ret; + if (!(cur_val & MP8859_CC_CV_MASK)) { + return regmap_update_bits(rdev->regmap, MP8859_IOUT_LIM_REG, + MP8859_IOUT_LIM_MASK, new_val); + } + + ret = regmap_read(rdev->regmap, MP8859_IOUT_LIM_REG, &cur_val); + if (ret != 0) + return ret; + + if (cur_val >= new_val) { + for (i = cur_val; i >= new_val; i--) { + ret = regmap_update_bits(rdev->regmap, + MP8859_IOUT_LIM_REG, + MP8859_IOUT_LIM_MASK, + cur_val - i); + if (ret != 0) + return ret; + } + } else { + for (i = cur_val; i <= new_val; i++) { + ret = regmap_update_bits(rdev->regmap, + MP8859_IOUT_LIM_REG, + MP8859_IOUT_LIM_MASK, + cur_val + i); + if (ret != 0) + return ret; + } + } + + return 0; +} + +static int mp8859_get_status(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + /* Output status is only meaingful when enabled */ + ret = regmap_read(rdev->regmap, MP8859_CTL1_REG, &val); + if (ret != 0) + return ret; + if (!(val & MP8859_ENABLE_MASK)) + return REGULATOR_STATUS_UNDEFINED; + + ret = regmap_read(rdev->regmap, MP8859_STATUS_REG, &val); + if (ret != 0) + return ret; + + if (val & MP8859_PG_MASK) + return REGULATOR_STATUS_ON; + else + return REGULATOR_STATUS_ERROR; +} + +static int mp8859_get_error_flags(struct regulator_dev *rdev, + unsigned int *flags) +{ + unsigned int status, enabled; + int ret; + + *flags = 0; + + /* Output status is only meaingful when enabled */ + ret = regmap_read(rdev->regmap, MP8859_CTL1_REG, &enabled); + if (ret != 0) + return ret; + enabled &= MP8859_ENABLE_MASK; + + ret = regmap_read(rdev->regmap, MP8859_STATUS_REG, &status); + if (ret != 0) + return ret; + + if (enabled && !(status & MP8859_PG_MASK)) + status |= REGULATOR_ERROR_FAIL; + if (status & MP8859_OTP_MASK) + status |= REGULATOR_ERROR_OVER_TEMP; + if (status & MP8859_OTW_MASK) + status |= REGULATOR_ERROR_OVER_TEMP_WARN; + if (status & MP8859_CC_CV_MASK) + status |= REGULATOR_ERROR_OVER_CURRENT; + + return 0; +} + static const struct linear_range mp8859_dcdc_ranges[] = { REGULATOR_LINEAR_RANGE(0, VOL_MIN_IDX, VOL_MAX_IDX, 10000), }; +static bool mp8859_readable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MP8859_VOUT_L_REG: + case MP8859_VOUT_H_REG: + case MP8859_VOUT_GO_REG: + case MP8859_IOUT_LIM_REG: + case MP8859_CTL1_REG: + case MP8859_CTL2_REG: + case MP8859_STATUS_REG: + case MP8859_INTERRUPT_REG: + case MP8859_MASK_REG: + case MP8859_ID1_REG: + case MP8859_MFR_ID_REG: + case MP8859_DEV_ID_REG: + case MP8859_IC_REV_REG: + return true; + default: + return false; + } +} + +static bool mp8859_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MP8859_VOUT_GO_REG: + case MP8859_STATUS_REG: + case MP8859_INTERRUPT_REG: + return true; + default: + return false; + } +} + static const struct regmap_config mp8859_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = MP8859_MAX_REG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, + .readable_reg = mp8859_readable, + .volatile_reg = mp8859_volatile, }; static const struct regulator_ops mp8859_ops = { .set_voltage_sel = mp8859_set_voltage_sel, .get_voltage_sel = mp8859_get_voltage_sel, .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_time_sel = mp8859_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = mp8859_set_mode, + .get_mode = mp8859_get_mode, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_current_limit = mp8859_set_current_limit, + .get_status = mp8859_get_status, + .get_error_flags = mp8859_get_error_flags, }; static const struct regulator_desc mp8859_regulators[] = { @@ -100,6 +310,12 @@ static const struct regulator_desc mp8859_regulators[] = { .n_voltages = VOL_MAX_IDX + 1, .linear_ranges = mp8859_dcdc_ranges, .n_linear_ranges = 1, + .enable_reg = MP8859_CTL1_REG, + .enable_mask = MP8859_ENABLE_MASK, + .enable_val = MP8859_ENABLE_MASK, + .active_discharge_reg = MP8859_CTL1_REG, + .active_discharge_on = MP8859_DISCHG_EN_MASK, + .active_discharge_mask = MP8859_DISCHG_EN_MASK, .ops = &mp8859_ops, .owner = THIS_MODULE, }, @@ -111,12 +327,46 @@ static int mp8859_i2c_probe(struct i2c_client *i2c) struct regulator_config config = {.dev = &i2c->dev}; struct regmap *regmap = devm_regmap_init_i2c(i2c, &mp8859_regmap); struct regulator_dev *rdev; + unsigned int val, rev; if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); dev_err(&i2c->dev, "regmap init failed: %d\n", ret); return ret; } + + ret = regmap_read(regmap, MP8859_MFR_ID_REG, &val); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to read manufacturer ID: %d\n", ret); + return ret; + } + if (val != 0x9) { + dev_err(&i2c->dev, "Manufacturer ID %x != 9\n", val); + return -EINVAL; + } + + ret = regmap_read(regmap, MP8859_DEV_ID_REG, &val); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to read device ID: %d\n", ret); + return ret; + } + if (val != 0x58) { + dev_err(&i2c->dev, "Manufacturer ID %x != 0x58\n", val); + return -EINVAL; + } + + ret = regmap_read(regmap, MP8859_IC_REV_REG, &rev); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to read device revision: %d\n", ret); + return ret; + } + ret = regmap_read(regmap, MP8859_ID1_REG, &val); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to read device ID1: %d\n", ret); + return ret; + } + dev_info(&i2c->dev, "MP8859-%04d revision %d\n", val, rev); + rdev = devm_regulator_register(&i2c->dev, &mp8859_regulators[0], &config); diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c index 63a51485f2cc..2ebc1c0b5e6f 100644 --- a/drivers/regulator/mt6311-regulator.c +++ b/drivers/regulator/mt6311-regulator.c @@ -20,7 +20,7 @@ static const struct regmap_config mt6311_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = MT6311_FQMTR_CON4, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* Default limits measured in millivolts and milliamps */ @@ -133,8 +133,8 @@ static int mt6311_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id mt6311_i2c_id[] = { - {"mt6311", 0}, - {}, + { "mt6311" }, + {} }; MODULE_DEVICE_TABLE(i2c, mt6311_i2c_id); diff --git a/drivers/regulator/mt6357-regulator.c b/drivers/regulator/mt6357-regulator.c index c0439a4e0b50..1eb69c7a6acb 100644 --- a/drivers/regulator/mt6357-regulator.c +++ b/drivers/regulator/mt6357-regulator.c @@ -123,7 +123,7 @@ struct mt6357_regulator_info { * * Regulators that use regmap for their register I/O can set the * da_vsel_reg and da_vsel_mask fields in the info structure and - * then use this as their get_voltage_vsel operation. + * then use this as their get_voltage_sel operation. */ static int mt6357_get_buck_voltage_sel(struct regulator_dev *rdev) { diff --git a/drivers/regulator/mt6360-regulator.c b/drivers/regulator/mt6360-regulator.c index ad6587a378d0..24cc9fc94e90 100644 --- a/drivers/regulator/mt6360-regulator.c +++ b/drivers/regulator/mt6360-regulator.c @@ -319,15 +319,15 @@ static unsigned int mt6360_regulator_of_map_mode(unsigned int hw_mode) } } -#define MT6360_REGULATOR_DESC(_name, _sname, ereg, emask, vreg, vmask, \ - mreg, mmask, streg, stmask, vranges, \ - vcnts, offon_delay, irq_tbls) \ +#define MT6360_REGULATOR_DESC(match, _name, _sname, ereg, emask, vreg, \ + vmask, mreg, mmask, streg, stmask, \ + vranges, vcnts, offon_delay, irq_tbls) \ { \ .desc = { \ .name = #_name, \ .supply_name = #_sname, \ .id = MT6360_REGULATOR_##_name, \ - .of_match = of_match_ptr(#_name), \ + .of_match = of_match_ptr(match), \ .regulators_node = of_match_ptr("regulator"), \ .of_map_mode = mt6360_regulator_of_map_mode, \ .owner = THIS_MODULE, \ @@ -351,21 +351,29 @@ static unsigned int mt6360_regulator_of_map_mode(unsigned int hw_mode) } static const struct mt6360_regulator_desc mt6360_regulator_descs[] = { - MT6360_REGULATOR_DESC(BUCK1, BUCK1_VIN, 0x117, 0x40, 0x110, 0xff, 0x117, 0x30, 0x117, 0x04, + MT6360_REGULATOR_DESC("buck1", BUCK1, BUCK1_VIN, + 0x117, 0x40, 0x110, 0xff, 0x117, 0x30, 0x117, 0x04, buck_vout_ranges, 256, 0, buck1_irq_tbls), - MT6360_REGULATOR_DESC(BUCK2, BUCK2_VIN, 0x127, 0x40, 0x120, 0xff, 0x127, 0x30, 0x127, 0x04, + MT6360_REGULATOR_DESC("buck2", BUCK2, BUCK2_VIN, + 0x127, 0x40, 0x120, 0xff, 0x127, 0x30, 0x127, 0x04, buck_vout_ranges, 256, 0, buck2_irq_tbls), - MT6360_REGULATOR_DESC(LDO6, LDO_VIN3, 0x137, 0x40, 0x13B, 0xff, 0x137, 0x30, 0x137, 0x04, + MT6360_REGULATOR_DESC("ldo6", LDO6, LDO_VIN3, + 0x137, 0x40, 0x13B, 0xff, 0x137, 0x30, 0x137, 0x04, ldo_vout_ranges1, 256, 0, ldo6_irq_tbls), - MT6360_REGULATOR_DESC(LDO7, LDO_VIN3, 0x131, 0x40, 0x135, 0xff, 0x131, 0x30, 0x131, 0x04, + MT6360_REGULATOR_DESC("ldo7", LDO7, LDO_VIN3, + 0x131, 0x40, 0x135, 0xff, 0x131, 0x30, 0x131, 0x04, ldo_vout_ranges1, 256, 0, ldo7_irq_tbls), - MT6360_REGULATOR_DESC(LDO1, LDO_VIN1, 0x217, 0x40, 0x21B, 0xff, 0x217, 0x30, 0x217, 0x04, + MT6360_REGULATOR_DESC("ldo1", LDO1, LDO_VIN1, + 0x217, 0x40, 0x21B, 0xff, 0x217, 0x30, 0x217, 0x04, ldo_vout_ranges2, 256, 0, ldo1_irq_tbls), - MT6360_REGULATOR_DESC(LDO2, LDO_VIN1, 0x211, 0x40, 0x215, 0xff, 0x211, 0x30, 0x211, 0x04, + MT6360_REGULATOR_DESC("ldo2", LDO2, LDO_VIN1, + 0x211, 0x40, 0x215, 0xff, 0x211, 0x30, 0x211, 0x04, ldo_vout_ranges2, 256, 0, ldo2_irq_tbls), - MT6360_REGULATOR_DESC(LDO3, LDO_VIN1, 0x205, 0x40, 0x209, 0xff, 0x205, 0x30, 0x205, 0x04, + MT6360_REGULATOR_DESC("ldo3", LDO3, LDO_VIN1, + 0x205, 0x40, 0x209, 0xff, 0x205, 0x30, 0x205, 0x04, ldo_vout_ranges2, 256, 100, ldo3_irq_tbls), - MT6360_REGULATOR_DESC(LDO5, LDO_VIN2, 0x20B, 0x40, 0x20F, 0x7f, 0x20B, 0x30, 0x20B, 0x04, + MT6360_REGULATOR_DESC("ldo5", LDO5, LDO_VIN2, + 0x20B, 0x40, 0x20F, 0x7f, 0x20B, 0x30, 0x20B, 0x04, ldo_vout_ranges3, 128, 100, ldo5_irq_tbls), }; diff --git a/drivers/regulator/mtk-dvfsrc-regulator.c b/drivers/regulator/mtk-dvfsrc-regulator.c index f1280d45265d..f5662c569464 100644 --- a/drivers/regulator/mtk-dvfsrc-regulator.c +++ b/drivers/regulator/mtk-dvfsrc-regulator.c @@ -1,99 +1,94 @@ // SPDX-License-Identifier: GPL-2.0 -// -// Copyright (c) 2020 MediaTek Inc. +/* + * Copyright (C) 2020 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> + */ -#include <linux/err.h> -#include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/of_.h> +#include <linux/of.h> #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> -#include <linux/soc/mediatek/mtk_dvfsrc.h> - -#define DVFSRC_ID_VCORE 0 -#define DVFSRC_ID_VSCP 1 - -#define MT_DVFSRC_REGULAR(match, _name, _volt_table) \ -[DVFSRC_ID_##_name] = { \ - .desc = { \ - .name = match, \ - .of_match = of_match_ptr(match), \ - .ops = &dvfsrc_vcore_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = DVFSRC_ID_##_name, \ - .owner = THIS_MODULE, \ - .n_voltages = ARRAY_SIZE(_volt_table), \ - .volt_table = _volt_table, \ - }, \ -} - -/* - * DVFSRC regulators' information - * - * @desc: standard fields of regulator description. - * @voltage_selector: Selector used for get_voltage_sel() and - * set_voltage_sel() callbacks - */ +#include <linux/soc/mediatek/dvfsrc.h> -struct dvfsrc_regulator { - struct regulator_desc desc; +enum dvfsrc_regulator_id { + DVFSRC_ID_VCORE, + DVFSRC_ID_VSCP, + DVFSRC_ID_MAX }; -/* - * MTK DVFSRC regulators' init data - * - * @size: num of regulators - * @regulator_info: regulator info. - */ -struct dvfsrc_regulator_init_data { +struct dvfsrc_regulator_pdata { + const struct regulator_desc *descs; u32 size; - struct dvfsrc_regulator *regulator_info; }; -static inline struct device *to_dvfsrc_dev(struct regulator_dev *rdev) +#define MTK_DVFSRC_VREG(match, _name, _volt_table) \ +{ \ + .name = match, \ + .of_match = match, \ + .ops = &dvfsrc_vcore_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = DVFSRC_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(_volt_table), \ + .volt_table = _volt_table, \ +} + +static inline struct device *to_dvfs_regulator_dev(struct regulator_dev *rdev) { return rdev_get_dev(rdev)->parent; } +static inline struct device *to_dvfsrc_dev(struct regulator_dev *rdev) +{ + return to_dvfs_regulator_dev(rdev)->parent; +} + +static int dvfsrc_get_cmd(int rdev_id, enum mtk_dvfsrc_cmd *cmd) +{ + switch (rdev_id) { + case DVFSRC_ID_VCORE: + *cmd = MTK_DVFSRC_CMD_VCORE_LEVEL; + break; + case DVFSRC_ID_VSCP: + *cmd = MTK_DVFSRC_CMD_VSCP_LEVEL; + break; + default: + return -EINVAL; + } + + return 0; +} + static int dvfsrc_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector) { struct device *dvfsrc_dev = to_dvfsrc_dev(rdev); + enum mtk_dvfsrc_cmd req_cmd; int id = rdev_get_id(rdev); + int ret; - if (id == DVFSRC_ID_VCORE) - mtk_dvfsrc_send_request(dvfsrc_dev, - MTK_DVFSRC_CMD_VCORE_REQUEST, - selector); - else if (id == DVFSRC_ID_VSCP) - mtk_dvfsrc_send_request(dvfsrc_dev, - MTK_DVFSRC_CMD_VSCP_REQUEST, - selector); - else - return -EINVAL; + ret = dvfsrc_get_cmd(id, &req_cmd); + if (ret) + return ret; - return 0; + return mtk_dvfsrc_send_request(dvfsrc_dev, req_cmd, selector); } static int dvfsrc_get_voltage_sel(struct regulator_dev *rdev) { struct device *dvfsrc_dev = to_dvfsrc_dev(rdev); + enum mtk_dvfsrc_cmd query_cmd; int id = rdev_get_id(rdev); int val, ret; - if (id == DVFSRC_ID_VCORE) - ret = mtk_dvfsrc_query_info(dvfsrc_dev, - MTK_DVFSRC_CMD_VCORE_LEVEL_QUERY, - &val); - else if (id == DVFSRC_ID_VSCP) - ret = mtk_dvfsrc_query_info(dvfsrc_dev, - MTK_DVFSRC_CMD_VSCP_LEVEL_QUERY, - &val); - else - return -EINVAL; + ret = dvfsrc_get_cmd(id, &query_cmd); + if (ret) + return ret; - if (ret != 0) + ret = mtk_dvfsrc_query_info(dvfsrc_dev, query_cmd, &val); + if (ret) return ret; return val; @@ -105,110 +100,97 @@ static const struct regulator_ops dvfsrc_vcore_ops = { .set_voltage_sel = dvfsrc_set_voltage_sel, }; +static const unsigned int mt6873_voltages[] = { + 575000, + 600000, + 650000, + 725000, +}; + +static const struct regulator_desc mt6873_regulators[] = { + MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt6873_voltages), + MTK_DVFSRC_VREG("dvfsrc-vscp", VSCP, mt6873_voltages), +}; + +static const struct dvfsrc_regulator_pdata mt6873_data = { + .descs = mt6873_regulators, + .size = ARRAY_SIZE(mt6873_regulators), +}; + static const unsigned int mt8183_voltages[] = { 725000, 800000, }; -static struct dvfsrc_regulator mt8183_regulators[] = { - MT_DVFSRC_REGULAR("dvfsrc-vcore", VCORE, - mt8183_voltages), +static const struct regulator_desc mt8183_regulators[] = { + MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt8183_voltages), }; -static const struct dvfsrc_regulator_init_data regulator_mt8183_data = { +static const struct dvfsrc_regulator_pdata mt8183_data = { + .descs = mt8183_regulators, .size = ARRAY_SIZE(mt8183_regulators), - .regulator_info = &mt8183_regulators[0], }; -static const unsigned int mt6873_voltages[] = { - 575000, +static const unsigned int mt8195_voltages[] = { + 550000, 600000, 650000, - 725000, + 750000, }; -static struct dvfsrc_regulator mt6873_regulators[] = { - MT_DVFSRC_REGULAR("dvfsrc-vcore", VCORE, - mt6873_voltages), - MT_DVFSRC_REGULAR("dvfsrc-vscp", VSCP, - mt6873_voltages), -}; - -static const struct dvfsrc_regulator_init_data regulator_mt6873_data = { - .size = ARRAY_SIZE(mt6873_regulators), - .regulator_info = &mt6873_regulators[0], +static const struct regulator_desc mt8195_regulators[] = { + MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt8195_voltages), + MTK_DVFSRC_VREG("dvfsrc-vscp", VSCP, mt8195_voltages), }; -static const struct of_device_id mtk_dvfsrc_regulator_match[] = { - { - .compatible = "mediatek,mt8183-dvfsrc", - .data = ®ulator_mt8183_data, - }, { - .compatible = "mediatek,mt8192-dvfsrc", - .data = ®ulator_mt6873_data, - }, { - .compatible = "mediatek,mt6873-dvfsrc", - .data = ®ulator_mt6873_data, - }, { - /* sentinel */ - }, +static const struct dvfsrc_regulator_pdata mt8195_data = { + .descs = mt8195_regulators, + .size = ARRAY_SIZE(mt8195_regulators), }; -MODULE_DEVICE_TABLE(of, mtk_dvfsrc_regulator_match); static int dvfsrc_vcore_regulator_probe(struct platform_device *pdev) { - const struct of_device_id *match; - struct device *dev = &pdev->dev; - struct regulator_config config = { }; - struct regulator_dev *rdev; - const struct dvfsrc_regulator_init_data *regulator_init_data; - struct dvfsrc_regulator *mt_regulators; + struct regulator_config config = { .dev = &pdev->dev }; + const struct dvfsrc_regulator_pdata *pdata; int i; - match = of_match_node(mtk_dvfsrc_regulator_match, dev->parent->of_node); + pdata = device_get_match_data(&pdev->dev); + if (!pdata) + return -EINVAL; - if (!match) { - dev_err(dev, "invalid compatible string\n"); - return -ENODEV; - } + for (i = 0; i < pdata->size; i++) { + const struct regulator_desc *vrdesc = &pdata->descs[i]; + struct regulator_dev *rdev; - regulator_init_data = match->data; - - mt_regulators = regulator_init_data->regulator_info; - for (i = 0; i < regulator_init_data->size; i++) { - config.dev = dev->parent; - config.driver_data = (mt_regulators + i); - rdev = devm_regulator_register(dev, &(mt_regulators + i)->desc, - &config); - if (IS_ERR(rdev)) { - dev_err(dev, "failed to register %s\n", - (mt_regulators + i)->desc.name); - return PTR_ERR(rdev); - } + rdev = devm_regulator_register(&pdev->dev, vrdesc, &config); + if (IS_ERR(rdev)) + return dev_err_probe(&pdev->dev, PTR_ERR(rdev), + "failed to register %s\n", vrdesc->name); } return 0; } +static const struct of_device_id mtk_dvfsrc_regulator_match[] = { + { .compatible = "mediatek,mt6873-dvfsrc-regulator", .data = &mt6873_data }, + { .compatible = "mediatek,mt8183-dvfsrc-regulator", .data = &mt8183_data }, + { .compatible = "mediatek,mt8192-dvfsrc-regulator", .data = &mt6873_data }, + { .compatible = "mediatek,mt8195-dvfsrc-regulator", .data = &mt8195_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mtk_dvfsrc_regulator_match); + static struct platform_driver mtk_dvfsrc_regulator_driver = { .driver = { .name = "mtk-dvfsrc-regulator", + .of_match_table = mtk_dvfsrc_regulator_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = dvfsrc_vcore_regulator_probe, }; +module_platform_driver(mtk_dvfsrc_regulator_driver); -static int __init mtk_dvfsrc_regulator_init(void) -{ - return platform_driver_register(&mtk_dvfsrc_regulator_driver); -} -subsys_initcall(mtk_dvfsrc_regulator_init); - -static void __exit mtk_dvfsrc_regulator_exit(void) -{ - platform_driver_unregister(&mtk_dvfsrc_regulator_driver); -} -module_exit(mtk_dvfsrc_regulator_exit); - +MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>"); MODULE_AUTHOR("Arvin wang <arvin.wang@mediatek.com>"); -MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MediaTek DVFS Resource Collector Regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 03afc160fc72..011088c57891 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -125,6 +125,9 @@ static int of_get_regulation_constraints(struct device *dev, if (constraints->min_uA != constraints->max_uA) constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT; + if (!of_property_read_u32(np, "regulator-power-budget-milliwatt", &pval)) + constraints->pw_budget_mW = pval; + constraints->boot_on = of_property_read_bool(np, "regulator-boot-on"); constraints->always_on = of_property_read_bool(np, "regulator-always-on"); if (!constraints->always_on) /* status change should be possible. */ @@ -175,7 +178,7 @@ static int of_get_regulation_constraints(struct device *dev, if (!ret) constraints->enable_time = pval; - ret = of_property_read_u32(np, "regulator-uv-survival-time-ms", &pval); + ret = of_property_read_u32(np, "regulator-uv-less-critical-window-ms", &pval); if (!ret) constraints->uv_less_critical_window_ms = pval; else @@ -338,8 +341,10 @@ static int of_get_regulation_constraints(struct device *dev, * @desc: regulator description * * Populates regulator_init_data structure by extracting data from device - * tree node, returns a pointer to the populated structure or NULL if memory - * alloc fails. + * tree node. + * + * Return: Pointer to a populated &struct regulator_init_data or NULL if + * memory allocation fails. */ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, struct device_node *node, @@ -391,7 +396,7 @@ static void devm_of_regulator_put_matches(struct device *dev, void *res) * in place and an additional of_node reference is taken for each matched * regulator. * - * Returns the number of matches found or a negative error code on failure. + * Return: The number of matches found or a negative error number on failure. */ int of_regulator_match(struct device *dev, struct device_node *node, struct of_regulator_match *matches, @@ -444,7 +449,7 @@ int of_regulator_match(struct device *dev, struct device_node *node, "failed to parse DT for regulator %pOFn\n", child); of_node_put(child); - return -EINVAL; + goto err_put; } match->of_node = of_node_get(child); count++; @@ -453,6 +458,18 @@ int of_regulator_match(struct device *dev, struct device_node *node, } return count; + +err_put: + for (i = 0; i < num_matches; i++) { + struct of_regulator_match *match = &matches[i]; + + match->init_data = NULL; + if (match->of_node) { + of_node_put(match->of_node); + match->of_node = NULL; + } + } + return -EINVAL; } EXPORT_SYMBOL_GPL(of_regulator_match); @@ -550,7 +567,73 @@ error: return NULL; } -struct regulator_dev *of_find_regulator_by_node(struct device_node *np) +/** + * of_get_child_regulator - get a child regulator device node + * based on supply name + * @parent: Parent device node + * @prop_name: Combination regulator supply name and "-supply" + * + * Traverse all child nodes. + * Extract the child regulator device node corresponding to the supply name. + * + * Return: Pointer to the &struct device_node corresponding to the regulator + * if found, or %NULL if not found. + */ +static struct device_node *of_get_child_regulator(struct device_node *parent, + const char *prop_name) +{ + struct device_node *regnode = NULL; + struct device_node *child = NULL; + + for_each_child_of_node(parent, child) { + regnode = of_parse_phandle(child, prop_name, 0); + if (regnode) + goto err_node_put; + + regnode = of_get_child_regulator(child, prop_name); + if (regnode) + goto err_node_put; + } + return NULL; + +err_node_put: + of_node_put(child); + return regnode; +} + +/** + * of_get_regulator - get a regulator device node based on supply name + * @dev: Device pointer for dev_printk() messages + * @node: Device node pointer for supply property lookup + * @supply: regulator supply name + * + * Extract the regulator device node corresponding to the supply name. + * + * Return: Pointer to the &struct device_node corresponding to the regulator + * if found, or %NULL if not found. + */ +static struct device_node *of_get_regulator(struct device *dev, struct device_node *node, + const char *supply) +{ + struct device_node *regnode = NULL; + char prop_name[64]; /* 64 is max size of property name */ + + dev_dbg(dev, "Looking up %s-supply from device node %pOF\n", supply, node); + + snprintf(prop_name, 64, "%s-supply", supply); + regnode = of_parse_phandle(node, prop_name, 0); + if (regnode) + return regnode; + + regnode = of_get_child_regulator(dev->of_node, prop_name); + if (regnode) + return regnode; + + dev_dbg(dev, "Looking up %s property in node %pOF failed\n", prop_name, dev->of_node); + return NULL; +} + +static struct regulator_dev *of_find_regulator_by_node(struct device_node *np) { struct device *dev; @@ -559,6 +642,83 @@ struct regulator_dev *of_find_regulator_by_node(struct device_node *np) return dev ? dev_to_rdev(dev) : NULL; } +/** + * of_regulator_dev_lookup - lookup a regulator device with device tree only + * @dev: Device pointer for regulator supply lookup. + * @np: Device node pointer for regulator supply lookup. + * @supply: Supply name or regulator ID. + * + * Return: Pointer to the &struct regulator_dev on success, or ERR_PTR() + * encoded value on error. + * + * If successful, returns a pointer to the &struct regulator_dev that + * corresponds to the name @supply and with the embedded &struct device + * refcount incremented by one. The refcount must be dropped by calling + * put_device(). + * + * On failure one of the following ERR_PTR() encoded values is returned: + * * -%ENODEV if lookup fails permanently. + * * -%EPROBE_DEFER if lookup could succeed in the future. + */ +struct regulator_dev *of_regulator_dev_lookup(struct device *dev, struct device_node *np, + const char *supply) +{ + struct regulator_dev *r; + struct device_node *node; + + node = of_get_regulator(dev, np, supply); + if (node) { + r = of_find_regulator_by_node(node); + of_node_put(node); + if (r) + return r; + + /* + * We have a node, but there is no device. + * assume it has not registered yet. + */ + return ERR_PTR(-EPROBE_DEFER); + } + + return ERR_PTR(-ENODEV); +} + +struct regulator *_of_regulator_get(struct device *dev, struct device_node *node, + const char *id, enum regulator_get_type get_type) +{ + struct regulator_dev *r; + int ret; + + ret = _regulator_get_common_check(dev, id, get_type); + if (ret) + return ERR_PTR(ret); + + r = of_regulator_dev_lookup(dev, node, id); + return _regulator_get_common(r, dev, id, get_type); +} + +/** + * of_regulator_get_optional - get optional regulator via device tree lookup + * @dev: device used for dev_printk() messages + * @node: device node for regulator "consumer" + * @id: Supply name + * + * Return: pointer to struct regulator corresponding to the regulator producer, + * or PTR_ERR() encoded error number. + * + * This is intended for use by consumers that want to get a regulator + * supply directly from a device node, and can and want to deal with + * absence of such supplies. This will _not_ consider supply aliases. + * See regulator_dev_lookup(). + */ +struct regulator *of_regulator_get_optional(struct device *dev, + struct device_node *node, + const char *id) +{ + return _of_regulator_get(dev, node, id, OPTIONAL_GET); +} +EXPORT_SYMBOL_GPL(of_regulator_get_optional); + /* * Returns number of regulators coupled with rdev. */ @@ -619,7 +779,7 @@ static bool of_coupling_find_node(struct device_node *src, * - all coupled regulators have the same number of regulator_dev phandles * - all regulators are linked to each other * - * Returns true if all conditions are met. + * Return: True if all conditions are met; false otherwise. */ bool of_check_coupling_data(struct regulator_dev *rdev) { @@ -690,8 +850,8 @@ clean: * "regulator-coupled-with" property * @index: Index in phandles array * - * Returns the regulator_dev pointer parsed from DTS. If it has not been yet - * registered, returns NULL + * Return: Pointer to the &struct regulator_dev parsed from DTS, or %NULL if + * it has not yet been registered. */ struct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev, int index) @@ -735,31 +895,32 @@ static int is_supply_name(const char *name) return 0; } -/* +/** * of_regulator_bulk_get_all - get multiple regulator consumers * * @dev: Device to supply * @np: device node to search for consumers * @consumers: Configuration of consumers; clients are stored here. * - * @return number of regulators on success, an errno on failure. - * * This helper function allows drivers to get several regulator * consumers in one operation. If any of the regulators cannot be * acquired then any regulators that were allocated will be freed - * before returning to the caller. + * before returning to the caller, and @consumers will not be + * changed. + * + * Return: Number of regulators on success, or a negative error number + * on failure. */ int of_regulator_bulk_get_all(struct device *dev, struct device_node *np, struct regulator_bulk_data **consumers) { int num_consumers = 0; struct regulator *tmp; + struct regulator_bulk_data *_consumers = NULL; struct property *prop; int i, n = 0, ret; char name[64]; - *consumers = NULL; - /* * first pass: get numbers of xxx-supply * second pass: fill consumers @@ -769,7 +930,7 @@ restart: i = is_supply_name(prop->name); if (i == 0) continue; - if (!*consumers) { + if (!_consumers) { num_consumers++; continue; } else { @@ -777,28 +938,31 @@ restart: name[i] = '\0'; tmp = regulator_get(dev, name); if (IS_ERR(tmp)) { - ret = -EINVAL; + ret = PTR_ERR(tmp); goto error; } - (*consumers)[n].consumer = tmp; + _consumers[n].consumer = tmp; n++; continue; } } - if (*consumers) + if (_consumers) { + *consumers = _consumers; return num_consumers; + } if (num_consumers == 0) return 0; - *consumers = kmalloc_array(num_consumers, + _consumers = kmalloc_array(num_consumers, sizeof(struct regulator_bulk_data), GFP_KERNEL); - if (!*consumers) + if (!_consumers) return -ENOMEM; goto restart; error: while (--n >= 0) - regulator_put(consumers[n]->consumer); + regulator_put(_consumers[n].consumer); + kfree(_consumers); return ret; } EXPORT_SYMBOL_GPL(of_regulator_bulk_get_all); diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 2ab365d2749f..faa6b79c27d7 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -53,7 +53,7 @@ static const struct regmap_config pca9450_regmap_config = { .val_bits = 8, .volatile_table = &pca9450_volatile_regs, .max_register = PCA9450_MAX_REGISTER - 1, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* @@ -107,6 +107,14 @@ static const struct linear_range pca9450_dvs_buck_volts[] = { }; /* + * BUCK1/3 + * 0.65 to 2.2375V (12.5mV step) + */ +static const struct linear_range pca9451a_dvs_buck_volts[] = { + REGULATOR_LINEAR_RANGE(650000, 0x00, 0x7F, 12500), +}; + +/* * BUCK4/5/6 * 0.6V to 3.4V (25mV step) */ @@ -239,6 +247,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .ramp_mask = BUCK1_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, .of_parse_cb = pca9450_set_dvs_levels, }, @@ -264,6 +273,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK2OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK2CTRL, .enable_mask = BUCK2_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ_STBYREQ, .ramp_reg = PCA9450_REG_BUCK2CTRL, .ramp_mask = BUCK2_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, @@ -293,6 +303,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK3OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK3CTRL, .enable_mask = BUCK3_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .ramp_reg = PCA9450_REG_BUCK3CTRL, .ramp_mask = BUCK3_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, @@ -322,6 +333,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK4OUT_MASK, .enable_reg = PCA9450_REG_BUCK4CTRL, .enable_mask = BUCK4_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -340,6 +352,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK5OUT_MASK, .enable_reg = PCA9450_REG_BUCK5CTRL, .enable_mask = BUCK5_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -358,6 +371,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK6OUT_MASK, .enable_reg = PCA9450_REG_BUCK6CTRL, .enable_mask = BUCK6_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -473,6 +487,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK1OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK1CTRL, .enable_mask = BUCK1_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .ramp_reg = PCA9450_REG_BUCK1CTRL, .ramp_mask = BUCK1_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, @@ -502,6 +517,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK2OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK2CTRL, .enable_mask = BUCK2_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ_STBYREQ, .ramp_reg = PCA9450_REG_BUCK2CTRL, .ramp_mask = BUCK2_RAMP_MASK, .ramp_delay_table = pca9450_dvs_buck_ramp_table, @@ -531,6 +547,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK4OUT_MASK, .enable_reg = PCA9450_REG_BUCK4CTRL, .enable_mask = BUCK4_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -549,6 +566,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK5OUT_MASK, .enable_reg = PCA9450_REG_BUCK5CTRL, .enable_mask = BUCK5_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -567,6 +585,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK6OUT_MASK, .enable_reg = PCA9450_REG_BUCK6CTRL, .enable_mask = BUCK6_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, .owner = THIS_MODULE, }, }, @@ -662,6 +681,196 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { }, }; +static const struct pca9450_regulator_desc pca9451a_regulators[] = { + { + .desc = { + .name = "buck1", + .of_match = of_match_ptr("BUCK1"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_BUCK1, + .ops = &pca9450_dvs_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_BUCK1_VOLTAGE_NUM, + .linear_ranges = pca9451a_dvs_buck_volts, + .n_linear_ranges = ARRAY_SIZE(pca9451a_dvs_buck_volts), + .vsel_reg = PCA9450_REG_BUCK1OUT_DVS0, + .vsel_mask = BUCK1OUT_DVS0_MASK, + .enable_reg = PCA9450_REG_BUCK1CTRL, + .enable_mask = BUCK1_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, + .ramp_mask = BUCK1_RAMP_MASK, + .ramp_delay_table = pca9450_dvs_buck_ramp_table, + .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), + .owner = THIS_MODULE, + .of_parse_cb = pca9450_set_dvs_levels, + }, + .dvs = { + .run_reg = PCA9450_REG_BUCK1OUT_DVS0, + .run_mask = BUCK1OUT_DVS0_MASK, + .standby_reg = PCA9450_REG_BUCK1OUT_DVS1, + .standby_mask = BUCK1OUT_DVS1_MASK, + }, + }, + { + .desc = { + .name = "buck2", + .of_match = of_match_ptr("BUCK2"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_BUCK2, + .ops = &pca9450_dvs_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_BUCK2_VOLTAGE_NUM, + .linear_ranges = pca9450_dvs_buck_volts, + .n_linear_ranges = ARRAY_SIZE(pca9450_dvs_buck_volts), + .vsel_reg = PCA9450_REG_BUCK2OUT_DVS0, + .vsel_mask = BUCK2OUT_DVS0_MASK, + .enable_reg = PCA9450_REG_BUCK2CTRL, + .enable_mask = BUCK2_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ_STBYREQ, + .ramp_mask = BUCK2_RAMP_MASK, + .ramp_delay_table = pca9450_dvs_buck_ramp_table, + .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), + .owner = THIS_MODULE, + .of_parse_cb = pca9450_set_dvs_levels, + }, + .dvs = { + .run_reg = PCA9450_REG_BUCK2OUT_DVS0, + .run_mask = BUCK2OUT_DVS0_MASK, + .standby_reg = PCA9450_REG_BUCK2OUT_DVS1, + .standby_mask = BUCK2OUT_DVS1_MASK, + }, + }, + { + .desc = { + .name = "buck4", + .of_match = of_match_ptr("BUCK4"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_BUCK4, + .ops = &pca9450_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_BUCK4_VOLTAGE_NUM, + .linear_ranges = pca9450_buck_volts, + .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts), + .vsel_reg = PCA9450_REG_BUCK4OUT, + .vsel_mask = BUCK4OUT_MASK, + .enable_reg = PCA9450_REG_BUCK4CTRL, + .enable_mask = BUCK4_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, + .owner = THIS_MODULE, + }, + }, + { + .desc = { + .name = "buck5", + .of_match = of_match_ptr("BUCK5"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_BUCK5, + .ops = &pca9450_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_BUCK5_VOLTAGE_NUM, + .linear_ranges = pca9450_buck_volts, + .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts), + .vsel_reg = PCA9450_REG_BUCK5OUT, + .vsel_mask = BUCK5OUT_MASK, + .enable_reg = PCA9450_REG_BUCK5CTRL, + .enable_mask = BUCK5_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, + .owner = THIS_MODULE, + }, + }, + { + .desc = { + .name = "buck6", + .of_match = of_match_ptr("BUCK6"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_BUCK6, + .ops = &pca9450_buck_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_BUCK6_VOLTAGE_NUM, + .linear_ranges = pca9450_buck_volts, + .n_linear_ranges = ARRAY_SIZE(pca9450_buck_volts), + .vsel_reg = PCA9450_REG_BUCK6OUT, + .vsel_mask = BUCK6OUT_MASK, + .enable_reg = PCA9450_REG_BUCK6CTRL, + .enable_mask = BUCK6_ENMODE_MASK, + .enable_val = BUCK_ENMODE_ONREQ, + .owner = THIS_MODULE, + }, + }, + { + .desc = { + .name = "ldo1", + .of_match = of_match_ptr("LDO1"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_LDO1, + .ops = &pca9450_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_LDO1_VOLTAGE_NUM, + .linear_ranges = pca9450_ldo1_volts, + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo1_volts), + .vsel_reg = PCA9450_REG_LDO1CTRL, + .vsel_mask = LDO1OUT_MASK, + .enable_reg = PCA9450_REG_LDO1CTRL, + .enable_mask = LDO1_EN_MASK, + .owner = THIS_MODULE, + }, + }, + { + .desc = { + .name = "ldo3", + .of_match = of_match_ptr("LDO3"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_LDO3, + .ops = &pca9450_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_LDO3_VOLTAGE_NUM, + .linear_ranges = pca9450_ldo34_volts, + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts), + .vsel_reg = PCA9450_REG_LDO3CTRL, + .vsel_mask = LDO3OUT_MASK, + .enable_reg = PCA9450_REG_LDO3CTRL, + .enable_mask = LDO3_EN_MASK, + .owner = THIS_MODULE, + }, + }, + { + .desc = { + .name = "ldo4", + .of_match = of_match_ptr("LDO4"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_LDO4, + .ops = &pca9450_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_LDO4_VOLTAGE_NUM, + .linear_ranges = pca9450_ldo34_volts, + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts), + .vsel_reg = PCA9450_REG_LDO4CTRL, + .vsel_mask = LDO4OUT_MASK, + .enable_reg = PCA9450_REG_LDO4CTRL, + .enable_mask = LDO4_EN_MASK, + .owner = THIS_MODULE, + }, + }, + { + .desc = { + .name = "ldo5", + .of_match = of_match_ptr("LDO5"), + .regulators_node = of_match_ptr("regulators"), + .id = PCA9450_LDO5, + .ops = &pca9450_ldo_regulator_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = PCA9450_LDO5_VOLTAGE_NUM, + .linear_ranges = pca9450_ldo5_volts, + .n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts), + .vsel_reg = PCA9450_REG_LDO5CTRL_H, + .vsel_mask = LDO5HOUT_MASK, + .enable_reg = PCA9450_REG_LDO5CTRL_H, + .enable_mask = LDO5H_EN_MASK, + .owner = THIS_MODULE, + }, + }, +}; + static irqreturn_t pca9450_irq_handler(int irq, void *data) { struct pca9450 *pca9450 = data; @@ -711,11 +920,6 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) unsigned int reset_ctrl; int ret; - if (!i2c->irq) { - dev_err(&i2c->dev, "No IRQ configured?\n"); - return -EINVAL; - } - pca9450 = devm_kzalloc(&i2c->dev, sizeof(struct pca9450), GFP_KERNEL); if (!pca9450) return -ENOMEM; @@ -729,6 +933,11 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) regulator_desc = pca9450bc_regulators; pca9450->rcnt = ARRAY_SIZE(pca9450bc_regulators); break; + case PCA9450_TYPE_PCA9451A: + case PCA9450_TYPE_PCA9452: + regulator_desc = pca9451a_regulators; + pca9450->rcnt = ARRAY_SIZE(pca9451a_regulators); + break; default: dev_err(&i2c->dev, "Unknown device type"); return -EINVAL; @@ -742,24 +951,21 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) pca9450->regmap = devm_regmap_init_i2c(i2c, &pca9450_regmap_config); - if (IS_ERR(pca9450->regmap)) { - dev_err(&i2c->dev, "regmap initialization failed\n"); - return PTR_ERR(pca9450->regmap); - } + if (IS_ERR(pca9450->regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->regmap), + "regmap initialization failed\n"); ret = regmap_read(pca9450->regmap, PCA9450_REG_DEV_ID, &device_id); - if (ret) { - dev_err(&i2c->dev, "Read device id error\n"); - return ret; - } + if (ret) + return dev_err_probe(&i2c->dev, ret, "Read device id error\n"); /* Check your board and dts for match the right pmic */ if (((device_id >> 4) != 0x1 && type == PCA9450_TYPE_PCA9450A) || - ((device_id >> 4) != 0x3 && type == PCA9450_TYPE_PCA9450BC)) { - dev_err(&i2c->dev, "Device id(%x) mismatched\n", - device_id >> 4); - return -EINVAL; - } + ((device_id >> 4) != 0x3 && type == PCA9450_TYPE_PCA9450BC) || + ((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9451A) || + ((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9452)) + return dev_err_probe(&i2c->dev, -EINVAL, + "Device id(%x) mismatched\n", device_id >> 4); for (i = 0; i < pca9450->rcnt; i++) { const struct regulator_desc *desc; @@ -769,45 +975,41 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) r = ®ulator_desc[i]; desc = &r->desc; + if (type == PCA9450_TYPE_PCA9451A && !strcmp(desc->name, "ldo3")) + continue; + config.regmap = pca9450->regmap; config.dev = pca9450->dev; rdev = devm_regulator_register(pca9450->dev, desc, &config); - if (IS_ERR(rdev)) { - ret = PTR_ERR(rdev); - dev_err(pca9450->dev, - "Failed to register regulator(%s): %d\n", - desc->name, ret); - return ret; - } + if (IS_ERR(rdev)) + return dev_err_probe(pca9450->dev, PTR_ERR(rdev), + "Failed to register regulator(%s)\n", desc->name); } - ret = devm_request_threaded_irq(pca9450->dev, pca9450->irq, NULL, - pca9450_irq_handler, - (IRQF_TRIGGER_FALLING | IRQF_ONESHOT), - "pca9450-irq", pca9450); - if (ret != 0) { - dev_err(pca9450->dev, "Failed to request IRQ: %d\n", - pca9450->irq); - return ret; - } - /* Unmask all interrupt except PWRON/WDOG/RSVD */ - ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_INT1_MSK, - IRQ_VR_FLT1 | IRQ_VR_FLT2 | IRQ_LOWVSYS | - IRQ_THERM_105 | IRQ_THERM_125, - IRQ_PWRON | IRQ_WDOGB | IRQ_RSVD); - if (ret) { - dev_err(&i2c->dev, "Unmask irq error\n"); - return ret; + if (pca9450->irq) { + ret = devm_request_threaded_irq(pca9450->dev, pca9450->irq, NULL, + pca9450_irq_handler, + (IRQF_TRIGGER_FALLING | IRQF_ONESHOT), + "pca9450-irq", pca9450); + if (ret != 0) + return dev_err_probe(pca9450->dev, ret, "Failed to request IRQ: %d\n", + pca9450->irq); + + /* Unmask all interrupt except PWRON/WDOG/RSVD */ + ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_INT1_MSK, + IRQ_VR_FLT1 | IRQ_VR_FLT2 | IRQ_LOWVSYS | + IRQ_THERM_105 | IRQ_THERM_125, + IRQ_PWRON | IRQ_WDOGB | IRQ_RSVD); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); } /* Clear PRESET_EN bit in BUCK123_DVS to use DVS registers */ ret = regmap_clear_bits(pca9450->regmap, PCA9450_REG_BUCK123_DVS, BUCK123_PRESET_EN); - if (ret) { - dev_err(&i2c->dev, "Failed to clear PRESET_EN bit: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&i2c->dev, ret, "Failed to clear PRESET_EN bit\n"); if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset")) reset_ctrl = WDOG_B_CFG_WARM; @@ -817,20 +1019,16 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) /* Set reset behavior on assertion of WDOG_B signal */ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL, WDOG_B_CFG_MASK, reset_ctrl); - if (ret) { - dev_err(&i2c->dev, "Failed to set WDOG_B reset behavior\n"); - return ret; - } + if (ret) + return dev_err_probe(&i2c->dev, ret, "Failed to set WDOG_B reset behavior\n"); if (of_property_read_bool(i2c->dev.of_node, "nxp,i2c-lt-enable")) { /* Enable I2C Level Translator */ ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_CONFIG2, I2C_LT_MASK, I2C_LT_ON_STANDBY_RUN); - if (ret) { - dev_err(&i2c->dev, - "Failed to enable I2C level translator\n"); - return ret; - } + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to enable I2C level translator\n"); } /* @@ -840,13 +1038,13 @@ static int pca9450_i2c_probe(struct i2c_client *i2c) */ pca9450->sd_vsel_gpio = gpiod_get_optional(pca9450->dev, "sd-vsel", GPIOD_OUT_HIGH); - if (IS_ERR(pca9450->sd_vsel_gpio)) { - dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n"); - return PTR_ERR(pca9450->sd_vsel_gpio); - } + if (IS_ERR(pca9450->sd_vsel_gpio)) + return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->sd_vsel_gpio), + "Failed to get SD_VSEL GPIO\n"); dev_info(&i2c->dev, "%s probed.\n", - type == PCA9450_TYPE_PCA9450A ? "pca9450a" : "pca9450bc"); + type == PCA9450_TYPE_PCA9450A ? "pca9450a" : + (type == PCA9450_TYPE_PCA9451A ? "pca9451a" : "pca9450bc")); return 0; } @@ -864,6 +1062,14 @@ static const struct of_device_id pca9450_of_match[] = { .compatible = "nxp,pca9450c", .data = (void *)PCA9450_TYPE_PCA9450BC, }, + { + .compatible = "nxp,pca9451a", + .data = (void *)PCA9450_TYPE_PCA9451A, + }, + { + .compatible = "nxp,pca9452", + .data = (void *)PCA9450_TYPE_PCA9452, + }, { } }; MODULE_DEVICE_TABLE(of, pca9450_of_match); diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 319a88412154..441c9344aef7 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -105,7 +105,7 @@ struct pcap_regulator { .lowpwr = _lowpwr, \ } -static struct pcap_regulator vreg_table[] = { +static const struct pcap_regulator vreg_table[] = { VREG_INFO(V1, PCAP_REG_VREG1, 1, 2, 18, 0), VREG_INFO(V2, PCAP_REG_VREG1, 5, 6, 19, 22), VREG_INFO(V3, PCAP_REG_VREG1, 7, 8, 20, 23), @@ -141,7 +141,7 @@ static struct pcap_regulator vreg_table[] = { static int pcap_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { - struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; + const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); /* the regulator doesn't support voltage switching */ @@ -155,7 +155,7 @@ static int pcap_regulator_set_voltage_sel(struct regulator_dev *rdev, static int pcap_regulator_get_voltage_sel(struct regulator_dev *rdev) { - struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; + const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); u32 tmp; @@ -169,7 +169,7 @@ static int pcap_regulator_get_voltage_sel(struct regulator_dev *rdev) static int pcap_regulator_enable(struct regulator_dev *rdev) { - struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; + const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); if (vreg->en == NA) @@ -180,7 +180,7 @@ static int pcap_regulator_enable(struct regulator_dev *rdev) static int pcap_regulator_disable(struct regulator_dev *rdev) { - struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; + const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); if (vreg->en == NA) @@ -191,7 +191,7 @@ static int pcap_regulator_disable(struct regulator_dev *rdev) static int pcap_regulator_is_enabled(struct regulator_dev *rdev) { - struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; + const struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); u32 tmp; diff --git a/drivers/regulator/pf8x00-regulator.c b/drivers/regulator/pf8x00-regulator.c index b0781d9a1058..ea3611de42b4 100644 --- a/drivers/regulator/pf8x00-regulator.c +++ b/drivers/regulator/pf8x00-regulator.c @@ -142,7 +142,7 @@ static const struct regmap_config pf8x00_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = PF8X00_PAGE_SELECT, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* VLDOx output: 1.5V to 5.0V */ @@ -596,10 +596,10 @@ static const struct of_device_id pf8x00_dt_ids[] = { MODULE_DEVICE_TABLE(of, pf8x00_dt_ids); static const struct i2c_device_id pf8x00_i2c_id[] = { - { "pf8100", 0 }, - { "pf8121a", 0 }, - { "pf8200", 0 }, - {}, + { "pf8100" }, + { "pf8121a" }, + { "pf8200" }, + {} }; MODULE_DEVICE_TABLE(i2c, pf8x00_i2c_id); diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 46854602b3ea..7d56c22b5e40 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -76,7 +76,7 @@ struct pfuze_chip { struct device *dev; struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR]; - struct pfuze_regulator *pfuze_regulators; + const struct pfuze_regulator *pfuze_regulators; }; static const int pfuze100_swbst[] = { @@ -367,7 +367,7 @@ static const struct regulator_ops pfuze3000_sw_regulator_ops = { } /* PFUZE100 */ -static struct pfuze_regulator pfuze100_regulators[] = { +static const struct pfuze_regulator pfuze100_regulators[] = { PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000), PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), @@ -386,7 +386,7 @@ static struct pfuze_regulator pfuze100_regulators[] = { PFUZE100_COIN_REG(PFUZE100, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin), }; -static struct pfuze_regulator pfuze200_regulators[] = { +static const struct pfuze_regulator pfuze200_regulators[] = { PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), @@ -403,7 +403,7 @@ static struct pfuze_regulator pfuze200_regulators[] = { PFUZE100_COIN_REG(PFUZE200, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin), }; -static struct pfuze_regulator pfuze3000_regulators[] = { +static const struct pfuze_regulator pfuze3000_regulators[] = { PFUZE3000_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a), PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000), PFUZE3000_SW_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), @@ -419,7 +419,7 @@ static struct pfuze_regulator pfuze3000_regulators[] = { PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), }; -static struct pfuze_regulator pfuze3001_regulators[] = { +static const struct pfuze_regulator pfuze3001_regulators[] = { PFUZE3000_SW_REG(PFUZE3001, SW1, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a), PFUZE3000_SW_REG(PFUZE3001, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), PFUZE3000_SW3_REG(PFUZE3001, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000), @@ -680,7 +680,7 @@ static const struct regmap_config pfuze_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = PFUZE_NUMREGS - 1, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int pfuze100_regulator_probe(struct i2c_client *client) diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c index aa90360fa046..ae1c4b9daaa1 100644 --- a/drivers/regulator/pv88060-regulator.c +++ b/drivers/regulator/pv88060-regulator.c @@ -360,8 +360,8 @@ static int pv88060_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id pv88060_i2c_id[] = { - {"pv88060", 0}, - {}, + { "pv88060" }, + {} }; MODULE_DEVICE_TABLE(i2c, pv88060_i2c_id); diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c index f4acde4d56c8..3c48757bbbda 100644 --- a/drivers/regulator/pv88090-regulator.c +++ b/drivers/regulator/pv88090-regulator.c @@ -381,8 +381,8 @@ static int pv88090_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id pv88090_i2c_id[] = { - {"pv88090", 0}, - {}, + { "pv88090" }, + {} }; MODULE_DEVICE_TABLE(i2c, pv88090_i2c_id); diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 60cfcd741c2a..7434b6b22d32 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -271,11 +271,10 @@ static int pwm_regulator_init_table(struct platform_device *pdev, of_find_property(np, "voltage-table", &length); if ((length < sizeof(*duty_cycle_table)) || - (length % sizeof(*duty_cycle_table))) { - dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n", - length); - return -EINVAL; - } + (length % sizeof(*duty_cycle_table))) + return dev_err_probe(&pdev->dev, -EINVAL, + "voltage-table length(%d) is invalid\n", + length); duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); if (!duty_cycle_table) @@ -284,10 +283,9 @@ static int pwm_regulator_init_table(struct platform_device *pdev, ret = of_property_read_u32_array(np, "voltage-table", (u32 *)duty_cycle_table, length / sizeof(u32)); - if (ret) { - dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to read voltage-table\n"); drvdata->state = -ENOTRECOVERABLE; drvdata->duty_cycle_table = duty_cycle_table; @@ -359,10 +357,9 @@ static int pwm_regulator_probe(struct platform_device *pdev) enum gpiod_flags gpio_flags; int ret; - if (!np) { - dev_err(&pdev->dev, "Device Tree node missing\n"); - return -EINVAL; - } + if (!np) + return dev_err_probe(&pdev->dev, -EINVAL, + "Device Tree node missing\n"); drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) @@ -400,8 +397,7 @@ static int pwm_regulator_probe(struct platform_device *pdev) gpio_flags); if (IS_ERR(drvdata->enb_gpio)) { ret = PTR_ERR(drvdata->enb_gpio); - dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret); - return ret; + return dev_err_probe(&pdev->dev, ret, "Failed to get enable GPIO\n"); } ret = pwm_adjust_config(drvdata->pwm); @@ -409,19 +405,17 @@ static int pwm_regulator_probe(struct platform_device *pdev) return ret; ret = pwm_regulator_init_boot_on(pdev, drvdata, init_data); - if (ret) { - dev_err(&pdev->dev, "Failed to apply boot_on settings: %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to apply boot_on settings\n"); regulator = devm_regulator_register(&pdev->dev, &drvdata->desc, &config); if (IS_ERR(regulator)) { ret = PTR_ERR(regulator); - dev_err(&pdev->dev, "Failed to register regulator %s: %d\n", - drvdata->desc.name, ret); - return ret; + return dev_err_probe(&pdev->dev, ret, + "Failed to register regulator %s\n", + drvdata->desc.name); } return 0; diff --git a/drivers/regulator/qcom-pm8008-regulator.c b/drivers/regulator/qcom-pm8008-regulator.c new file mode 100644 index 000000000000..da017c1969d0 --- /dev/null +++ b/drivers/regulator/qcom-pm8008-regulator.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2024 Linaro Limited + */ + +#include <linux/array_size.h> +#include <linux/bits.h> +#include <linux/device.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +#include <asm/byteorder.h> + +#define DEFAULT_VOLTAGE_STEPPER_RATE 38400 + +#define LDO_STEPPER_CTL_REG 0x3b +#define STEP_RATE_MASK GENMASK(1, 0) + +#define LDO_VSET_LB_REG 0x40 + +#define LDO_ENABLE_REG 0x46 +#define ENABLE_BIT BIT(7) + +struct pm8008_regulator { + struct regmap *regmap; + struct regulator_desc desc; + unsigned int base; +}; + +struct pm8008_regulator_data { + const char *name; + const char *supply_name; + unsigned int base; + int min_dropout_uV; + const struct linear_range *voltage_range; +}; + +static const struct linear_range nldo_ranges[] = { + REGULATOR_LINEAR_RANGE(528000, 0, 122, 8000), +}; + +static const struct linear_range pldo_ranges[] = { + REGULATOR_LINEAR_RANGE(1504000, 0, 237, 8000), +}; + +static const struct pm8008_regulator_data pm8008_reg_data[] = { + { "ldo1", "vdd-l1-l2", 0x4000, 225000, nldo_ranges, }, + { "ldo2", "vdd-l1-l2", 0x4100, 225000, nldo_ranges, }, + { "ldo3", "vdd-l3-l4", 0x4200, 300000, pldo_ranges, }, + { "ldo4", "vdd-l3-l4", 0x4300, 300000, pldo_ranges, }, + { "ldo5", "vdd-l5", 0x4400, 200000, pldo_ranges, }, + { "ldo6", "vdd-l6", 0x4500, 200000, pldo_ranges, }, + { "ldo7", "vdd-l7", 0x4600, 200000, pldo_ranges, }, +}; + +static int pm8008_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) +{ + struct pm8008_regulator *preg = rdev_get_drvdata(rdev); + unsigned int mV; + __le16 val; + int ret; + + ret = regulator_list_voltage_linear_range(rdev, sel); + if (ret < 0) + return ret; + + mV = DIV_ROUND_UP(ret, 1000); + + val = cpu_to_le16(mV); + + ret = regmap_bulk_write(preg->regmap, preg->base + LDO_VSET_LB_REG, + &val, sizeof(val)); + if (ret < 0) + return ret; + + return 0; +} + +static int pm8008_regulator_get_voltage_sel(struct regulator_dev *rdev) +{ + struct pm8008_regulator *preg = rdev_get_drvdata(rdev); + unsigned int uV; + __le16 val; + int ret; + + ret = regmap_bulk_read(preg->regmap, preg->base + LDO_VSET_LB_REG, + &val, sizeof(val)); + if (ret < 0) + return ret; + + uV = le16_to_cpu(val) * 1000; + + return (uV - preg->desc.min_uV) / preg->desc.uV_step; +} + +static const struct regulator_ops pm8008_regulator_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = pm8008_regulator_set_voltage_sel, + .get_voltage_sel = pm8008_regulator_get_voltage_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static int pm8008_regulator_probe(struct platform_device *pdev) +{ + const struct pm8008_regulator_data *data; + struct regulator_config config = {}; + struct device *dev = &pdev->dev; + struct pm8008_regulator *preg; + struct regulator_desc *desc; + struct regulator_dev *rdev; + struct regmap *regmap; + unsigned int val; + int ret, i; + + regmap = dev_get_regmap(dev->parent, "secondary"); + if (!regmap) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(pm8008_reg_data); i++) { + data = &pm8008_reg_data[i]; + + preg = devm_kzalloc(dev, sizeof(*preg), GFP_KERNEL); + if (!preg) + return -ENOMEM; + + preg->regmap = regmap; + preg->base = data->base; + + desc = &preg->desc; + + desc->name = data->name; + desc->supply_name = data->supply_name; + desc->of_match = data->name; + desc->regulators_node = of_match_ptr("regulators"); + desc->ops = &pm8008_regulator_ops; + desc->type = REGULATOR_VOLTAGE; + desc->owner = THIS_MODULE; + + desc->linear_ranges = data->voltage_range; + desc->n_linear_ranges = 1; + desc->uV_step = desc->linear_ranges[0].step; + desc->min_uV = desc->linear_ranges[0].min; + desc->n_voltages = linear_range_values_in_range(&desc->linear_ranges[0]); + + ret = regmap_read(regmap, preg->base + LDO_STEPPER_CTL_REG, &val); + if (ret < 0) { + dev_err(dev, "failed to read step rate: %d\n", ret); + return ret; + } + val &= STEP_RATE_MASK; + desc->ramp_delay = DEFAULT_VOLTAGE_STEPPER_RATE >> val; + + desc->min_dropout_uV = data->min_dropout_uV; + + desc->enable_reg = preg->base + LDO_ENABLE_REG; + desc->enable_mask = ENABLE_BIT; + + config.dev = dev->parent; + config.driver_data = preg; + config.regmap = regmap; + + rdev = devm_regulator_register(dev, desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "failed to register regulator %s: %d\n", + desc->name, ret); + return ret; + } + } + + return 0; +} + +static const struct platform_device_id pm8008_regulator_id_table[] = { + { "pm8008-regulator" }, + { } +}; +MODULE_DEVICE_TABLE(platform, pm8008_regulator_id_table); + +static struct platform_driver pm8008_regulator_driver = { + .driver = { + .name = "qcom-pm8008-regulator", + }, + .probe = pm8008_regulator_probe, + .id_table = pm8008_regulator_id_table, +}; +module_platform_driver(pm8008_regulator_driver); + +MODULE_DESCRIPTION("Qualcomm PM8008 PMIC regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/qcom-refgen-regulator.c b/drivers/regulator/qcom-refgen-regulator.c index 656fe330d38f..cfa72ce85bc8 100644 --- a/drivers/regulator/qcom-refgen-regulator.c +++ b/drivers/regulator/qcom-refgen-regulator.c @@ -62,7 +62,7 @@ static int qcom_sdm845_refgen_is_enabled(struct regulator_dev *rdev) return 1; } -static struct regulator_desc sdm845_refgen_desc = { +static const struct regulator_desc sdm845_refgen_desc = { .enable_time = 5, .name = "refgen", .owner = THIS_MODULE, @@ -74,7 +74,7 @@ static struct regulator_desc sdm845_refgen_desc = { }, }; -static struct regulator_desc sm8250_refgen_desc = { +static const struct regulator_desc sm8250_refgen_desc = { .enable_reg = REFGEN_REG_PWRDWN_CTRL5, .enable_mask = REFGEN_PWRDWN_CTRL5_MASK, .enable_val = REFGEN_PWRDWN_CTRL5_ENABLE, @@ -140,6 +140,7 @@ static const struct of_device_id qcom_refgen_match_table[] = { { .compatible = "qcom,sm8250-refgen-regulator", .data = &sm8250_refgen_desc }, { } }; +MODULE_DEVICE_TABLE(of, qcom_refgen_match_table); static struct platform_driver qcom_refgen_driver = { .probe = qcom_refgen_probe, diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 80e304711345..7870722b6ee2 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -158,7 +158,7 @@ struct rpmh_vreg_init_data { * @wait_for_ack: Boolean indicating if execution must wait until the * request has been acknowledged as complete * - * Return: 0 on success, errno on failure + * Return: 0 on success, or a negative error number on failure */ static int rpmh_regulator_send_request(struct rpmh_vreg *vreg, struct tcs_cmd *cmd, bool wait_for_ack) @@ -317,7 +317,7 @@ static unsigned int rpmh_regulator_vrm_get_mode(struct regulator_dev *rdev) * This function is used in the regulator_ops for VRM type RPMh regulator * devices. * - * Return: 0 on success, errno on failure + * Return: 0 on success, or a negative error number on failure */ static unsigned int rpmh_regulator_vrm_get_optimum_mode( struct regulator_dev *rdev, int input_uV, int output_uV, int load_uA) @@ -409,7 +409,7 @@ static const struct regulator_ops rpmh_regulator_xob_ops = { * @pmic_rpmh_data: Pointer to a null-terminated array of rpmh-regulator * resources defined for the top level PMIC device * - * Return: 0 on success, errno on failure + * Return: 0 on success, or a negative error number on failure */ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev, struct device_node *node, const char *pmic_id, @@ -843,26 +843,15 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = { .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, }; -static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = { +static const struct rpmh_vreg_hw_data pmic5_ftsmps525 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, .voltage_ranges = (struct linear_range[]) { REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000), + REGULATOR_LINEAR_RANGE(1376000, 268, 438, 8000), }, - .n_linear_ranges = 1, - .n_voltages = 268, - .pmic_mode_map = pmic_mode_map_pmic5_smps, - .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, -}; - -static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = { - .regulator_type = VRM, - .ops = &rpmh_regulator_vrm_ops, - .voltage_ranges = (struct linear_range[]) { - REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000), - }, - .n_linear_ranges = 1, - .n_voltages = 268, + .n_linear_ranges = 2, + .n_voltages = 439, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, }; @@ -1190,12 +1179,12 @@ static const struct rpmh_vreg_init_data pm8550_vreg_data[] = { }; static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_lv, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_mv, "vdd-s6"), + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), @@ -1203,14 +1192,14 @@ static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = { }; static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"), + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525, "vdd-s8"), RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), @@ -1218,14 +1207,14 @@ static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = { }; static const struct rpmh_vreg_init_data pmc8380_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"), + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525, "vdd-s8"), RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), @@ -1409,16 +1398,16 @@ static const struct rpmh_vreg_init_data pmx65_vreg_data[] = { }; static const struct rpmh_vreg_init_data pmx75_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"), - RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps525_lv, "vdd-s9"), - RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps525_lv, "vdd-s10"), + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525, "vdd-s8"), + RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps525, "vdd-s9"), + RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps525, "vdd-s10"), RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-18"), RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), @@ -1537,7 +1526,6 @@ static int rpmh_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct rpmh_vreg_init_data *vreg_data; - struct device_node *node; struct rpmh_vreg *vreg; const char *pmic_id; int ret; @@ -1552,19 +1540,15 @@ static int rpmh_regulator_probe(struct platform_device *pdev) return ret; } - for_each_available_child_of_node(dev->of_node, node) { + for_each_available_child_of_node_scoped(dev->of_node, node) { vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); - if (!vreg) { - of_node_put(node); + if (!vreg) return -ENOMEM; - } ret = rpmh_regulator_init_vreg(vreg, dev, node, pmic_id, vreg_data); - if (ret < 0) { - of_node_put(node); + if (ret < 0) return ret; - } } return 0; diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index d1be9568025e..25ed9f713974 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -11,11 +11,10 @@ #include <linux/regulator/of_regulator.h> #include <linux/soc/qcom/smd-rpm.h> +static struct qcom_smd_rpm *smd_vreg_rpm; + struct qcom_rpm_reg { struct device *dev; - - struct qcom_smd_rpm *rpm; - u32 type; u32 id; @@ -70,7 +69,7 @@ static int rpm_reg_write_active(struct qcom_rpm_reg *vreg) if (!reqlen) return 0; - ret = qcom_rpm_smd_write(vreg->rpm, QCOM_SMD_RPM_ACTIVE_STATE, + ret = qcom_rpm_smd_write(smd_vreg_rpm, QCOM_SMD_RPM_ACTIVE_STATE, vreg->type, vreg->id, req, sizeof(req[0]) * reqlen); if (!ret) { @@ -1384,14 +1383,13 @@ MODULE_DEVICE_TABLE(of, rpm_of_match); * @dev: Pointer to the top level qcom_smd-regulator PMIC device * @node: Pointer to the individual qcom_smd-regulator resource * device node - * @rpm: Pointer to the rpm bus node * @pmic_rpm_data: Pointer to a null-terminated array of qcom_smd-regulator * resources defined for the top level PMIC device * - * Return: 0 on success, errno on failure + * Return: 0 on success, or a negative error number on failure */ static int rpm_regulator_init_vreg(struct qcom_rpm_reg *vreg, struct device *dev, - struct device_node *node, struct qcom_smd_rpm *rpm, + struct device_node *node, const struct rpm_regulator_data *pmic_rpm_data) { struct regulator_config config = {}; @@ -1409,7 +1407,6 @@ static int rpm_regulator_init_vreg(struct qcom_rpm_reg *vreg, struct device *dev } vreg->dev = dev; - vreg->rpm = rpm; vreg->type = rpm_data->type; vreg->id = rpm_data->id; @@ -1438,7 +1435,6 @@ static int rpm_reg_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct rpm_regulator_data *vreg_data; - struct device_node *node; struct qcom_rpm_reg *vreg; struct qcom_smd_rpm *rpm; int ret; @@ -1449,23 +1445,23 @@ static int rpm_reg_probe(struct platform_device *pdev) return -ENODEV; } + if (smd_vreg_rpm && rpm != smd_vreg_rpm) + return dev_err_probe(dev, -EINVAL, "RPM mismatch\n"); + + smd_vreg_rpm = rpm; + vreg_data = of_device_get_match_data(dev); if (!vreg_data) return -ENODEV; - for_each_available_child_of_node(dev->of_node, node) { + for_each_available_child_of_node_scoped(dev->of_node, node) { vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); - if (!vreg) { - of_node_put(node); + if (!vreg) return -ENOMEM; - } - - ret = rpm_regulator_init_vreg(vreg, dev, node, rpm, vreg_data); - if (ret < 0) { - of_node_put(node); + ret = rpm_regulator_init_vreg(vreg, dev, node, vreg_data); + if (ret < 0) return ret; - } } return 0; diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 9a9fa20dcd95..d66a0f61637e 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -245,7 +245,7 @@ enum spmi_saw3_registers { SAW3_VERSION = 0xFD0, }; -/* Used for indexing into ctrl_reg. These are offets from 0x40 */ +/* Used for indexing into ctrl_reg. These are offsets from 0x40 */ enum spmi_common_control_register_index { SPMI_COMMON_IDX_VOLTAGE_RANGE = 0, SPMI_COMMON_IDX_VOLTAGE_SET = 1, @@ -2528,8 +2528,8 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) if (!reg) return -ENODEV; - if (of_find_property(node, "qcom,saw-reg", &lenp)) { - syscon = of_parse_phandle(node, "qcom,saw-reg", 0); + syscon = of_parse_phandle(node, "qcom,saw-reg", 0); + if (syscon) { saw_regmap = syscon_node_to_regmap(syscon); of_node_put(syscon); if (IS_ERR(saw_regmap)) @@ -2577,15 +2577,13 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) if (saw_regmap) { reg_node = of_get_child_by_name(node, reg->name); - reg_prop = of_find_property(reg_node, "qcom,saw-leader", - &lenp); - of_node_put(reg_node); - if (reg_prop) { + if (of_property_read_bool(reg_node, "qcom,saw-leader")) { spmi_saw_ops = *(vreg->desc.ops); spmi_saw_ops.set_voltage_sel = spmi_regulator_saw_set_voltage; vreg->desc.ops = &spmi_saw_ops; } + of_node_put(reg_node); } if (vreg->set_points && vreg->set_points->count == 1) { diff --git a/drivers/regulator/renesas-usb-vbus-regulator.c b/drivers/regulator/renesas-usb-vbus-regulator.c new file mode 100644 index 000000000000..dec7cac5e8d5 --- /dev/null +++ b/drivers/regulator/renesas-usb-vbus-regulator.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas USB VBUS output regulator driver +// +// Copyright (C) 2024 Renesas Electronics Corporation +// + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +static const struct regulator_ops rzg2l_usb_vbus_reg_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_desc rzg2l_usb_vbus_rdesc = { + .name = "vbus", + .of_match = of_match_ptr("regulator-vbus"), + .ops = &rzg2l_usb_vbus_reg_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = 0, + .enable_mask = BIT(0), + .enable_is_inverted = true, + .fixed_uV = 5000000, + .n_voltages = 1, +}; + +static int rzg2l_usb_vbus_regulator_probe(struct platform_device *pdev) +{ + struct regulator_config config = { }; + struct device *dev = &pdev->dev; + struct regulator_dev *rdev; + + config.regmap = dev_get_regmap(dev->parent, NULL); + if (!config.regmap) + return dev_err_probe(dev, -ENOENT, "Failed to get regmap\n"); + + config.dev = dev; + config.of_node = of_get_child_by_name(dev->parent->of_node, "regulator-vbus"); + if (!config.of_node) + return dev_err_probe(dev, -ENODEV, "regulator node not found\n"); + + rdev = devm_regulator_register(dev, &rzg2l_usb_vbus_rdesc, &config); + of_node_put(config.of_node); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), + "not able to register vbus regulator\n"); + + return 0; +} + +static struct platform_driver rzg2l_usb_vbus_regulator_driver = { + .probe = rzg2l_usb_vbus_regulator_probe, + .driver = { + .name = "rzg2l-usb-vbus-regulator", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; +module_platform_driver(rzg2l_usb_vbus_regulator_driver); + +MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); +MODULE_DESCRIPTION("Renesas RZ/G2L USB Vbus Regulator Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index d89ae7f16d7a..7d82bd1b36df 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Regulator driver for Rockchip RK805/RK808/RK818 + * Regulator driver for Rockchip RK80x and RK81x PMIC series * * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd * Copyright (c) 2021 Rockchip Electronics Co., Ltd. @@ -23,7 +23,7 @@ #include <linux/regulator/of_regulator.h> #include <linux/gpio/consumer.h> -/* Field Definitions */ +/* Field definitions */ #define RK808_BUCK_VSEL_MASK 0x3f #define RK808_BUCK4_VSEL_MASK 0xf #define RK808_LDO_VSEL_MASK 0x1f @@ -158,6 +158,11 @@ RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \ _vmask, _ereg, _emask, 0, 0, _etime, &rk808_reg_ops) +#define RK816_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _disval, _etime) \ + RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _emask, _disval, _etime, &rk816_reg_ops) + #define RK817_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \ _vmask, _ereg, _emask, _disval, _etime) \ RK8XX_DESC_COM(_id, _match, _supply, _min, _max, _step, _vreg, \ @@ -258,7 +263,7 @@ static const unsigned int rk808_buck1_2_ramp_table[] = { 2000, 4000, 6000, 10000 }; -/* RK817 RK809 */ +/* RK817/RK809/RK816 (buck 1/2 only) */ static const unsigned int rk817_buck1_4_ramp_table[] = { 3000, 6300, 12500, 25000 }; @@ -534,15 +539,25 @@ static int rk808_set_suspend_voltage_range(struct regulator_dev *rdev, int uv) { unsigned int reg; int sel = regulator_map_voltage_linear_range(rdev, uv, uv); + int ret; if (sel < 0) return -EINVAL; reg = rdev->desc->vsel_reg + RK808_SLP_REG_OFFSET; - return regmap_update_bits(rdev->regmap, reg, - rdev->desc->vsel_mask, - sel); + ret = regmap_update_bits(rdev->regmap, reg, + rdev->desc->vsel_mask, + sel); + if (ret) + return ret; + + if (rdev->desc->apply_bit) + ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg, + rdev->desc->apply_bit, + rdev->desc->apply_bit); + + return ret; } static int rk805_set_suspend_enable(struct regulator_dev *rdev) @@ -630,6 +645,38 @@ static int rk808_set_suspend_disable(struct regulator_dev *rdev) rdev->desc->enable_mask); } +static const struct rk8xx_register_bit rk816_suspend_bits[] = { + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 0), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 1), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 2), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 3), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 0), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 1), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 2), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 3), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 4), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG2, 5), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 5), + RK8XX_REG_BIT(RK818_SLEEP_SET_OFF_REG1, 6), +}; + +static int rk816_set_suspend_enable(struct regulator_dev *rdev) +{ + int rid = rdev_get_id(rdev); + + return regmap_update_bits(rdev->regmap, rk816_suspend_bits[rid].reg, + rk816_suspend_bits[rid].bit, + rk816_suspend_bits[rid].bit); +} + +static int rk816_set_suspend_disable(struct regulator_dev *rdev) +{ + int rid = rdev_get_id(rdev); + + return regmap_update_bits(rdev->regmap, rk816_suspend_bits[rid].reg, + rk816_suspend_bits[rid].bit, 0); +} + static int rk817_set_suspend_enable_ctrl(struct regulator_dev *rdev, unsigned int en) { @@ -903,6 +950,54 @@ static const struct regulator_ops rk809_buck5_ops_range = { .set_suspend_disable = rk817_set_suspend_disable, }; +static const struct regulator_ops rk816_buck1_2_ops_ranges = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = rk8xx_set_mode, + .get_mode = rk8xx_get_mode, + .set_suspend_mode = rk8xx_set_suspend_mode, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .set_suspend_voltage = rk808_set_suspend_voltage_range, + .set_suspend_enable = rk816_set_suspend_enable, + .set_suspend_disable = rk816_set_suspend_disable, +}; + +static const struct regulator_ops rk816_buck4_ops_ranges = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = rk8xx_set_mode, + .get_mode = rk8xx_get_mode, + .set_suspend_mode = rk8xx_set_suspend_mode, + .set_suspend_voltage = rk808_set_suspend_voltage_range, + .set_suspend_enable = rk816_set_suspend_enable, + .set_suspend_disable = rk816_set_suspend_disable, +}; + +static const struct regulator_ops rk816_reg_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = rk8xx_is_enabled_wmsk_regmap, + .set_suspend_voltage = rk808_set_suspend_voltage, + .set_suspend_enable = rk816_set_suspend_enable, + .set_suspend_disable = rk816_set_suspend_disable, +}; + static const struct regulator_ops rk817_reg_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -1284,6 +1379,8 @@ static const struct regulator_desc rk809_reg[] = { .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges), .vsel_reg = RK817_BUCK3_ON_VSEL_REG, .vsel_mask = RK817_BUCK_VSEL_MASK, + .apply_reg = RK817_POWER_CONFIG, + .apply_bit = RK817_BUCK3_FB_RES_INTER, .enable_reg = RK817_POWER_EN_REG(0), .enable_mask = ENABLE_MASK(RK817_ID_DCDC3), .enable_val = ENABLE_MASK(RK817_ID_DCDC3), @@ -1382,6 +1479,117 @@ static const struct regulator_desc rk809_reg[] = { DISABLE_VAL(3)), }; +static const struct linear_range rk816_buck_4_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(800000, 0, 26, 100000), + REGULATOR_LINEAR_RANGE(3500000, 27, 31, 0), +}; + +static const struct regulator_desc rk816_reg[] = { + { + .name = "dcdc1", + .supply_name = "vcc1", + .of_match = of_match_ptr("dcdc1"), + .regulators_node = of_match_ptr("regulators"), + .id = RK816_ID_DCDC1, + .ops = &rk816_buck1_2_ops_ranges, + .type = REGULATOR_VOLTAGE, + .n_voltages = 64, + .linear_ranges = rk805_buck_1_2_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), + .vsel_reg = RK818_BUCK1_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .apply_reg = RK816_DCDC_EN_REG2, + .apply_bit = RK816_BUCK_DVS_CONFIRM, + .enable_reg = RK816_DCDC_EN_REG1, + .enable_mask = BIT(4) | BIT(0), + .enable_val = BIT(4) | BIT(0), + .disable_val = BIT(4), + .ramp_reg = RK818_BUCK1_CONFIG_REG, + .ramp_mask = RK808_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), + .of_map_mode = rk8xx_regulator_of_map_mode, + .owner = THIS_MODULE, + }, { + .name = "dcdc2", + .supply_name = "vcc2", + .of_match = of_match_ptr("dcdc2"), + .regulators_node = of_match_ptr("regulators"), + .id = RK816_ID_DCDC2, + .ops = &rk816_buck1_2_ops_ranges, + .type = REGULATOR_VOLTAGE, + .n_voltages = 64, + .linear_ranges = rk805_buck_1_2_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), + .vsel_reg = RK818_BUCK2_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .apply_reg = RK816_DCDC_EN_REG2, + .apply_bit = RK816_BUCK_DVS_CONFIRM, + .enable_reg = RK816_DCDC_EN_REG1, + .enable_mask = BIT(5) | BIT(1), + .enable_val = BIT(5) | BIT(1), + .disable_val = BIT(5), + .ramp_reg = RK818_BUCK2_CONFIG_REG, + .ramp_mask = RK808_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), + .of_map_mode = rk8xx_regulator_of_map_mode, + .owner = THIS_MODULE, + }, { + .name = "dcdc3", + .supply_name = "vcc3", + .of_match = of_match_ptr("dcdc3"), + .regulators_node = of_match_ptr("regulators"), + .id = RK816_ID_DCDC3, + .ops = &rk808_switch_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .enable_reg = RK816_DCDC_EN_REG1, + .enable_mask = BIT(6) | BIT(2), + .enable_val = BIT(6) | BIT(2), + .disable_val = BIT(6), + .of_map_mode = rk8xx_regulator_of_map_mode, + .owner = THIS_MODULE, + }, { + .name = "dcdc4", + .supply_name = "vcc4", + .of_match = of_match_ptr("dcdc4"), + .regulators_node = of_match_ptr("regulators"), + .id = RK816_ID_DCDC4, + .ops = &rk816_buck4_ops_ranges, + .type = REGULATOR_VOLTAGE, + .n_voltages = 32, + .linear_ranges = rk816_buck_4_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk816_buck_4_voltage_ranges), + .vsel_reg = RK818_BUCK4_ON_VSEL_REG, + .vsel_mask = RK818_BUCK4_VSEL_MASK, + .enable_reg = RK816_DCDC_EN_REG1, + .enable_mask = BIT(7) | BIT(3), + .enable_val = BIT(7) | BIT(3), + .disable_val = BIT(7), + .of_map_mode = rk8xx_regulator_of_map_mode, + .owner = THIS_MODULE, + }, + RK816_DESC(RK816_ID_LDO1, "ldo1", "vcc5", 800, 3400, 100, + RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG1, ENABLE_MASK(0), DISABLE_VAL(0), 400), + RK816_DESC(RK816_ID_LDO2, "ldo2", "vcc5", 800, 3400, 100, + RK818_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG1, ENABLE_MASK(1), DISABLE_VAL(1), 400), + RK816_DESC(RK816_ID_LDO3, "ldo3", "vcc5", 800, 3400, 100, + RK818_LDO3_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG1, ENABLE_MASK(2), DISABLE_VAL(2), 400), + RK816_DESC(RK816_ID_LDO4, "ldo4", "vcc6", 800, 3400, 100, + RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG1, ENABLE_MASK(3), DISABLE_VAL(3), 400), + RK816_DESC(RK816_ID_LDO5, "ldo5", "vcc6", 800, 3400, 100, + RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG2, ENABLE_MASK(0), DISABLE_VAL(0), 400), + RK816_DESC(RK816_ID_LDO6, "ldo6", "vcc6", 800, 3400, 100, + RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK816_LDO_EN_REG2, ENABLE_MASK(1), DISABLE_VAL(1), 400), +}; + static const struct regulator_desc rk817_reg[] = { { .name = "DCDC_REG1", @@ -1623,9 +1831,8 @@ static const struct regulator_desc rk818_reg[] = { RK818_DCDC_EN_REG, BIT(7)), }; -static int rk808_regulator_dt_parse_pdata(struct device *dev, - struct regmap *map, - struct rk808_regulator_data *pdata) +static int rk808_regulator_dt_parse_pdata(struct device *dev, struct regmap *map, + struct rk808_regulator_data *pdata) { struct device_node *np; int tmp, ret = 0, i; @@ -1636,23 +1843,21 @@ static int rk808_regulator_dt_parse_pdata(struct device *dev, for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) { pdata->dvs_gpio[i] = - devm_gpiod_get_index_optional(dev, "dvs", i, - GPIOD_OUT_LOW); + devm_gpiod_get_index_optional(dev, "dvs", i, GPIOD_OUT_LOW); if (IS_ERR(pdata->dvs_gpio[i])) { - ret = PTR_ERR(pdata->dvs_gpio[i]); - dev_err(dev, "failed to get dvs%d gpio (%d)\n", i, ret); + ret = dev_err_probe(dev, PTR_ERR(pdata->dvs_gpio[i]), + "failed to get dvs%d gpio\n", i); goto dt_parse_end; } if (!pdata->dvs_gpio[i]) { - dev_info(dev, "there is no dvs%d gpio\n", i); + dev_dbg(dev, "there is no dvs%d gpio\n", i); continue; } tmp = i ? RK808_DVS2_POL : RK808_DVS1_POL; ret = regmap_update_bits(map, RK808_IO_POL_REG, tmp, - gpiod_is_active_low(pdata->dvs_gpio[i]) ? - 0 : tmp); + gpiod_is_active_low(pdata->dvs_gpio[i]) ? 0 : tmp); } dt_parse_end: @@ -1681,12 +1886,6 @@ static int rk808_regulator_probe(struct platform_device *pdev) if (!pdata) return -ENOMEM; - ret = rk808_regulator_dt_parse_pdata(&pdev->dev, regmap, pdata); - if (ret < 0) - return ret; - - platform_set_drvdata(pdev, pdata); - switch (rk808->variant) { case RK805_ID: regulators = rk805_reg; @@ -1697,6 +1896,11 @@ static int rk808_regulator_probe(struct platform_device *pdev) nregulators = ARRAY_SIZE(rk806_reg); break; case RK808_ID: + /* DVS0/1 GPIOs are supported on the RK808 only */ + ret = rk808_regulator_dt_parse_pdata(&pdev->dev, regmap, pdata); + if (ret < 0) + return ret; + regulators = rk808_reg; nregulators = RK808_NUM_REGULATORS; break; @@ -1704,6 +1908,10 @@ static int rk808_regulator_probe(struct platform_device *pdev) regulators = rk809_reg; nregulators = RK809_NUM_REGULATORS; break; + case RK816_ID: + regulators = rk816_reg; + nregulators = ARRAY_SIZE(rk816_reg); + break; case RK817_ID: regulators = rk817_reg; nregulators = RK817_NUM_REGULATORS; @@ -1713,11 +1921,12 @@ static int rk808_regulator_probe(struct platform_device *pdev) nregulators = RK818_NUM_REGULATORS; break; default: - dev_err(&pdev->dev, "unsupported RK8XX ID %lu\n", - rk808->variant); - return -EINVAL; + return dev_err_probe(&pdev->dev, -EINVAL, + "unsupported RK8xx ID %lu\n", rk808->variant); } + platform_set_drvdata(pdev, pdata); + config.dev = &pdev->dev; config.driver_data = pdata; config.regmap = regmap; @@ -1744,7 +1953,7 @@ static struct platform_driver rk808_regulator_driver = { module_platform_driver(rk808_regulator_driver); -MODULE_DESCRIPTION("regulator driver for the RK805/RK808/RK818 series PMICs"); +MODULE_DESCRIPTION("Rockchip RK80x/RK81x PMIC series regulator driver"); MODULE_AUTHOR("Tony xie <tony.xie@rock-chips.com>"); MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>"); diff --git a/drivers/regulator/rohm-regulator.c b/drivers/regulator/rohm-regulator.c index 0e2418ed957c..4b95ca01959c 100644 --- a/drivers/regulator/rohm-regulator.c +++ b/drivers/regulator/rohm-regulator.c @@ -46,6 +46,7 @@ static int set_dvs_level(const struct regulator_desc *desc, continue; if (ret == uv) { i <<= ffs(desc->vsel_mask) - 1; + ret = regmap_update_bits(regmap, reg, mask, i); if (omask && !ret) ret = regmap_update_bits(regmap, oreg, omask, @@ -53,6 +54,9 @@ static int set_dvs_level(const struct regulator_desc *desc, break; } } + if (i == desc->n_voltages) + pr_warn("Unsupported %s voltage %u\n", prop, uv); + return ret; } diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index f52c3d47ecea..6c3b6bfac961 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -75,7 +75,7 @@ static const struct regmap_config attiny_regmap_config = { .val_bits = 8, .disable_locking = 1, .max_register = REG_WRITE_DATA_L, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int attiny_set_port_state(struct attiny_lcd *state, int reg, u8 val) diff --git a/drivers/regulator/rt4831-regulator.c b/drivers/regulator/rt4831-regulator.c index 97e6f7e2a0ba..dfc868a24056 100644 --- a/drivers/regulator/rt4831-regulator.c +++ b/drivers/regulator/rt4831-regulator.c @@ -202,4 +202,5 @@ static struct platform_driver rt4831_regulator_driver = { module_platform_driver(rt4831_regulator_driver); MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Richtek RT4831 DSV Regulators driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/rt5120-regulator.c b/drivers/regulator/rt5120-regulator.c index a388ac70865f..f0d3efd160d4 100644 --- a/drivers/regulator/rt5120-regulator.c +++ b/drivers/regulator/rt5120-regulator.c @@ -245,8 +245,8 @@ static void rt5120_fillin_regulator_desc(struct regulator_desc *desc, int rid) desc->n_voltages = RT5120_BUCK1_NUM_VOLT; desc->min_uV = RT5120_BUCK1_MINUV; desc->uV_step = RT5120_BUCK1_STEPUV; - desc->vsel_reg = RT5120_REG_CH1VID, - desc->vsel_mask = RT5120_CH1VID_MASK, + desc->vsel_reg = RT5120_REG_CH1VID; + desc->vsel_mask = RT5120_CH1VID_MASK; desc->ops = &rt5120_buck1_ops; break; case RT5120_REGULATOR_BUCK2 ... RT5120_REGULATOR_BUCK4: diff --git a/drivers/regulator/rtmv20-regulator.c b/drivers/regulator/rtmv20-regulator.c index dfd1522637e4..3d8d29f87b58 100644 --- a/drivers/regulator/rtmv20-regulator.c +++ b/drivers/regulator/rtmv20-regulator.c @@ -312,7 +312,7 @@ static bool rtmv20_is_volatile_reg(struct device *dev, unsigned int reg) static const struct regmap_config rtmv20_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = RTMV20_REG_LDMASK, .num_reg_defaults_raw = RTMV20_MAX_REGS, diff --git a/drivers/regulator/rtq2208-regulator.c b/drivers/regulator/rtq2208-regulator.c index 2d54844c4226..9cde7181b0f0 100644 --- a/drivers/regulator/rtq2208-regulator.c +++ b/drivers/regulator/rtq2208-regulator.c @@ -26,6 +26,12 @@ #define RTQ2208_REG_BUCK_H_CFG0 0xA2 #define RTQ2208_REG_LDO1_CFG 0xB1 #define RTQ2208_REG_LDO2_CFG 0xC1 +#define RTQ2208_REG_LDO_DVS_CTRL 0xD0 +#define RTQ2208_REG_HIDDEN_BUCKPH 0x55 +#define RTQ2208_REG_HIDDEN_LDOCFG0 0x8F +#define RTQ2208_REG_HIDDEN_LDOCFG1 0x96 +#define RTQ2208_REG_HIDDEN0 0xFE +#define RTQ2208_REG_HIDDEN1 0xFF /* Mask */ #define RTQ2208_BUCK_NR_MTP_SEL_MASK GENMASK(7, 0) @@ -40,6 +46,15 @@ #define RTQ2208_EN_DIS_MASK BIT(0) #define RTQ2208_BUCK_RAMP_SEL_MASK GENMASK(2, 0) #define RTQ2208_HD_INT_MASK BIT(0) +#define RTQ2208_LDO1_DISCHG_EN_MASK BIT(4) +#define RTQ2208_LDO1_VOSEL_SD_MASK BIT(5) +#define RTQ2208_LDO2_DISCHG_EN_MASK BIT(6) +#define RTQ2208_LDO2_VOSEL_SD_MASK BIT(7) +#define RTQ2208_MASK_BUCKPH_GROUP1 GENMASK(6, 4) +#define RTQ2208_MASK_BUCKPH_GROUP2 GENMASK(2, 0) +#define RTQ2208_MASK_LDO2_OPT0 BIT(7) +#define RTQ2208_MASK_LDO2_OPT1 BIT(6) +#define RTQ2208_MASK_LDO1_FIXED BIT(6) /* Size */ #define RTQ2208_VOUT_MAXNUM 256 @@ -48,7 +63,7 @@ /* Value */ #define RTQ2208_RAMP_VALUE_MIN_uV 500 -#define RTQ2208_RAMP_VALUE_MAX_uV 64000 +#define RTQ2208_RAMP_VALUE_MAX_uV 16000 #define RTQ2208_BUCK_MASK(uv_irq, ov_irq) (1 << ((uv_irq) % 8) | 1 << ((ov_irq) % 8)) @@ -142,12 +157,11 @@ static int rtq2208_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) * Because the relation of seleltion and value is like that * * seletion: value - * 000: 64mv - * 001: 32mv + * 010: 16mv * ... * 111: 0.5mv * - * For example, if I would like to select 64mv, the fls(ramp_delay) - 1 will be 0b111, + * For example, if I would like to select 16mv, the fls(ramp_delay) - 1 will be 0b010, * and I need to use 0b111 - sel to do the shifting */ @@ -215,7 +229,7 @@ static const struct regulator_ops rtq2208_regulator_buck_ops = { .set_suspend_mode = rtq2208_set_suspend_mode, }; -static const struct regulator_ops rtq2208_regulator_ldo_ops = { +static const struct regulator_ops rtq2208_regulator_ldo_fix_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -224,6 +238,23 @@ static const struct regulator_ops rtq2208_regulator_ldo_ops = { .set_suspend_disable = rtq2208_set_suspend_disable, }; +static const struct regulator_ops rtq2208_regulator_ldo_adj_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_suspend_enable = rtq2208_set_suspend_enable, + .set_suspend_disable = rtq2208_set_suspend_disable, +}; + +static const unsigned int rtq2208_ldo_volt_table[] = { + 1800000, + 3300000, +}; + static unsigned int rtq2208_of_map_mode(unsigned int mode) { switch (mode) { @@ -318,15 +349,25 @@ static irqreturn_t rtq2208_irq_handler(int irqno, void *devid) return IRQ_HANDLED; } -#define RTQ2208_REGULATOR_INFO(_name, _base) \ -{ \ - .name = #_name, \ - .base = _base, \ +#define BUCK_INFO(_name, _id) \ +{ \ + .name = _name, \ + .base = RTQ2208_REG_BUCK_##_id##_CFG0, \ + .enable_reg = BUCK_RG_SHIFT(RTQ2208_REG_BUCK_##_id##_CFG0, 2), \ + .dis_reg = RTQ2208_REG_BUCK_##_id##_CFG0, \ } -#define BUCK_RG_BASE(_id) RTQ2208_REG_BUCK_##_id##_CFG0 + +#define LDO_INFO(_name, _id) \ +{ \ + .name = _name, \ + .base = RTQ2208_REG_LDO##_id##_CFG, \ + .enable_reg = RTQ2208_REG_LDO##_id##_CFG, \ + .dis_mask = RTQ2208_LDO##_id##_DISCHG_EN_MASK, \ + .dis_on = RTQ2208_LDO##_id##_DISCHG_EN_MASK, \ + .vsel_mask = RTQ2208_LDO##_id##_VOSEL_SD_MASK, \ +} + #define BUCK_RG_SHIFT(_base, _shift) (_base + _shift) -#define LDO_RG_BASE(_id) RTQ2208_REG_LDO##_id##_CFG -#define LDO_RG_SHIFT(_base, _shift) (_base + _shift) #define VSEL_SHIFT(_sel) (_sel ? 3 : 1) #define MTP_SEL_MASK(_sel) RTQ2208_BUCK_EN_NR_MTP_SEL##_sel##_MASK @@ -335,62 +376,30 @@ static const struct linear_range rtq2208_vout_range[] = { REGULATOR_LINEAR_RANGE(1310000, 181, 255, 10000), }; -static int rtq2208_of_get_fixed_voltage(struct device *dev, - struct of_regulator_match *rtq2208_ldo_match, int n_fixed) -{ - struct device_node *np; - struct of_regulator_match *match; - struct rtq2208_regulator_desc *rdesc; - struct regulator_init_data *init_data; - int ret, i; - - if (!dev->of_node) - return -ENODEV; - - np = of_get_child_by_name(dev->of_node, "regulators"); - if (!np) - np = dev->of_node; - - ret = of_regulator_match(dev, np, rtq2208_ldo_match, n_fixed); - - of_node_put(np); - - if (ret < 0) - return ret; - - for (i = 0; i < n_fixed; i++) { - match = rtq2208_ldo_match + i; - init_data = match->init_data; - rdesc = (struct rtq2208_regulator_desc *)match->driver_data; - - if (!init_data || !rdesc) - continue; - - if (init_data->constraints.min_uV == init_data->constraints.max_uV) - rdesc->desc.fixed_uV = init_data->constraints.min_uV; - } - - return 0; -} - -static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, int mtp_sel, - int idx, struct of_regulator_match *rtq2208_ldo_match, int *ldo_idx) +static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, int mtp_sel, int idx, + unsigned int ldo1_fixed, unsigned int ldo2_fixed) { struct regulator_desc *desc; + unsigned int fixed_uV; static const struct { char *name; int base; + int enable_reg; + int dis_reg; + int dis_mask; + int dis_on; + int vsel_mask; } regulator_info[] = { - RTQ2208_REGULATOR_INFO(buck-b, BUCK_RG_BASE(B)), - RTQ2208_REGULATOR_INFO(buck-c, BUCK_RG_BASE(C)), - RTQ2208_REGULATOR_INFO(buck-d, BUCK_RG_BASE(D)), - RTQ2208_REGULATOR_INFO(buck-a, BUCK_RG_BASE(A)), - RTQ2208_REGULATOR_INFO(buck-f, BUCK_RG_BASE(F)), - RTQ2208_REGULATOR_INFO(buck-g, BUCK_RG_BASE(G)), - RTQ2208_REGULATOR_INFO(buck-h, BUCK_RG_BASE(H)), - RTQ2208_REGULATOR_INFO(buck-e, BUCK_RG_BASE(E)), - RTQ2208_REGULATOR_INFO(ldo2, LDO_RG_BASE(2)), - RTQ2208_REGULATOR_INFO(ldo1, LDO_RG_BASE(1)), + BUCK_INFO("buck-b", B), + BUCK_INFO("buck-c", C), + BUCK_INFO("buck-d", D), + BUCK_INFO("buck-a", A), + BUCK_INFO("buck-f", F), + BUCK_INFO("buck-g", G), + BUCK_INFO("buck-h", H), + BUCK_INFO("buck-e", E), + LDO_INFO("ldo2", 2), + LDO_INFO("ldo1", 1), }, *curr_info; curr_info = regulator_info + idx; @@ -402,15 +411,14 @@ static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, in desc->owner = THIS_MODULE; desc->type = REGULATOR_VOLTAGE; desc->enable_mask = mtp_sel ? MTP_SEL_MASK(1) : MTP_SEL_MASK(0); - desc->active_discharge_on = RTQ2208_EN_DIS_MASK; + desc->enable_reg = curr_info->enable_reg; desc->active_discharge_off = 0; - desc->active_discharge_mask = RTQ2208_EN_DIS_MASK; rdesc->mode_mask = RTQ2208_BUCK_NRMODE_MASK; - if (idx >= RTQ2208_BUCK_B && idx <= RTQ2208_BUCK_E) { + switch (idx) { + case RTQ2208_BUCK_B ... RTQ2208_BUCK_E: /* init buck desc */ - desc->enable_reg = BUCK_RG_SHIFT(curr_info->base, 2); desc->ops = &rtq2208_regulator_buck_ops; desc->vsel_reg = curr_info->base + VSEL_SHIFT(mtp_sel); desc->vsel_mask = RTQ2208_BUCK_NR_MTP_SEL_MASK; @@ -418,34 +426,46 @@ static void rtq2208_init_regulator_desc(struct rtq2208_regulator_desc *rdesc, in desc->linear_ranges = rtq2208_vout_range; desc->n_linear_ranges = ARRAY_SIZE(rtq2208_vout_range); desc->ramp_reg = BUCK_RG_SHIFT(curr_info->base, 5); - desc->active_discharge_reg = curr_info->base; desc->of_map_mode = rtq2208_of_map_mode; + desc->active_discharge_reg = curr_info->dis_reg; + desc->active_discharge_on = RTQ2208_EN_DIS_MASK; + desc->active_discharge_mask = RTQ2208_EN_DIS_MASK; rdesc->mode_reg = BUCK_RG_SHIFT(curr_info->base, 2); rdesc->suspend_config_reg = BUCK_RG_SHIFT(curr_info->base, 4); rdesc->suspend_enable_mask = RTQ2208_BUCK_EN_STR_MASK; rdesc->suspend_mode_mask = RTQ2208_BUCK_STRMODE_MASK; - } else { - /* init ldo desc */ - desc->enable_reg = curr_info->base; - desc->ops = &rtq2208_regulator_ldo_ops; - desc->n_voltages = 1; - desc->active_discharge_reg = LDO_RG_SHIFT(curr_info->base, 2); + break; + default: + fixed_uV = idx == RTQ2208_LDO2 ? ldo2_fixed : ldo1_fixed; + if (fixed_uV) { + desc->n_voltages = 1; + desc->fixed_uV = fixed_uV; + desc->ops = &rtq2208_regulator_ldo_fix_ops; + } else { + desc->n_voltages = ARRAY_SIZE(rtq2208_ldo_volt_table); + desc->volt_table = rtq2208_ldo_volt_table; + desc->ops = &rtq2208_regulator_ldo_adj_ops; + } - rtq2208_ldo_match[*ldo_idx].name = desc->name; - rtq2208_ldo_match[*ldo_idx].driver_data = rdesc; - rtq2208_ldo_match[(*ldo_idx)++].desc = desc; + /* init ldo desc */ + desc->active_discharge_reg = RTQ2208_REG_LDO_DVS_CTRL; + desc->active_discharge_on = curr_info->dis_on; + desc->active_discharge_mask = curr_info->dis_mask; + desc->vsel_reg = RTQ2208_REG_LDO_DVS_CTRL; + desc->vsel_mask = curr_info->vsel_mask; rdesc->suspend_config_reg = curr_info->base; rdesc->suspend_enable_mask = RTQ2208_LDO_EN_STR_MASK; + break; } } static int rtq2208_parse_regulator_dt_data(int n_regulator, const unsigned int *regulator_idx_table, - struct rtq2208_regulator_desc *rdesc[RTQ2208_LDO_MAX], struct device *dev) + struct rtq2208_regulator_desc *rdesc[RTQ2208_LDO_MAX], struct device *dev, + unsigned int ldo1_fixed, unsigned int ldo2_fixed) { - struct of_regulator_match rtq2208_ldo_match[2]; - int mtp_sel, ret, i, idx, ldo_idx = 0; + int mtp_sel, i, idx; /* get mtp_sel0 or mtp_sel1 */ mtp_sel = device_property_read_bool(dev, "richtek,mtp-sel-high"); @@ -457,39 +477,101 @@ static int rtq2208_parse_regulator_dt_data(int n_regulator, const unsigned int * if (!rdesc[i]) return -ENOMEM; - rtq2208_init_regulator_desc(rdesc[i], mtp_sel, idx, rtq2208_ldo_match, &ldo_idx); + rtq2208_init_regulator_desc(rdesc[i], mtp_sel, idx, ldo1_fixed, ldo2_fixed); } - /* init ldo fixed_uV */ - ret = rtq2208_of_get_fixed_voltage(dev, rtq2208_ldo_match, ldo_idx); - if (ret) - return dev_err_probe(dev, ret, "Failed to get ldo fixed_uV\n"); - return 0; } -/** different slave address corresponds different used bucks - * slave address 0x10: BUCK[BCA FGE] - * slave address 0x20: BUCK[BC FGHE] - * slave address 0x40: BUCK[C G] - */ -static int rtq2208_regulator_check(int slave_addr, int *num, - int *regulator_idx_table, unsigned int *buck_masks) +static int rtq2208_regulator_check(struct device *dev, int *num, int *regulator_idx_table, + unsigned int *buck_masks, unsigned int *ldo1_fixed_uV, + unsigned int *ldo2_fixed_uV) { - static bool rtq2208_used_table[3][RTQ2208_LDO_MAX] = { - /* BUCK[BCA FGE], LDO[12] */ - {1, 1, 0, 1, 1, 1, 0, 1, 1, 1}, - /* BUCK[BC FGHE], LDO[12]*/ - {1, 1, 0, 0, 1, 1, 1, 1, 1, 1}, - /* BUCK[C G], LDO[12] */ - {0, 1, 0, 0, 0, 1, 0, 0, 1, 1}, - }; - int i, idx = ffs(slave_addr >> 4) - 1; + struct regmap *regmap = dev_get_regmap(dev, NULL); + bool rtq2208_used_table[RTQ2208_LDO_MAX] = {0}; + u8 entry_key[] = { 0x69, 0x01 }; + unsigned int buck_phase, ldo_cfg0, ldo_cfg1; + int i, ret; u8 mask; + ret = regmap_raw_write(regmap, RTQ2208_REG_HIDDEN0, entry_key, ARRAY_SIZE(entry_key)); + if (ret) + return dev_err_probe(dev, ret, "Failed to enter hidden page\n"); + + ret = regmap_read(regmap, RTQ2208_REG_HIDDEN_BUCKPH, &buck_phase); + if (ret) + return dev_err_probe(dev, ret, "Failed to read buck phase configuration\n"); + + ret = regmap_read(regmap, RTQ2208_REG_HIDDEN_LDOCFG0, &ldo_cfg0); + if (ret) + return dev_err_probe(dev, ret, "Failed to read ldo cfg0\n"); + + ret = regmap_read(regmap, RTQ2208_REG_HIDDEN_LDOCFG1, &ldo_cfg1); + if (ret) + return dev_err_probe(dev, ret, "Failed to read ldo cfg1\n"); + + ret = regmap_write(regmap, RTQ2208_REG_HIDDEN1, 0x00); + if (ret) + return dev_err_probe(dev, ret, "Failed to exit hidden page\n"); + + dev_info(dev, "BUCK Phase 0x%x\n", buck_phase); + /* + * Use buck phase configuration to assign used table mask + * GROUP1 GROUP2 + * 0 -> 2P + 2P BC FG + * 1 -> 2P + 1P + 1P BCA FGE + * 2 -> 1P + 1P + 1P + 1P BCDA FGHE + * 3 -> 3P + 1P BC FG + * others -> 4P C G + */ + switch (FIELD_GET(RTQ2208_MASK_BUCKPH_GROUP1, buck_phase)) { + case 2: + rtq2208_used_table[RTQ2208_BUCK_D] = true; + fallthrough; + case 1: + rtq2208_used_table[RTQ2208_BUCK_A] = true; + fallthrough; + case 0: + case 3: + rtq2208_used_table[RTQ2208_BUCK_B] = true; + fallthrough; + default: + rtq2208_used_table[RTQ2208_BUCK_C] = true; + break; + } + + switch (FIELD_GET(RTQ2208_MASK_BUCKPH_GROUP2, buck_phase)) { + case 2: + rtq2208_used_table[RTQ2208_BUCK_F] = true; + fallthrough; + case 1: + rtq2208_used_table[RTQ2208_BUCK_E] = true; + fallthrough; + case 0: + case 3: + rtq2208_used_table[RTQ2208_BUCK_H] = true; + fallthrough; + default: + rtq2208_used_table[RTQ2208_BUCK_G] = true; + break; + } + + *ldo1_fixed_uV = FIELD_GET(RTQ2208_MASK_LDO1_FIXED, ldo_cfg1) ? 1200000 : 0; + + if (!FIELD_GET(RTQ2208_MASK_LDO2_OPT0, ldo_cfg0) && + !FIELD_GET(RTQ2208_MASK_LDO2_OPT1, ldo_cfg1)) + *ldo2_fixed_uV = 0; + else if (FIELD_GET(RTQ2208_MASK_LDO2_OPT1, ldo_cfg1)) + *ldo2_fixed_uV = 900000; + else + *ldo2_fixed_uV = 1200000; + + /* By default, LDO1 & LDO2 are always used */ + rtq2208_used_table[RTQ2208_LDO1] = rtq2208_used_table[RTQ2208_LDO2] = true; + for (i = 0; i < RTQ2208_LDO_MAX; i++) { - if (!rtq2208_used_table[idx][i]) + if (!rtq2208_used_table[i]) continue; regulator_idx_table[(*num)++] = i; @@ -504,7 +586,7 @@ static int rtq2208_regulator_check(int slave_addr, int *num, static const struct regmap_config rtq2208_regmap_config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0xEF, + .max_register = 0xFF, }; static int rtq2208_probe(struct i2c_client *i2c) @@ -513,11 +595,12 @@ static int rtq2208_probe(struct i2c_client *i2c) struct regmap *regmap; struct rtq2208_regulator_desc *rdesc[RTQ2208_LDO_MAX]; struct regulator_dev *rdev; - struct regulator_config cfg; + struct regulator_config cfg = {}; struct rtq2208_rdev_map *rdev_map; int i, ret = 0, idx, n_regulator = 0; unsigned int regulator_idx_table[RTQ2208_LDO_MAX], buck_masks[RTQ2208_BUCK_NUM_IRQ_REGS] = {0x33, 0x33, 0x33, 0x33, 0x33}; + unsigned int ldo1_fixed_uV, ldo2_fixed_uV; rdev_map = devm_kzalloc(dev, sizeof(struct rtq2208_rdev_map), GFP_KERNEL); if (!rdev_map) @@ -528,7 +611,8 @@ static int rtq2208_probe(struct i2c_client *i2c) return dev_err_probe(dev, PTR_ERR(regmap), "Failed to allocate regmap\n"); /* get needed regulator */ - ret = rtq2208_regulator_check(i2c->addr, &n_regulator, regulator_idx_table, buck_masks); + ret = rtq2208_regulator_check(dev, &n_regulator, regulator_idx_table, buck_masks, + &ldo1_fixed_uV, &ldo2_fixed_uV); if (ret) return dev_err_probe(dev, ret, "Failed to check used regulators\n"); @@ -538,7 +622,8 @@ static int rtq2208_probe(struct i2c_client *i2c) cfg.dev = dev; /* init regulator desc */ - ret = rtq2208_parse_regulator_dt_data(n_regulator, regulator_idx_table, rdesc, dev); + ret = rtq2208_parse_regulator_dt_data(n_regulator, regulator_idx_table, rdesc, dev, + ldo1_fixed_uV, ldo2_fixed_uV); if (ret) return ret; diff --git a/drivers/regulator/rtq6752-regulator.c b/drivers/regulator/rtq6752-regulator.c index 8176e5ab0683..d35d844eff3b 100644 --- a/drivers/regulator/rtq6752-regulator.c +++ b/drivers/regulator/rtq6752-regulator.c @@ -209,7 +209,7 @@ static const struct reg_default rtq6752_reg_defaults[] = { static const struct regmap_config rtq6752_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = RTQ6752_REG_FAULT, .reg_defaults = rtq6752_reg_defaults, .num_reg_defaults = ARRAY_SIZE(rtq6752_reg_defaults), diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 570b61420f3a..7dcf92af8f15 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -4,6 +4,7 @@ // http://www.samsung.com #include <linux/bug.h> +#include <linux/cleanup.h> #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/slab.h> @@ -1120,7 +1121,6 @@ static const struct regulator_desc s2mpu02_regulators[] = { static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct of_regulator_match *rdata = NULL; struct regulator_config config = { }; struct s2mps11_info *s2mps11; unsigned int rdev_num = 0; @@ -1170,7 +1170,8 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) if (!s2mps11->ext_control_gpiod) return -ENOMEM; - rdata = kcalloc(rdev_num, sizeof(*rdata), GFP_KERNEL); + struct of_regulator_match *rdata __free(kfree) = + kcalloc(rdev_num, sizeof(*rdata), GFP_KERNEL); if (!rdata) return -ENOMEM; @@ -1179,7 +1180,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, rdev_num); if (ret) - goto out; + return ret; platform_set_drvdata(pdev, s2mps11); @@ -1201,10 +1202,9 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) regulator = devm_regulator_register(&pdev->dev, ®ulators[i], &config); if (IS_ERR(regulator)) { - ret = PTR_ERR(regulator); dev_err(&pdev->dev, "regulator init failed for %d\n", i); - goto out; + return PTR_ERR(regulator); } if (config.ena_gpiod) { @@ -1214,15 +1214,12 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to enable GPIO control over %s: %d\n", regulator->desc->name, ret); - goto out; + return ret; } } } -out: - kfree(rdata); - - return ret; + return 0; } static const struct platform_device_id s2mps11_pmic_id[] = { diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index bfc0e143bf40..d25cd81e3f36 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -3,6 +3,7 @@ // Copyright (c) 2011 Samsung Electronics Co., Ltd // http://www.samsung.com +#include <linux/cleanup.h> #include <linux/err.h> #include <linux/of_gpio.h> #include <linux/gpio/consumer.h> @@ -521,7 +522,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, struct sec_platform_data *pdata) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct device_node *pmic_np, *regulators_np, *reg_np; + struct device_node *pmic_np, *reg_np; struct sec_regulator_data *rdata; struct sec_opmode_data *rmode; unsigned int i, dvs_voltage_nr = 8, ret; @@ -532,7 +533,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, return -ENODEV; } - regulators_np = of_get_child_by_name(pmic_np, "regulators"); + struct device_node *regulators_np __free(device_node) = of_get_child_by_name(pmic_np, + "regulators"); if (!regulators_np) { dev_err(iodev->dev, "could not find regulators sub-node\n"); return -EINVAL; @@ -544,18 +546,14 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, rdata = devm_kcalloc(&pdev->dev, pdata->num_regulators, sizeof(*rdata), GFP_KERNEL); - if (!rdata) { - of_node_put(regulators_np); + if (!rdata) return -ENOMEM; - } rmode = devm_kcalloc(&pdev->dev, pdata->num_regulators, sizeof(*rmode), GFP_KERNEL); - if (!rmode) { - of_node_put(regulators_np); + if (!rmode) return -ENOMEM; - } pdata->regulators = rdata; pdata->opmode = rmode; @@ -581,7 +579,6 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, rdata->ext_control_gpiod = NULL; } else if (IS_ERR(rdata->ext_control_gpiod)) { of_node_put(reg_np); - of_node_put(regulators_np); return PTR_ERR(rdata->ext_control_gpiod); } @@ -603,8 +600,6 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, rmode++; } - of_node_put(regulators_np); - if (of_property_read_bool(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs")) { pdata->buck2_gpiodvs = true; diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c index 29ab217297d6..9df726f10ad1 100644 --- a/drivers/regulator/scmi-regulator.c +++ b/drivers/regulator/scmi-regulator.c @@ -297,7 +297,7 @@ static int process_scmi_regulator_of_node(struct scmi_device *sdev, static int scmi_regulator_probe(struct scmi_device *sdev) { int d, ret, num_doms; - struct device_node *np, *child; + struct device_node *np; const struct scmi_handle *handle = sdev->handle; struct scmi_regulator_info *rinfo; struct scmi_protocol_handle *ph; @@ -341,13 +341,11 @@ static int scmi_regulator_probe(struct scmi_device *sdev) */ of_node_get(handle->dev->of_node); np = of_find_node_by_name(handle->dev->of_node, "regulators"); - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo); /* abort on any mem issue */ - if (ret == -ENOMEM) { - of_node_put(child); + if (ret == -ENOMEM) return ret; - } } of_node_put(np); /* diff --git a/drivers/regulator/slg51000-regulator.c b/drivers/regulator/slg51000-regulator.c index 59aa16825d8a..3bbd4a29e6d3 100644 --- a/drivers/regulator/slg51000-regulator.c +++ b/drivers/regulator/slg51000-regulator.c @@ -497,8 +497,8 @@ static int slg51000_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id slg51000_i2c_id[] = { - {"slg51000", 0}, - {}, + { "slg51000" }, + {} }; MODULE_DEVICE_TABLE(i2c, slg51000_i2c_id); diff --git a/drivers/regulator/sm5703-regulator.c b/drivers/regulator/sm5703-regulator.c deleted file mode 100644 index 702461cf075e..000000000000 --- a/drivers/regulator/sm5703-regulator.c +++ /dev/null @@ -1,170 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include <linux/mfd/sm5703.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/platform_device.h> -#include <linux/regmap.h> -#include <linux/regulator/driver.h> -#include <linux/regulator/of_regulator.h> - -enum sm5703_regulators { - SM5703_BUCK, - SM5703_LDO1, - SM5703_LDO2, - SM5703_LDO3, - SM5703_USBLDO1, - SM5703_USBLDO2, - SM5703_VBUS, - SM5703_MAX_REGULATORS, -}; - -static const int sm5703_ldo_voltagemap[] = { - 1500000, 1800000, 2600000, 2800000, 3000000, 3300000, -}; - -static const int sm5703_buck_voltagemap[] = { - 1000000, 1000000, 1000000, 1000000, - 1000000, 1000000, 1000000, 1000000, - 1000000, 1000000, 1000000, 1100000, - 1200000, 1300000, 1400000, 1500000, - 1600000, 1700000, 1800000, 1900000, - 2000000, 2100000, 2200000, 2300000, - 2400000, 2500000, 2600000, 2700000, - 2800000, 2900000, 3000000, 3000000, -}; - -#define SM5703USBLDO(_name, _id) \ - [SM5703_USBLDO ## _id] = { \ - .name = _name, \ - .of_match = _name, \ - .regulators_node = "regulators", \ - .type = REGULATOR_VOLTAGE, \ - .id = SM5703_USBLDO ## _id, \ - .ops = &sm5703_regulator_ops_fixed, \ - .n_voltages = 1, \ - .fixed_uV = SM5703_USBLDO_MICROVOLT, \ - .enable_reg = SM5703_REG_USBLDO12, \ - .enable_mask = SM5703_REG_EN_USBLDO ##_id, \ - .owner = THIS_MODULE, \ - } - -#define SM5703VBUS(_name) \ - [SM5703_VBUS] = { \ - .name = _name, \ - .of_match = _name, \ - .regulators_node = "regulators", \ - .type = REGULATOR_VOLTAGE, \ - .id = SM5703_VBUS, \ - .ops = &sm5703_regulator_ops_fixed, \ - .n_voltages = 1, \ - .fixed_uV = SM5703_VBUS_MICROVOLT, \ - .enable_reg = SM5703_REG_CNTL, \ - .enable_mask = SM5703_OPERATION_MODE_MASK, \ - .enable_val = SM5703_OPERATION_MODE_USB_OTG_MODE, \ - .disable_val = SM5703_OPERATION_MODE_CHARGING_ON, \ - .owner = THIS_MODULE, \ - } - -#define SM5703BUCK(_name) \ - [SM5703_BUCK] = { \ - .name = _name, \ - .of_match = _name, \ - .regulators_node = "regulators", \ - .type = REGULATOR_VOLTAGE, \ - .id = SM5703_BUCK, \ - .ops = &sm5703_regulator_ops, \ - .n_voltages = ARRAY_SIZE(sm5703_buck_voltagemap), \ - .volt_table = sm5703_buck_voltagemap, \ - .vsel_reg = SM5703_REG_BUCK, \ - .vsel_mask = SM5703_BUCK_VOLT_MASK, \ - .enable_reg = SM5703_REG_BUCK, \ - .enable_mask = SM5703_REG_EN_BUCK, \ - .owner = THIS_MODULE, \ - } - -#define SM5703LDO(_name, _id) \ - [SM5703_LDO ## _id] = { \ - .name = _name, \ - .of_match = _name, \ - .regulators_node = "regulators", \ - .type = REGULATOR_VOLTAGE, \ - .id = SM5703_LDO ## _id, \ - .ops = &sm5703_regulator_ops, \ - .n_voltages = ARRAY_SIZE(sm5703_ldo_voltagemap), \ - .volt_table = sm5703_ldo_voltagemap, \ - .vsel_reg = SM5703_REG_LDO ##_id, \ - .vsel_mask = SM5703_LDO_VOLT_MASK, \ - .enable_reg = SM5703_REG_LDO ##_id, \ - .enable_mask = SM5703_LDO_EN, \ - .owner = THIS_MODULE, \ - } - -static const struct regulator_ops sm5703_regulator_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .list_voltage = regulator_list_voltage_table, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, -}; - -static const struct regulator_ops sm5703_regulator_ops_fixed = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, -}; - -static struct regulator_desc sm5703_regulators_desc[SM5703_MAX_REGULATORS] = { - SM5703BUCK("buck"), - SM5703LDO("ldo1", 1), - SM5703LDO("ldo2", 2), - SM5703LDO("ldo3", 3), - SM5703USBLDO("usbldo1", 1), - SM5703USBLDO("usbldo2", 2), - SM5703VBUS("vbus"), -}; - -static int sm5703_regulator_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct regulator_config config = { NULL, }; - struct regulator_dev *rdev; - struct sm5703_dev *sm5703 = dev_get_drvdata(pdev->dev.parent); - int i; - - config.dev = dev->parent; - config.regmap = sm5703->regmap; - - for (i = 0; i < SM5703_MAX_REGULATORS; i++) { - rdev = devm_regulator_register(dev, - &sm5703_regulators_desc[i], - &config); - if (IS_ERR(rdev)) - return dev_err_probe(dev, PTR_ERR(rdev), - "Failed to register a regulator\n"); - } - - return 0; -} - -static const struct platform_device_id sm5703_regulator_id[] = { - { "sm5703-regulator", 0 }, - {} -}; -MODULE_DEVICE_TABLE(platform, sm5703_regulator_id); - -static struct platform_driver sm5703_regulator_driver = { - .driver = { - .name = "sm5703-regulator", - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - }, - .probe = sm5703_regulator_probe, - .id_table = sm5703_regulator_id, -}; - -module_platform_driver(sm5703_regulator_driver); - -MODULE_DESCRIPTION("Silicon Mitus SM5703 LDO/Buck/USB regulator driver"); -MODULE_AUTHOR("Markuss Broks <markuss.broks@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c index 85b0102fb9b1..b7aeef6e09e7 100644 --- a/drivers/regulator/stm32-pwr.c +++ b/drivers/regulator/stm32-pwr.c @@ -166,6 +166,7 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) static const struct of_device_id __maybe_unused stm32_pwr_of_match[] = { { .compatible = "st,stm32mp1,pwr-reg", }, + { .compatible = "st,stm32mp13-pwr-reg", }, {}, }; MODULE_DEVICE_TABLE(of, stm32_pwr_of_match); diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c index 40855105dd33..a85ea94f0673 100644 --- a/drivers/regulator/stm32-vrefbuf.c +++ b/drivers/regulator/stm32-vrefbuf.c @@ -280,7 +280,7 @@ MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match); static struct platform_driver stm32_vrefbuf_driver = { .probe = stm32_vrefbuf_probe, - .remove_new = stm32_vrefbuf_remove, + .remove = stm32_vrefbuf_remove, .driver = { .name = "stm32-vrefbuf", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/regulator/sun20i-regulator.c b/drivers/regulator/sun20i-regulator.c new file mode 100644 index 000000000000..e09be44859e7 --- /dev/null +++ b/drivers/regulator/sun20i-regulator.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright (c) 2021-2022 Samuel Holland <samuel@sholland.org> +// + +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +#define SUN20I_SYS_LDO_CTRL_REG 0x150 + +struct sun20i_regulator_data { + const struct regulator_desc *descs; + unsigned int ndescs; +}; + +/* regulator_list_voltage_linear() modified for the non-integral uV_step. */ +static int sun20i_d1_system_ldo_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + const struct regulator_desc *desc = rdev->desc; + unsigned int fraction, uV; + + if (selector >= desc->n_voltages) + return -EINVAL; + + uV = desc->min_uV + (desc->uV_step * selector); + fraction = selector + (desc->min_uV % 4); + + if (uV > 1606667) + uV += 6667; + else + fraction++; + + /* Produce correctly-rounded absolute voltages. */ + return uV + (fraction / 3); +} + +static const struct regulator_ops sun20i_d1_system_ldo_ops = { + .list_voltage = sun20i_d1_system_ldo_list_voltage, + .map_voltage = regulator_map_voltage_ascend, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static const struct regulator_desc sun20i_d1_system_ldo_descs[] = { + { + .name = "ldoa", + .supply_name = "ldo-in", + .of_match = "ldoa", + .ops = &sun20i_d1_system_ldo_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = 32, + .min_uV = 1593333, + .uV_step = 13333, /* repeating */ + .vsel_reg = SUN20I_SYS_LDO_CTRL_REG, + .vsel_mask = GENMASK(7, 0), + }, + { + .name = "ldob", + .supply_name = "ldo-in", + .of_match = "ldob", + .ops = &sun20i_d1_system_ldo_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = 64, + .min_uV = 1166666, + .uV_step = 13333, /* repeating */ + .vsel_reg = SUN20I_SYS_LDO_CTRL_REG, + .vsel_mask = GENMASK(15, 8), + }, +}; + +static const struct sun20i_regulator_data sun20i_d1_system_ldos = { + .descs = sun20i_d1_system_ldo_descs, + .ndescs = ARRAY_SIZE(sun20i_d1_system_ldo_descs), +}; + +static struct regmap *sun20i_regulator_get_regmap(struct device *dev) +{ + struct regmap *regmap; + + /* + * First try the syscon interface. The system control device is not + * compatible with "syscon", so fall back to getting the regmap from + * its platform device. This is ugly, but required for devicetree + * backward compatibility. + */ + regmap = syscon_node_to_regmap(dev->parent->of_node); + if (!IS_ERR(regmap)) + return regmap; + + regmap = dev_get_regmap(dev->parent, NULL); + if (regmap) + return regmap; + + return ERR_PTR(-EPROBE_DEFER); +} + +static int sun20i_regulator_probe(struct platform_device *pdev) +{ + const struct sun20i_regulator_data *data; + struct device *dev = &pdev->dev; + struct regulator_config config; + struct regmap *regmap; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + regmap = sun20i_regulator_get_regmap(dev); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Failed to get regmap\n"); + + config = (struct regulator_config) { + .dev = dev, + .regmap = regmap, + }; + + for (unsigned int i = 0; i < data->ndescs; ++i) { + const struct regulator_desc *desc = &data->descs[i]; + struct regulator_dev *rdev; + + rdev = devm_regulator_register(dev, desc, &config); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + } + + return 0; +} + +static const struct of_device_id sun20i_regulator_of_match[] = { + { + .compatible = "allwinner,sun20i-d1-system-ldos", + .data = &sun20i_d1_system_ldos, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, sun20i_regulator_of_match); + +static struct platform_driver sun20i_regulator_driver = { + .probe = sun20i_regulator_probe, + .driver = { + .name = "sun20i-regulator", + .of_match_table = sun20i_regulator_of_match, + }, +}; +module_platform_driver(sun20i_regulator_driver); + +MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); +MODULE_DESCRIPTION("Allwinner D1 internal LDO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c index 1bcfdd6dcfc1..d79a4cc25a0d 100644 --- a/drivers/regulator/sy8106a-regulator.c +++ b/drivers/regulator/sy8106a-regulator.c @@ -130,8 +130,8 @@ static const struct of_device_id sy8106a_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match); static const struct i2c_device_id sy8106a_i2c_id[] = { - { "sy8106a", 0 }, - { }, + { "sy8106a" }, + { } }; MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id); diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index 5199e0437388..3a384bf9d2c5 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -199,7 +199,7 @@ static const struct regmap_config tps51632_regmap_config = { .readable_reg = is_read_reg, .volatile_reg = is_volatile_reg, .max_register = TPS51632_MAX_REG - 1, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #if defined(CONFIG_OF) diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 32e1a05a57fd..be6a6702cbfa 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -275,7 +275,7 @@ static const struct regmap_config tps62360_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = REG_CHIPID, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static struct tps62360_regulator_platform_data * diff --git a/drivers/regulator/tps6286x-regulator.c b/drivers/regulator/tps6286x-regulator.c index 758c70269653..75f441f36de7 100644 --- a/drivers/regulator/tps6286x-regulator.c +++ b/drivers/regulator/tps6286x-regulator.c @@ -136,11 +136,11 @@ static int tps6286x_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id tps6286x_i2c_id[] = { - { "tps62864", 0 }, - { "tps62866", 0 }, - { "tps62868", 0 }, - { "tps62869", 0 }, - {}, + { "tps62864" }, + { "tps62866" }, + { "tps62868" }, + { "tps62869" }, + {} }; MODULE_DEVICE_TABLE(i2c, tps6286x_i2c_id); @@ -156,4 +156,5 @@ static struct i2c_driver tps6286x_regulator_driver = { module_i2c_driver(tps6286x_regulator_driver); +MODULE_DESCRIPTION("TI TPS6286x Power Regulator driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps6287x-regulator.c b/drivers/regulator/tps6287x-regulator.c index 9b7c3d77789e..c0f5f0a186a3 100644 --- a/drivers/regulator/tps6287x-regulator.c +++ b/drivers/regulator/tps6287x-regulator.c @@ -44,10 +44,35 @@ static const unsigned int tps6287x_voltage_range_sel[] = { 0x0, 0x1, 0x2, 0x3 }; +static const unsigned int tps6287x_voltage_range_prefix[] = { + 0x000, 0x100, 0x200, 0x300 +}; + static const unsigned int tps6287x_ramp_table[] = { 10000, 5000, 1250, 500 }; +struct tps6287x_reg_data { + int range; +}; + +static int tps6287x_best_range(struct regulator_config *config, const struct regulator_desc *desc) +{ + const struct linear_range *r; + int i; + + if (!config->init_data->constraints.apply_uV) + return -1; + + for (i = 0; i < desc->n_linear_ranges; i++) { + r = &desc->linear_ranges[i]; + if (r->min <= config->init_data->constraints.min_uV && + config->init_data->constraints.max_uV <= linear_range_get_max_value(r)) + return i; + } + return -1; +} + static int tps6287x_set_mode(struct regulator_dev *rdev, unsigned int mode) { unsigned int val; @@ -91,6 +116,28 @@ static unsigned int tps6287x_of_map_mode(unsigned int mode) } } +static int tps6287x_map_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) +{ + struct tps6287x_reg_data *data = (struct tps6287x_reg_data *)rdev->reg_data; + struct linear_range selected_range; + int selector, voltage; + + if (!data || data->range == -1) + return regulator_map_voltage_pickable_linear_range(rdev, min_uV, max_uV); + + selected_range = rdev->desc->linear_ranges[data->range]; + selector = DIV_ROUND_UP(min_uV - selected_range.min, selected_range.step); + if (selector < selected_range.min_sel || selector > selected_range.max_sel) + return -EINVAL; + + selector |= tps6287x_voltage_range_prefix[data->range]; + voltage = rdev->desc->ops->list_voltage(rdev, selector); + if (voltage < min_uV || voltage > max_uV) + return -EINVAL; + + return selector; +} + static const struct regulator_ops tps6287x_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -100,10 +147,11 @@ static const struct regulator_ops tps6287x_regulator_ops = { .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap, .list_voltage = regulator_list_voltage_pickable_linear_range, + .map_voltage = tps6287x_map_voltage, .set_ramp_delay = regulator_set_ramp_delay_regmap, }; -static struct regulator_desc tps6287x_reg = { +static const struct regulator_desc tps6287x_reg = { .name = "tps6287x", .owner = THIS_MODULE, .ops = &tps6287x_regulator_ops, @@ -115,6 +163,7 @@ static struct regulator_desc tps6287x_reg = { .vsel_mask = 0xFF, .vsel_range_reg = TPS6287X_CTRL2, .vsel_range_mask = TPS6287X_CTRL2_VRANGE, + .range_applied_by_vsel = true, .ramp_reg = TPS6287X_CTRL1, .ramp_mask = TPS6287X_CTRL1_VRAMP, .ramp_delay_table = tps6287x_ramp_table, @@ -129,8 +178,14 @@ static int tps6287x_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct regulator_config config = {}; + struct tps6287x_reg_data *reg_data; struct regulator_dev *rdev; + reg_data = devm_kzalloc(dev, sizeof(struct tps6287x_reg_data), GFP_KERNEL); + + if (!reg_data) + return -ENOMEM; + config.regmap = devm_regmap_init_i2c(i2c, &tps6287x_regmap_config); if (IS_ERR(config.regmap)) { dev_err(dev, "Failed to init i2c\n"); @@ -142,12 +197,15 @@ static int tps6287x_i2c_probe(struct i2c_client *i2c) config.init_data = of_get_regulator_init_data(dev, dev->of_node, &tps6287x_reg); + reg_data->range = tps6287x_best_range(&config, &tps6287x_reg); + rdev = devm_regulator_register(dev, &tps6287x_reg, &config); if (IS_ERR(rdev)) { dev_err(dev, "Failed to register regulator\n"); return PTR_ERR(rdev); } + rdev->reg_data = (void *)reg_data; dev_dbg(dev, "Probed regulator\n"); return 0; @@ -164,11 +222,11 @@ static const struct of_device_id tps6287x_dt_ids[] = { MODULE_DEVICE_TABLE(of, tps6287x_dt_ids); static const struct i2c_device_id tps6287x_i2c_id[] = { - { "tps62870", 0 }, - { "tps62871", 0 }, - { "tps62872", 0 }, - { "tps62873", 0 }, - {}, + { "tps62870" }, + { "tps62871" }, + { "tps62872" }, + { "tps62873" }, + {} }; MODULE_DEVICE_TABLE(i2c, tps6287x_i2c_id); diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index d5757fd9a65b..3334b5b7d907 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -242,17 +242,17 @@ static const struct regulator_desc tps65023_regulators[] = { TPS65023_REGULATOR_LDO(2, TPS65023_LDO2_VSEL_table, 0x70), }; -static struct tps_driver_data tps65020_drv_data = { +static const struct tps_driver_data tps65020_drv_data = { .desc = tps65020_regulators, .core_regulator = TPS65023_DCDC_3, }; -static struct tps_driver_data tps65021_drv_data = { +static const struct tps_driver_data tps65021_drv_data = { .desc = tps65021_regulators, .core_regulator = TPS65023_DCDC_3, }; -static struct tps_driver_data tps65023_drv_data = { +static const struct tps_driver_data tps65023_drv_data = { .desc = tps65023_regulators, .core_regulator = TPS65023_DCDC_1, }; diff --git a/drivers/regulator/tps65132-regulator.c b/drivers/regulator/tps65132-regulator.c index a06f5f2d7932..9c2f0dd42613 100644 --- a/drivers/regulator/tps65132-regulator.c +++ b/drivers/regulator/tps65132-regulator.c @@ -267,10 +267,17 @@ static const struct i2c_device_id tps65132_id[] = { }; MODULE_DEVICE_TABLE(i2c, tps65132_id); +static const struct of_device_id __maybe_unused tps65132_of_match[] = { + { .compatible = "ti,tps65132" }, + {}, +}; +MODULE_DEVICE_TABLE(of, tps65132_of_match); + static struct i2c_driver tps65132_i2c_driver = { .driver = { .name = "tps65132", .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = of_match_ptr(tps65132_of_match), }, .probe = tps65132_probe, .id_table = tps65132_id, diff --git a/drivers/regulator/tps65219-regulator.c b/drivers/regulator/tps65219-regulator.c index b4065356392f..aa65077f9d41 100644 --- a/drivers/regulator/tps65219-regulator.c +++ b/drivers/regulator/tps65219-regulator.c @@ -287,21 +287,6 @@ static irqreturn_t tps65219_regulator_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int tps65219_get_rdev_by_name(const char *regulator_name, - struct regulator_dev *rdevtbl[7], - struct regulator_dev **dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(regulators); i++) { - if (strcmp(regulator_name, regulators[i].name) == 0) { - *dev = rdevtbl[i]; - return 0; - } - } - return -EINVAL; -} - static int tps65219_regulator_probe(struct platform_device *pdev) { struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent); @@ -312,23 +297,18 @@ static int tps65219_regulator_probe(struct platform_device *pdev) int irq; struct tps65219_regulator_irq_data *irq_data; struct tps65219_regulator_irq_type *irq_type; - struct regulator_dev *rdevtbl[7]; config.dev = tps->dev; config.driver_data = tps; config.regmap = tps->regmap; for (i = 0; i < ARRAY_SIZE(regulators); i++) { - dev_dbg(tps->dev, "%s regul i= %d START", __func__, i); rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); - if (IS_ERR(rdev)) { - dev_err(tps->dev, "failed to register %s regulator\n", - regulators[i].name); - return PTR_ERR(rdev); - } - rdevtbl[i] = rdev; - dev_dbg(tps->dev, "%s regul i= %d COMPLETED", __func__, i); + if (IS_ERR(rdev)) + return dev_err_probe(tps->dev, PTR_ERR(rdev), + "Failed to register %s regulator\n", + regulators[i].name); } irq_data = devm_kmalloc(tps->dev, @@ -348,14 +328,6 @@ static int tps65219_regulator_probe(struct platform_device *pdev) irq_data[i].dev = tps->dev; irq_data[i].type = irq_type; - tps65219_get_rdev_by_name(irq_type->regulator_name, rdevtbl, &rdev); - if (IS_ERR(rdev)) { - dev_err(tps->dev, "Failed to get rdev for %s\n", - irq_type->regulator_name); - return -EINVAL; - } - irq_data[i].rdev = rdev; - error = devm_request_threaded_irq(tps->dev, irq, NULL, tps65219_regulator_irq_handler, IRQF_ONESHOT, @@ -379,7 +351,7 @@ MODULE_DEVICE_TABLE(platform, tps65219_regulator_id_table); static struct platform_driver tps65219_regulator_driver = { .driver = { - .name = "tps65219-pmic", + .name = "tps65219-regulator", .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = tps65219_regulator_probe, @@ -390,5 +362,4 @@ module_platform_driver(tps65219_regulator_driver); MODULE_AUTHOR("Jerome Neanne <j-neanne@baylibre.com>"); MODULE_DESCRIPTION("TPS65219 voltage regulator driver"); -MODULE_ALIAS("platform:tps65219-pmic"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/tps6594-regulator.c b/drivers/regulator/tps6594-regulator.c index b7f0c8779757..ac53792e3fed 100644 --- a/drivers/regulator/tps6594-regulator.c +++ b/drivers/regulator/tps6594-regulator.c @@ -18,10 +18,13 @@ #include <linux/mfd/tps6594.h> -#define BUCK_NB 5 -#define LDO_NB 4 -#define MULTI_PHASE_NB 4 -#define REGS_INT_NB 4 +#define BUCK_NB 5 +#define LDO_NB 4 +#define MULTI_PHASE_NB 4 +/* TPS6593 and LP8764 supports OV, UV, SC, ILIM */ +#define REGS_INT_NB 4 +/* TPS65224 supports OV or UV */ +#define TPS65224_REGS_INT_NB 1 enum tps6594_regulator_id { /* DCDC's */ @@ -66,6 +69,15 @@ static struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = { REGULATOR_EVENT_OVER_VOLTAGE_WARN }, }; +static struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = { + { TPS65224_IRQ_NAME_VCCA_UVOV, "VCCA", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, + { TPS65224_IRQ_NAME_VMON1_UVOV, "VMON1", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, + { TPS65224_IRQ_NAME_VMON2_UVOV, "VMON2", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + struct tps6594_regulator_irq_data { struct device *dev; struct tps6594_regulator_irq_type *type; @@ -122,6 +134,27 @@ static const struct linear_range ldos_4_ranges[] = { REGULATOR_LINEAR_RANGE(1200000, 0x20, 0x74, 25000), }; +/* Voltage range for TPS65224 Bucks and LDOs */ +static const struct linear_range tps65224_bucks_1_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0x0a, 0x0e, 20000), + REGULATOR_LINEAR_RANGE(600000, 0x0f, 0x72, 5000), + REGULATOR_LINEAR_RANGE(1100000, 0x73, 0xaa, 10000), + REGULATOR_LINEAR_RANGE(1660000, 0xab, 0xfd, 20000), +}; + +static const struct linear_range tps65224_bucks_2_3_4_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0x0, 0x1a, 25000), + REGULATOR_LINEAR_RANGE(1200000, 0x1b, 0x45, 50000), +}; + +static const struct linear_range tps65224_ldos_1_ranges[] = { + REGULATOR_LINEAR_RANGE(1200000, 0xC, 0x36, 50000), +}; + +static const struct linear_range tps65224_ldos_2_3_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x38, 50000), +}; + /* Operations permitted on BUCK1/2/3/4/5 */ static const struct regulator_ops tps6594_bucks_ops = { .is_enabled = regulator_is_enabled_regmap, @@ -197,6 +230,38 @@ static const struct regulator_desc buck_regs[] = { 4, 0, 0, NULL, 0, 0), }; +/* Buck configuration for TPS65224 */ +static const struct regulator_desc tps65224_buck_regs[] = { + TPS6594_REGULATOR("BUCK1", "buck1", TPS6594_BUCK_1, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCK1_VSET, + TPS6594_REG_BUCKX_VOUT_1(0), + TPS65224_MASK_BUCK1_VSET, + TPS6594_REG_BUCKX_CTRL(0), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_1_ranges, + 4, 0, 0, NULL, 0, 0), + TPS6594_REGULATOR("BUCK2", "buck2", TPS6594_BUCK_2, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_VOUT_1(1), + TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_CTRL(1), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges, + 4, 0, 0, NULL, 0, 0), + TPS6594_REGULATOR("BUCK3", "buck3", TPS6594_BUCK_3, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_VOUT_1(2), + TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_CTRL(2), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges, + 4, 0, 0, NULL, 0, 0), + TPS6594_REGULATOR("BUCK4", "buck4", TPS6594_BUCK_4, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_VOUT_1(3), + TPS65224_MASK_BUCKS_VSET, + TPS6594_REG_BUCKX_CTRL(3), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_2_3_4_ranges, + 4, 0, 0, NULL, 0, 0), +}; + static struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = { { TPS6594_IRQ_NAME_BUCK1_OV, "BUCK1", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN }, { TPS6594_IRQ_NAME_BUCK1_UV, "BUCK1", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE }, @@ -269,6 +334,41 @@ static struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; +static struct tps6594_regulator_irq_type tps65224_buck1_irq_types[] = { + { TPS65224_IRQ_NAME_BUCK1_UVOV, "BUCK1", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_buck2_irq_types[] = { + { TPS65224_IRQ_NAME_BUCK2_UVOV, "BUCK2", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_buck3_irq_types[] = { + { TPS65224_IRQ_NAME_BUCK3_UVOV, "BUCK3", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_buck4_irq_types[] = { + { TPS65224_IRQ_NAME_BUCK4_UVOV, "BUCK4", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_ldo1_irq_types[] = { + { TPS65224_IRQ_NAME_LDO1_UVOV, "LDO1", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_ldo2_irq_types[] = { + { TPS65224_IRQ_NAME_LDO2_UVOV, "LDO2", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + +static struct tps6594_regulator_irq_type tps65224_ldo3_irq_types[] = { + { TPS65224_IRQ_NAME_LDO3_UVOV, "LDO3", "voltage out of range", + REGULATOR_EVENT_REGULATION_OUT }, +}; + static struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = { tps6594_buck1_irq_types, tps6594_buck2_irq_types, @@ -284,38 +384,61 @@ static struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = { tps6594_ldo4_irq_types, }; -static const struct regulator_desc multi_regs[] = { +static struct tps6594_regulator_irq_type *tps65224_bucks_irq_types[] = { + tps65224_buck1_irq_types, + tps65224_buck2_irq_types, + tps65224_buck3_irq_types, + tps65224_buck4_irq_types, +}; + +static struct tps6594_regulator_irq_type *tps65224_ldos_irq_types[] = { + tps65224_ldo1_irq_types, + tps65224_ldo2_irq_types, + tps65224_ldo3_irq_types, +}; + +static const struct regulator_desc tps6594_multi_regs[] = { TPS6594_REGULATOR("BUCK12", "buck12", TPS6594_BUCK_1, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_VOUT_1(1), + TPS6594_REG_BUCKX_VOUT_1(0), TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_CTRL(1), + TPS6594_REG_BUCKX_CTRL(0), TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, 4, 4000, 0, NULL, 0, 0), TPS6594_REGULATOR("BUCK34", "buck34", TPS6594_BUCK_3, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_VOUT_1(3), + TPS6594_REG_BUCKX_VOUT_1(2), TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_CTRL(3), + TPS6594_REG_BUCKX_CTRL(2), TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, 4, 0, 0, NULL, 0, 0), TPS6594_REGULATOR("BUCK123", "buck123", TPS6594_BUCK_1, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_VOUT_1(1), + TPS6594_REG_BUCKX_VOUT_1(0), TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_CTRL(1), + TPS6594_REG_BUCKX_CTRL(0), TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, 4, 4000, 0, NULL, 0, 0), TPS6594_REGULATOR("BUCK1234", "buck1234", TPS6594_BUCK_1, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_VOUT_1(1), + TPS6594_REG_BUCKX_VOUT_1(0), TPS6594_MASK_BUCKS_VSET, - TPS6594_REG_BUCKX_CTRL(1), + TPS6594_REG_BUCKX_CTRL(0), TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges, 4, 4000, 0, NULL, 0, 0), }; -static const struct regulator_desc ldo_regs[] = { +static const struct regulator_desc tps65224_multi_regs[] = { + TPS6594_REGULATOR("BUCK12", "buck12", TPS6594_BUCK_1, + REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS65224_MASK_BUCK1_VSET, + TPS6594_REG_BUCKX_VOUT_1(0), + TPS65224_MASK_BUCK1_VSET, + TPS6594_REG_BUCKX_CTRL(0), + TPS6594_BIT_BUCK_EN, 0, 0, tps65224_bucks_1_ranges, + 4, 4000, 0, NULL, 0, 0), +}; + +static const struct regulator_desc tps6594_ldo_regs[] = { TPS6594_REGULATOR("LDO1", "ldo1", TPS6594_LDO_1, REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET, TPS6594_REG_LDOX_VOUT(0), @@ -346,6 +469,30 @@ static const struct regulator_desc ldo_regs[] = { 1, 0, 0, NULL, 0, 0), }; +static const struct regulator_desc tps65224_ldo_regs[] = { + TPS6594_REGULATOR("LDO1", "ldo1", TPS6594_LDO_1, + REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_VOUT(0), + TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_CTRL(0), + TPS6594_BIT_LDO_EN, 0, 0, tps65224_ldos_1_ranges, + 1, 0, 0, NULL, 0, TPS6594_BIT_LDO_BYPASS), + TPS6594_REGULATOR("LDO2", "ldo2", TPS6594_LDO_2, + REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_VOUT(1), + TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_CTRL(1), + TPS6594_BIT_LDO_EN, 0, 0, tps65224_ldos_2_3_ranges, + 1, 0, 0, NULL, 0, TPS6594_BIT_LDO_BYPASS), + TPS6594_REGULATOR("LDO3", "ldo3", TPS6594_LDO_3, + REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_VOUT(2), + TPS6594_MASK_LDO123_VSET, + TPS6594_REG_LDOX_CTRL(2), + TPS6594_BIT_LDO_EN, 0, 0, tps65224_ldos_2_3_ranges, + 1, 0, 0, NULL, 0, TPS6594_BIT_LDO_BYPASS), +}; + static irqreturn_t tps6594_regulator_irq_handler(int irq, void *data) { struct tps6594_regulator_irq_data *irq_data = data; @@ -369,17 +516,18 @@ static irqreturn_t tps6594_regulator_irq_handler(int irq, void *data) static int tps6594_request_reg_irqs(struct platform_device *pdev, struct regulator_dev *rdev, struct tps6594_regulator_irq_data *irq_data, - struct tps6594_regulator_irq_type *tps6594_regs_irq_types, + struct tps6594_regulator_irq_type *regs_irq_types, + size_t interrupt_cnt, int *irq_idx) { struct tps6594_regulator_irq_type *irq_type; struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent); - int j; + size_t j; int irq; int error; - for (j = 0; j < REGS_INT_NB; j++) { - irq_type = &tps6594_regs_irq_types[j]; + for (j = 0; j < interrupt_cnt; j++) { + irq_type = ®s_irq_types[j]; irq = platform_get_irq_byname(pdev, irq_type->irq_name); if (irq < 0) return -EINVAL; @@ -411,23 +559,47 @@ static int tps6594_regulator_probe(struct platform_device *pdev) struct tps6594_regulator_irq_data *irq_data; struct tps6594_ext_regulator_irq_data *irq_ext_reg_data; struct tps6594_regulator_irq_type *irq_type; - u8 buck_configured[BUCK_NB] = { 0 }; - u8 buck_multi[MULTI_PHASE_NB] = { 0 }; - static const char * const multiphases[] = {"buck12", "buck123", "buck1234", "buck34"}; + struct tps6594_regulator_irq_type *irq_types; + bool buck_configured[BUCK_NB] = { false }; + bool buck_multi[MULTI_PHASE_NB] = { false }; + static const char *npname; - int error, i, irq, multi, delta; + int error, i, irq, multi; int irq_idx = 0; int buck_idx = 0; - size_t ext_reg_irq_nb = 2; + int nr_ldo; + int nr_buck; + int nr_types; + unsigned int irq_count; + unsigned int multi_phase_cnt; size_t reg_irq_nb; + struct tps6594_regulator_irq_type **bucks_irq_types; + const struct regulator_desc *multi_regs; + struct tps6594_regulator_irq_type **ldos_irq_types; + const struct regulator_desc *ldo_regs; + size_t interrupt_count; + + if (tps->chip_id == TPS65224) { + bucks_irq_types = tps65224_bucks_irq_types; + interrupt_count = ARRAY_SIZE(tps65224_buck1_irq_types); + multi_regs = tps65224_multi_regs; + ldos_irq_types = tps65224_ldos_irq_types; + ldo_regs = tps65224_ldo_regs; + multi_phase_cnt = ARRAY_SIZE(tps65224_multi_regs); + } else { + bucks_irq_types = tps6594_bucks_irq_types; + interrupt_count = ARRAY_SIZE(tps6594_buck1_irq_types); + multi_regs = tps6594_multi_regs; + ldos_irq_types = tps6594_ldos_irq_types; + ldo_regs = tps6594_ldo_regs; + multi_phase_cnt = ARRAY_SIZE(tps6594_multi_regs); + } + enum { MULTI_BUCK12, + MULTI_BUCK12_34, MULTI_BUCK123, MULTI_BUCK1234, - MULTI_BUCK12_34, - MULTI_FIRST = MULTI_BUCK12, - MULTI_LAST = MULTI_BUCK12_34, - MULTI_NUM = MULTI_LAST - MULTI_FIRST + 1 }; config.dev = tps->dev; @@ -442,61 +614,64 @@ static int tps6594_regulator_probe(struct platform_device *pdev) * In case of Multiphase configuration, value should be defined for * buck_configured to avoid creating bucks for every buck in multiphase */ - for (multi = MULTI_FIRST; multi < MULTI_NUM; multi++) { - np = of_find_node_by_name(tps->dev->of_node, multiphases[multi]); + for (multi = 0; multi < multi_phase_cnt; multi++) { + np = of_find_node_by_name(tps->dev->of_node, multi_regs[multi].supply_name); npname = of_node_full_name(np); np_pmic_parent = of_get_parent(of_get_parent(np)); if (of_node_cmp(of_node_full_name(np_pmic_parent), tps->dev->of_node->full_name)) continue; - delta = strcmp(npname, multiphases[multi]); - if (!delta) { + if (strcmp(npname, multi_regs[multi].supply_name) == 0) { switch (multi) { case MULTI_BUCK12: - buck_multi[0] = 1; - buck_configured[0] = 1; - buck_configured[1] = 1; + buck_multi[0] = true; + buck_configured[0] = true; + buck_configured[1] = true; break; /* multiphase buck34 is supported only with buck12 */ case MULTI_BUCK12_34: - buck_multi[0] = 1; - buck_multi[1] = 1; - buck_configured[0] = 1; - buck_configured[1] = 1; - buck_configured[2] = 1; - buck_configured[3] = 1; + buck_multi[0] = true; + buck_multi[1] = true; + buck_configured[0] = true; + buck_configured[1] = true; + buck_configured[2] = true; + buck_configured[3] = true; break; case MULTI_BUCK123: - buck_multi[2] = 1; - buck_configured[0] = 1; - buck_configured[1] = 1; - buck_configured[2] = 1; + buck_multi[2] = true; + buck_configured[0] = true; + buck_configured[1] = true; + buck_configured[2] = true; break; case MULTI_BUCK1234: - buck_multi[3] = 1; - buck_configured[0] = 1; - buck_configured[1] = 1; - buck_configured[2] = 1; - buck_configured[3] = 1; + buck_multi[3] = true; + buck_configured[0] = true; + buck_configured[1] = true; + buck_configured[2] = true; + buck_configured[3] = true; break; } } } - if (tps->chip_id == LP8764) { - /* There is only 4 buck on LP8764 */ - buck_configured[4] = 1; - reg_irq_nb = size_mul(REGS_INT_NB, (BUCK_NB - 1)); + if (tps->chip_id == TPS65224) { + nr_buck = ARRAY_SIZE(tps65224_buck_regs); + nr_ldo = ARRAY_SIZE(tps65224_ldo_regs); + nr_types = TPS65224_REGS_INT_NB; } else { - reg_irq_nb = size_mul(REGS_INT_NB, (size_add(BUCK_NB, LDO_NB))); + nr_buck = ARRAY_SIZE(buck_regs); + nr_ldo = (tps->chip_id == LP8764) ? 0 : ARRAY_SIZE(tps6594_ldo_regs); + nr_types = REGS_INT_NB; } + reg_irq_nb = nr_types * (nr_buck + nr_ldo); + irq_data = devm_kmalloc_array(tps->dev, reg_irq_nb, sizeof(struct tps6594_regulator_irq_data), GFP_KERNEL); if (!irq_data) return -ENOMEM; - for (i = 0; i < MULTI_PHASE_NB; i++) { - if (buck_multi[i] == 0) + for (i = 0; i < multi_phase_cnt; i++) { + if (!buck_multi[i]) continue; rdev = devm_regulator_register(&pdev->dev, &multi_regs[i], &config); @@ -506,52 +681,60 @@ static int tps6594_regulator_probe(struct platform_device *pdev) pdev->name); /* config multiphase buck12+buck34 */ - if (i == 1) + if (i == MULTI_BUCK12_34) buck_idx = 2; + error = tps6594_request_reg_irqs(pdev, rdev, irq_data, - tps6594_bucks_irq_types[buck_idx], &irq_idx); + bucks_irq_types[buck_idx], + interrupt_count, &irq_idx); if (error) return error; + error = tps6594_request_reg_irqs(pdev, rdev, irq_data, - tps6594_bucks_irq_types[buck_idx + 1], &irq_idx); + bucks_irq_types[buck_idx + 1], + interrupt_count, &irq_idx); if (error) return error; - if (i == 2 || i == 3) { + if (i == MULTI_BUCK123 || i == MULTI_BUCK1234) { error = tps6594_request_reg_irqs(pdev, rdev, irq_data, tps6594_bucks_irq_types[buck_idx + 2], + interrupt_count, &irq_idx); if (error) return error; } - if (i == 3) { + if (i == MULTI_BUCK1234) { error = tps6594_request_reg_irqs(pdev, rdev, irq_data, tps6594_bucks_irq_types[buck_idx + 3], + interrupt_count, &irq_idx); if (error) return error; } } - for (i = 0; i < BUCK_NB; i++) { - if (buck_configured[i] == 1) + for (i = 0; i < nr_buck; i++) { + if (buck_configured[i]) continue; - rdev = devm_regulator_register(&pdev->dev, &buck_regs[i], &config); + const struct regulator_desc *buck_cfg = (tps->chip_id == TPS65224) ? + tps65224_buck_regs : buck_regs; + + rdev = devm_regulator_register(&pdev->dev, &buck_cfg[i], &config); if (IS_ERR(rdev)) return dev_err_probe(tps->dev, PTR_ERR(rdev), - "failed to register %s regulator\n", - pdev->name); + "failed to register %s regulator\n", pdev->name); error = tps6594_request_reg_irqs(pdev, rdev, irq_data, - tps6594_bucks_irq_types[i], &irq_idx); + bucks_irq_types[i], interrupt_count, &irq_idx); if (error) return error; } - /* LP8764 dosen't have LDO */ + /* LP8764 doesn't have LDO */ if (tps->chip_id != LP8764) { - for (i = 0; i < ARRAY_SIZE(ldo_regs); i++) { + for (i = 0; i < nr_ldo; i++) { rdev = devm_regulator_register(&pdev->dev, &ldo_regs[i], &config); if (IS_ERR(rdev)) return dev_err_probe(tps->dev, PTR_ERR(rdev), @@ -559,26 +742,34 @@ static int tps6594_regulator_probe(struct platform_device *pdev) pdev->name); error = tps6594_request_reg_irqs(pdev, rdev, irq_data, - tps6594_ldos_irq_types[i], + ldos_irq_types[i], interrupt_count, &irq_idx); if (error) return error; } } - if (tps->chip_id == LP8764) - ext_reg_irq_nb = ARRAY_SIZE(tps6594_ext_regulator_irq_types); + if (tps->chip_id == TPS65224) { + irq_types = tps65224_ext_regulator_irq_types; + irq_count = ARRAY_SIZE(tps65224_ext_regulator_irq_types); + } else { + irq_types = tps6594_ext_regulator_irq_types; + if (tps->chip_id == LP8764) + irq_count = ARRAY_SIZE(tps6594_ext_regulator_irq_types); + else + /* TPS6593 supports only VCCA OV and UV */ + irq_count = 2; + } irq_ext_reg_data = devm_kmalloc_array(tps->dev, - ext_reg_irq_nb, - sizeof(struct tps6594_ext_regulator_irq_data), - GFP_KERNEL); + irq_count, + sizeof(struct tps6594_ext_regulator_irq_data), + GFP_KERNEL); if (!irq_ext_reg_data) return -ENOMEM; - for (i = 0; i < ext_reg_irq_nb; ++i) { - irq_type = &tps6594_ext_regulator_irq_types[i]; - + for (i = 0; i < irq_count; ++i) { + irq_type = &irq_types[i]; irq = platform_get_irq_byname(pdev, irq_type->irq_name); if (irq < 0) return -EINVAL; @@ -610,5 +801,6 @@ module_platform_driver(tps6594_regulator_driver); MODULE_ALIAS("platform:tps6594-regulator"); MODULE_AUTHOR("Jerome Neanne <jneanne@baylibre.com>"); +MODULE_AUTHOR("Nirmala Devi Mal Nadar <m.nirmaladevi@ltts.com>"); MODULE_DESCRIPTION("TPS6594 voltage regulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c index 5f868042392f..74939b7fcd81 100644 --- a/drivers/regulator/uniphier-regulator.c +++ b/drivers/regulator/uniphier-regulator.c @@ -207,7 +207,7 @@ MODULE_DEVICE_TABLE(of, uniphier_regulator_match); static struct platform_driver uniphier_regulator_driver = { .probe = uniphier_regulator_probe, - .remove_new = uniphier_regulator_remove, + .remove = uniphier_regulator_remove, .driver = { .name = "uniphier-regulator", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index 53d1b9d6f69c..72bb5ffb49a8 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -158,10 +158,8 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev) ret = devm_regulator_bulk_get_exclusive(&pdev->dev, drvdata->num_supplies, drvdata->supplies); - if (ret) { - dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to get supplies\n"); platform_set_drvdata(pdev, drvdata); @@ -208,10 +206,11 @@ static const struct of_device_id regulator_userspace_consumer_of_match[] = { { .compatible = "regulator-output", }, {}, }; +MODULE_DEVICE_TABLE(of, regulator_userspace_consumer_of_match); static struct platform_driver regulator_userspace_consumer_driver = { .probe = regulator_userspace_consumer_probe, - .remove_new = regulator_userspace_consumer_remove, + .remove = regulator_userspace_consumer_remove, .driver = { .name = "reg-userspace-consumer", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index 0a0ee186c6af..218a0d66a152 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -357,7 +357,7 @@ static void regulator_virtual_remove(struct platform_device *pdev) static struct platform_driver regulator_virtual_consumer_driver = { .probe = regulator_virtual_probe, - .remove_new = regulator_virtual_remove, + .remove = regulator_virtual_remove, .driver = { .name = "reg-virt-consumer", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/regulator/vqmmc-ipq4019-regulator.c b/drivers/regulator/vqmmc-ipq4019-regulator.c index 086da36abc0b..4955616517ce 100644 --- a/drivers/regulator/vqmmc-ipq4019-regulator.c +++ b/drivers/regulator/vqmmc-ipq4019-regulator.c @@ -84,6 +84,7 @@ static const struct of_device_id regulator_ipq4019_of_match[] = { { .compatible = "qcom,vqmmc-ipq4019-regulator", }, {}, }; +MODULE_DEVICE_TABLE(of, regulator_ipq4019_of_match); static struct platform_driver ipq4019_regulator_driver = { .probe = ipq4019_regulator_probe, diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index ed5e191e8896..43f220cea21c 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -146,10 +146,10 @@ static int wm831x_isink_probe(struct platform_device *pdev) isink->desc.ops = &wm831x_isink_ops; isink->desc.type = REGULATOR_CURRENT; isink->desc.owner = THIS_MODULE; - isink->desc.curr_table = wm831x_isinkv_values, - isink->desc.n_current_limits = ARRAY_SIZE(wm831x_isinkv_values), - isink->desc.csel_reg = isink->reg, - isink->desc.csel_mask = WM831X_CS1_ISEL_MASK, + isink->desc.curr_table = wm831x_isinkv_values; + isink->desc.n_current_limits = ARRAY_SIZE(wm831x_isinkv_values); + isink->desc.csel_reg = isink->reg; + isink->desc.csel_mask = WM831X_CS1_ISEL_MASK; config.dev = pdev->dev.parent; config.init_data = pdata->isink[id]; diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 9939a5d2cbec..d09864bae5ef 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1304,9 +1304,9 @@ EXPORT_SYMBOL_GPL(wm8350_register_led); static struct platform_driver wm8350_regulator_driver = { .probe = wm8350_regulator_probe, - .remove_new = wm8350_regulator_remove, - .driver = { - .name = "wm8350-regulator", + .remove = wm8350_regulator_remove, + .driver = { + .name = "wm8350-regulator", .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index c4a229f66dec..fb3ca7956d00 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -112,7 +112,7 @@ static const struct regulator_ops wm8400_dcdc_ops = { .get_optimum_mode = wm8400_dcdc_get_optimum_mode, }; -static struct regulator_desc regulators[] = { +static const struct regulator_desc regulators[] = { { .name = "LDO1", .id = WM8400_LDO1, |