diff options
-rw-r--r-- | Documentation/devicetree/bindings/regulator/richtek,rt4831-regulator.yaml | 35 | ||||
-rw-r--r-- | arch/arm64/boot/dts/qcom/qrb5165-rb5.dts | 9 | ||||
-rw-r--r-- | drivers/regulator/Kconfig | 18 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 2 | ||||
-rw-r--r-- | drivers/regulator/atc260x-regulator.c | 539 | ||||
-rw-r--r-- | drivers/regulator/core.c | 6 | ||||
-rw-r--r-- | drivers/regulator/qcom-rpmh-regulator.c | 26 | ||||
-rw-r--r-- | drivers/regulator/rt4831-regulator.c | 198 | ||||
-rw-r--r-- | lib/linear_ranges.c | 8 |
9 files changed, 833 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/regulator/richtek,rt4831-regulator.yaml b/Documentation/devicetree/bindings/regulator/richtek,rt4831-regulator.yaml new file mode 100644 index 000000000000..d9c23333e157 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/richtek,rt4831-regulator.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/richtek,rt4831-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Richtek RT4831 Display Bias Voltage Regulator + +maintainers: + - ChiYuan Huang <[email protected]> + +description: | + RT4831 is a multifunctional device that can provide power to the LCD display + and LCD backlight. + + For Display Bias Voltage DSVP and DSVN, the output range is about 4V to 6.5V. + It is sufficient to meet the current LCD power requirement. + + DSVLCM is a boost regulator in IC internal as DSVP and DSVN input power. + Its voltage should be configured above 0.15V to 0.2V gap larger than the + voltage needed for DSVP and DSVN. Too much voltage gap could improve the + voltage drop from the heavy loading scenario. But it also make the power + efficiency worse. It's a trade-off. + + Datasheet is available at + https://www.richtek.com/assets/product_file/RT4831A/DS4831A-05.pdf + +patternProperties: + "^DSV(LCM|P|N)$": + type: object + $ref: regulator.yaml# + description: + Properties for single Display Bias Voltage regulator. + +additionalProperties: false diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index ce22d4fa383e..7917754c99d6 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -122,7 +122,7 @@ &apps_rsc { pm8009-rpmh-regulators { - compatible = "qcom,pm8009-rpmh-regulators"; + compatible = "qcom,pm8009-1-rpmh-regulators"; qcom,pmic-id = "f"; vdd-s1-supply = <&vph_pwr>; @@ -131,6 +131,13 @@ vdd-l5-l6-supply = <&vreg_bob>; vdd-l7-supply = <&vreg_s4a_1p8>; + vreg_s2f_0p95: smps2 { + regulator-name = "vreg_s2f_0p95"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <952000>; + regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>; + }; + vreg_l1f_1p1: ldo1 { regulator-name = "vreg_l1f_1p1"; regulator-min-microvolt = <1104000>; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 5abdd29fb9f3..b1d2103bfe57 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -179,6 +179,14 @@ config REGULATOR_AS3722 AS3722 PMIC. This will enable support for all the software controllable DCDC/LDO regulators. +config REGULATOR_ATC260X + tristate "Actions Semi ATC260x PMIC Regulators" + depends on MFD_ATC260X + help + This driver provides support for the voltage regulators on the + ATC260x PMICs. This will enable support for all the software + controllable DCDC/LDO regulators. + config REGULATOR_AXP20X tristate "X-POWERS AXP20X PMIC Regulators" depends on MFD_AXP20X @@ -969,6 +977,16 @@ config REGULATOR_RT4801 This adds support for voltage regulators in Richtek RT4801 Display Bias IC. The device supports two regulators (DSVP/DSVN). +config REGULATOR_RT4831 + tristate "Richtek RT4831 DSV Regulators" + depends on MFD_RT4831 + help + This adds support for voltage regulators in Richtek RT4831. + There are three regulators (VLCM/DSVP/DSVN). + VLCM is a virtual voltage input for DSVP/DSVN inside IC. + And DSVP/DSVN is the real Vout range from 4V to 6.5V. + It's common used to provide the power for the display panel. + config REGULATOR_RT5033 tristate "Richtek RT5033 Regulators" depends on MFD_RT5033 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 680e539f6579..dec23fa5c5f2 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_REGULATOR_ARIZONA_MICSUPP) += arizona-micsupp.o obj-$(CONFIG_REGULATOR_ARM_SCMI) += scmi-regulator.o obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o +obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o @@ -118,6 +119,7 @@ obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o obj-$(CONFIG_REGULATOR_ROHM) += rohm-regulator.o obj-$(CONFIG_REGULATOR_RT4801) += rt4801-regulator.o +obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o diff --git a/drivers/regulator/atc260x-regulator.c b/drivers/regulator/atc260x-regulator.c new file mode 100644 index 000000000000..d8b429955d33 --- /dev/null +++ b/drivers/regulator/atc260x-regulator.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Regulator driver for ATC260x PMICs +// +// Copyright (C) 2019 Manivannan Sadhasivam <[email protected]> +// Copyright (C) 2020 Cristian Ciocaltea <[email protected]> + +#include <linux/mfd/atc260x/core.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +struct atc260x_regulator_data { + int voltage_time_dcdc; + int voltage_time_ldo; +}; + +static const struct linear_range atc2603c_dcdc_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(1300000, 0, 13, 50000), + REGULATOR_LINEAR_RANGE(1950000, 14, 15, 100000), +}; + +static const struct linear_range atc2609a_dcdc_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0, 127, 6250), + REGULATOR_LINEAR_RANGE(1400000, 128, 232, 25000), +}; + +static const struct linear_range atc2609a_ldo_voltage_ranges0[] = { + REGULATOR_LINEAR_RANGE(700000, 0, 15, 100000), + REGULATOR_LINEAR_RANGE(2100000, 16, 28, 100000), +}; + +static const struct linear_range atc2609a_ldo_voltage_ranges1[] = { + REGULATOR_LINEAR_RANGE(850000, 0, 15, 100000), + REGULATOR_LINEAR_RANGE(2100000, 16, 27, 100000), +}; + +static const unsigned int atc260x_ldo_voltage_range_sel[] = { + 0x0, 0x1, +}; + +static int atc260x_dcdc_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct atc260x_regulator_data *data = rdev_get_drvdata(rdev); + + if (new_selector > old_selector) + return data->voltage_time_dcdc; + + return 0; +} + +static int atc260x_ldo_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct atc260x_regulator_data *data = rdev_get_drvdata(rdev); + + if (new_selector > old_selector) + return data->voltage_time_ldo; + + return 0; +} + +static const struct regulator_ops atc260x_dcdc_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = atc260x_dcdc_set_voltage_time_sel, +}; + +static const struct regulator_ops atc260x_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, +}; + +static const struct regulator_ops atc260x_ldo_bypass_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, + .set_bypass = regulator_set_bypass_regmap, + .get_bypass = regulator_get_bypass_regmap, +}; + +static const struct regulator_ops atc260x_ldo_bypass_discharge_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, + .set_bypass = regulator_set_bypass_regmap, + .get_bypass = regulator_get_bypass_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +static const struct regulator_ops atc260x_dcdc_range_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = atc260x_dcdc_set_voltage_time_sel, +}; + +static const struct regulator_ops atc260x_ldo_range_pick_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_pickable_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, + .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, +}; + +static const struct regulator_ops atc260x_dcdc_fixed_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = atc260x_dcdc_set_voltage_time_sel, +}; + +static const struct regulator_ops atc260x_ldo_fixed_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel, +}; + +static const struct regulator_ops atc260x_no_ops = { +}; + +/* + * Note LDO8 is not documented in datasheet (v2.4), but supported + * in the vendor's driver implementation (xapp-le-kernel). + */ +enum atc2603c_reg_ids { + ATC2603C_ID_DCDC1, + ATC2603C_ID_DCDC2, + ATC2603C_ID_DCDC3, + ATC2603C_ID_LDO1, + ATC2603C_ID_LDO2, + ATC2603C_ID_LDO3, + ATC2603C_ID_LDO5, + ATC2603C_ID_LDO6, + ATC2603C_ID_LDO7, + ATC2603C_ID_LDO8, + ATC2603C_ID_LDO11, + ATC2603C_ID_LDO12, + ATC2603C_ID_SWITCHLDO1, + ATC2603C_ID_MAX, +}; + +#define atc2603c_reg_desc_dcdc(num, min, step, n_volt, vsel_h, vsel_l) { \ + .name = "DCDC"#num, \ + .supply_name = "dcdc"#num, \ + .of_match = of_match_ptr("dcdc"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2603C_ID_DCDC##num, \ + .ops = &atc260x_dcdc_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = min, \ + .uV_step = step, \ + .n_voltages = n_volt, \ + .vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \ + .vsel_mask = GENMASK(vsel_h, vsel_l), \ + .enable_reg = ATC2603C_PMU_DC##num##_CTL0, \ + .enable_mask = BIT(15), \ + .enable_time = 800, \ + .owner = THIS_MODULE, \ +} + +#define atc2603c_reg_desc_dcdc_range(num, vsel_h, vsel_l) { \ + .name = "DCDC"#num, \ + .supply_name = "dcdc"#num, \ + .of_match = of_match_ptr("dcdc"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2603C_ID_DCDC##num, \ + .ops = &atc260x_dcdc_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .n_voltages = 16, \ + .linear_ranges = atc2603c_dcdc_voltage_ranges, \ + .n_linear_ranges = ARRAY_SIZE(atc2603c_dcdc_voltage_ranges), \ + .vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \ + .vsel_mask = GENMASK(vsel_h, vsel_l), \ + .enable_reg = ATC2603C_PMU_DC##num##_CTL0, \ + .enable_mask = BIT(15), \ + .enable_time = 800, \ + .owner = THIS_MODULE, \ +} + +#define atc2603c_reg_desc_dcdc_fixed(num, min, step, n_volt, vsel_h, vsel_l) { \ + .name = "DCDC"#num, \ + .supply_name = "dcdc"#num, \ + .of_match = of_match_ptr("dcdc"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2603C_ID_DCDC##num, \ + .ops = &atc260x_dcdc_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = min, \ + .uV_step = step, \ + .n_voltages = n_volt, \ + .vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \ + .vsel_mask = GENMASK(vsel_h, vsel_l), \ + .enable_time = 800, \ + .owner = THIS_MODULE, \ +} + +#define atc2603c_reg_desc_ldo(num, min, step, n_volt, vsel_h, vsel_l) { \ + .name = "LDO"#num, \ + .supply_name = "ldo"#num, \ + .of_match = of_match_ptr("ldo"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2603C_ID_LDO##num, \ + .ops = &atc260x_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = min, \ + .uV_step = step, \ + .n_voltages = n_volt, \ + .vsel_reg = ATC2603C_PMU_LDO##num##_CTL, \ + .vsel_mask = GENMASK(vsel_h, vsel_l), \ + .enable_reg = ATC2603C_PMU_LDO##num##_CTL, \ + .enable_mask = BIT(0), \ + .enable_time = 2000, \ + .owner = THIS_MODULE, \ +} + +#define atc2603c_reg_desc_ldo_fixed(num, min, step, n_volt, vsel_h, vsel_l) { \ + .name = "LDO"#num, \ + .supply_name = "ldo"#num, \ + .of_match = of_match_ptr("ldo"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2603C_ID_LDO##num, \ + .ops = &atc260x_ldo_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = min, \ + .uV_step = step, \ + .n_voltages = n_volt, \ + .vsel_reg = ATC2603C_PMU_LDO##num##_CTL, \ + .vsel_mask = GENMASK(vsel_h, vsel_l), \ + .enable_time = 2000, \ + .owner = THIS_MODULE, \ +} + +#define atc2603c_reg_desc_ldo_noops(num, vfixed) { \ + .name = "LDO"#num, \ + .supply_name = "ldo"#num, \ + .of_match = of_match_ptr("ldo"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2603C_ID_LDO##num, \ + .ops = &atc260x_no_ops, \ + .type = REGULATOR_VOLTAGE, \ + .fixed_uV = vfixed, \ + .n_voltages = 1, \ + .owner = THIS_MODULE, \ +} + +#define atc2603c_reg_desc_ldo_switch(num, min, step, n_volt, vsel_h, vsel_l) { \ + .name = "SWITCHLDO"#num, \ + .supply_name = "switchldo"#num, \ + .of_match = of_match_ptr("switchldo"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2603C_ID_SWITCHLDO##num, \ + .ops = &atc260x_ldo_bypass_discharge_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = min, \ + .uV_step = step, \ + .n_voltages = n_volt, \ + .vsel_reg = ATC2603C_PMU_SWITCH_CTL, \ + .vsel_mask = GENMASK(vsel_h, vsel_l), \ + .enable_reg = ATC2603C_PMU_SWITCH_CTL, \ + .enable_mask = BIT(15), \ + .enable_is_inverted = true, \ + .enable_time = 2000, \ + .bypass_reg = ATC2603C_PMU_SWITCH_CTL, \ + .bypass_mask = BIT(5), \ + .active_discharge_reg = ATC2603C_PMU_SWITCH_CTL, \ + .active_discharge_mask = BIT(1), \ + .owner = THIS_MODULE, \ +} + +static const struct regulator_desc atc2603c_reg[] = { + atc2603c_reg_desc_dcdc_fixed(1, 700000, 25000, 29, 11, 7), + atc2603c_reg_desc_dcdc_range(2, 12, 8), + atc2603c_reg_desc_dcdc_fixed(3, 2600000, 100000, 8, 11, 9), + atc2603c_reg_desc_ldo_fixed(1, 2600000, 100000, 8, 15, 13), + atc2603c_reg_desc_ldo_fixed(2, 2600000, 100000, 8, 15, 13), + atc2603c_reg_desc_ldo_fixed(3, 1500000, 100000, 6, 15, 13), + atc2603c_reg_desc_ldo(5, 2600000, 100000, 8, 15, 13), + atc2603c_reg_desc_ldo_fixed(6, 700000, 25000, 29, 15, 11), + atc2603c_reg_desc_ldo(7, 1500000, 100000, 6, 15, 13), + atc2603c_reg_desc_ldo(8, 2300000, 100000, 11, 15, 12), + atc2603c_reg_desc_ldo_fixed(11, 2600000, 100000, 8, 15, 13), + atc2603c_reg_desc_ldo_noops(12, 1800000), + atc2603c_reg_desc_ldo_switch(1, 3000000, 100000, 4, 4, 3), +}; + +static const struct regulator_desc atc2603c_reg_dcdc2_ver_b = + atc2603c_reg_desc_dcdc(2, 1000000, 50000, 18, 12, 8); + +enum atc2609a_reg_ids { + ATC2609A_ID_DCDC0, + ATC2609A_ID_DCDC1, + ATC2609A_ID_DCDC2, + ATC2609A_ID_DCDC3, + ATC2609A_ID_DCDC4, + ATC2609A_ID_LDO0, + ATC2609A_ID_LDO1, + ATC2609A_ID_LDO2, + ATC2609A_ID_LDO3, + ATC2609A_ID_LDO4, + ATC2609A_ID_LDO5, + ATC2609A_ID_LDO6, + ATC2609A_ID_LDO7, + ATC2609A_ID_LDO8, + ATC2609A_ID_LDO9, + ATC2609A_ID_MAX, +}; + +#define atc2609a_reg_desc_dcdc(num, en_bit) { \ + .name = "DCDC"#num, \ + .supply_name = "dcdc"#num, \ + .of_match = of_match_ptr("dcdc"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2609A_ID_DCDC##num, \ + .ops = &atc260x_dcdc_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = 600000, \ + .uV_step = 6250, \ + .n_voltages = 256, \ + .vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \ + .vsel_mask = GENMASK(15, 8), \ + .enable_reg = ATC2609A_PMU_DC_OSC, \ + .enable_mask = BIT(en_bit), \ + .enable_time = 800, \ + .owner = THIS_MODULE, \ +} + +#define atc2609a_reg_desc_dcdc_range(num, en_bit) { \ + .name = "DCDC"#num, \ + .supply_name = "dcdc"#num, \ + .of_match = of_match_ptr("dcdc"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2609A_ID_DCDC##num, \ + .ops = &atc260x_dcdc_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .n_voltages = 233, \ + .linear_ranges = atc2609a_dcdc_voltage_ranges, \ + .n_linear_ranges = ARRAY_SIZE(atc2609a_dcdc_voltage_ranges), \ + .vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \ + .vsel_mask = GENMASK(15, 8), \ + .enable_reg = ATC2609A_PMU_DC_OSC, \ + .enable_mask = BIT(en_bit), \ + .enable_time = 800, \ + .owner = THIS_MODULE, \ +} + +#define atc2609a_reg_desc_ldo(num) { \ + .name = "LDO"#num, \ + .supply_name = "ldo"#num, \ + .of_match = of_match_ptr("ldo"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2609A_ID_LDO##num, \ + .ops = &atc260x_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = 700000, \ + .uV_step = 100000, \ + .n_voltages = 16, \ + .vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \ + .vsel_mask = GENMASK(4, 1), \ + .enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \ + .enable_mask = BIT(0), \ + .enable_time = 2000, \ + .owner = THIS_MODULE, \ +} + +#define atc2609a_reg_desc_ldo_bypass(num) { \ + .name = "LDO"#num, \ + .supply_name = "ldo"#num, \ + .of_match = of_match_ptr("ldo"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2609A_ID_LDO##num, \ + .ops = &atc260x_ldo_bypass_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = 2300000, \ + .uV_step = 100000, \ + .n_voltages = 12, \ + .vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \ + .vsel_mask = GENMASK(5, 2), \ + .enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \ + .enable_mask = BIT(0), \ + .enable_time = 2000, \ + .bypass_reg = ATC2609A_PMU_LDO##num##_CTL0, \ + .bypass_mask = BIT(1), \ + .owner = THIS_MODULE, \ +} + +#define atc2609a_reg_desc_ldo_range_pick(num, n_range) { \ + .name = "LDO"#num, \ + .supply_name = "ldo"#num, \ + .of_match = of_match_ptr("ldo"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2609A_ID_LDO##num, \ + .ops = &atc260x_ldo_range_pick_ops, \ + .type = REGULATOR_VOLTAGE, \ + .linear_ranges = atc2609a_ldo_voltage_ranges##n_range, \ + .n_linear_ranges = ARRAY_SIZE(atc2609a_ldo_voltage_ranges##n_range), \ + .vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \ + .vsel_mask = GENMASK(4, 1), \ + .vsel_range_reg = ATC2609A_PMU_LDO##num##_CTL0, \ + .vsel_range_mask = BIT(5), \ + .linear_range_selectors = atc260x_ldo_voltage_range_sel, \ + .enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \ + .enable_mask = BIT(0), \ + .enable_time = 2000, \ + .owner = THIS_MODULE, \ +} + +#define atc2609a_reg_desc_ldo_fixed(num) { \ + .name = "LDO"#num, \ + .supply_name = "ldo"#num, \ + .of_match = of_match_ptr("ldo"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = ATC2609A_ID_LDO##num, \ + .ops = &atc260x_ldo_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .min_uV = 2600000, \ + .uV_step = 100000, \ + .n_voltages = 8, \ + .vsel_reg = ATC2609A_PMU_LDO##num##_CTL, \ + .vsel_mask = GENMASK(15, 13), \ + .enable_time = 2000, \ + .owner = THIS_MODULE, \ +} + +static const struct regulator_desc atc2609a_reg[] = { + atc2609a_reg_desc_dcdc(0, 4), + atc2609a_reg_desc_dcdc(1, 5), + atc2609a_reg_desc_dcdc(2, 6), + atc2609a_reg_desc_dcdc_range(3, 7), + atc2609a_reg_desc_dcdc(4, 8), + atc2609a_reg_desc_ldo_bypass(0), + atc2609a_reg_desc_ldo_bypass(1), + atc2609a_reg_desc_ldo_bypass(2), + atc2609a_reg_desc_ldo_range_pick(3, 0), + atc2609a_reg_desc_ldo_range_pick(4, 0), + atc2609a_reg_desc_ldo(5), + atc2609a_reg_desc_ldo_range_pick(6, 1), + atc2609a_reg_desc_ldo_range_pick(7, 0), + atc2609a_reg_desc_ldo_range_pick(8, 0), + atc2609a_reg_desc_ldo_fixed(9), +}; + +static int atc260x_regulator_probe(struct platform_device *pdev) +{ + struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent); + struct device *dev = atc260x->dev; + struct atc260x_regulator_data *atc260x_data; + struct regulator_config config = {}; + struct regulator_dev *atc260x_rdev; + const struct regulator_desc *regulators; + bool atc2603c_ver_b = false; + int i, nregulators; + + atc260x_data = devm_kzalloc(&pdev->dev, sizeof(*atc260x_data), GFP_KERNEL); + if (!atc260x_data) + return -ENOMEM; + + atc260x_data->voltage_time_dcdc = 350; + atc260x_data->voltage_time_ldo = 800; + + switch (atc260x->ic_type) { + case ATC2603C: + regulators = atc2603c_reg; + nregulators = ATC2603C_ID_MAX; + atc2603c_ver_b = atc260x->ic_ver == ATC260X_B; + break; + case ATC2609A: + atc260x_data->voltage_time_dcdc = 250; + regulators = atc2609a_reg; + nregulators = ATC2609A_ID_MAX; + break; + default: + dev_err(dev, "unsupported ATC260X ID %d\n", atc260x->ic_type); + return -EINVAL; + } + + config.dev = dev; + config.regmap = atc260x->regmap; + config.driver_data = atc260x_data; + + /* Instantiate the regulators */ + for (i = 0; i < nregulators; i++) { + if (atc2603c_ver_b && regulators[i].id == ATC2603C_ID_DCDC2) + atc260x_rdev = devm_regulator_register(&pdev->dev, + &atc2603c_reg_dcdc2_ver_b, + &config); + else + atc260x_rdev = devm_regulator_register(&pdev->dev, + ®ulators[i], + &config); + if (IS_ERR(atc260x_rdev)) { + dev_err(dev, "failed to register regulator: %d\n", i); + return PTR_ERR(atc260x_rdev); + } + } + + return 0; +} + +static struct platform_driver atc260x_regulator_driver = { + .probe = atc260x_regulator_probe, + .driver = { + .name = "atc260x-regulator", + }, +}; + +module_platform_driver(atc260x_regulator_driver); + +MODULE_DESCRIPTION("Regulator driver for ATC260x PMICs"); +MODULE_AUTHOR("Manivannan Sadhasivam <[email protected]>"); +MODULE_AUTHOR("Cristian Ciocaltea <[email protected]>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ca03d8e70bd1..fee924158091 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2020,7 +2020,7 @@ struct regulator *_regulator_get(struct device *dev, const char *id, * Returns a struct regulator corresponding to the regulator producer, * or IS_ERR() condition containing errno. * - * Use of supply names configured via regulator_set_device_supply() is + * 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. @@ -2047,7 +2047,7 @@ EXPORT_SYMBOL_GPL(regulator_get); * regulator off for correct operation of the hardware they are * controlling. * - * Use of supply names configured via regulator_set_device_supply() is + * 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. @@ -2073,7 +2073,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive); * disrupting the operation of drivers that can handle absent * supplies. * - * Use of supply names configured via regulator_set_device_supply() is + * 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. diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index c395a8dda6f7..98320e1d8bf6 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -732,6 +732,15 @@ static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = { .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, }; +static const struct rpmh_vreg_hw_data pmic5_hfsmps515_1 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(900000, 0, 4, 16000), + .n_voltages = 5, + .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_bob = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_bypass_ops, @@ -932,6 +941,19 @@ static const struct rpmh_vreg_init_data pm8009_vreg_data[] = { {}, }; +static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515_1, "vdd-s2"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo7", "ldo%s6", &pmic5_pldo_lv, "vdd-l7"), + {}, +}; + static const struct rpmh_vreg_init_data pm6150_vreg_data[] = { RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), @@ -1058,6 +1080,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .data = pm8009_vreg_data, }, { + .compatible = "qcom,pm8009-1-rpmh-regulators", + .data = pm8009_1_vreg_data, + }, + { .compatible = "qcom,pm8150-rpmh-regulators", .data = pm8150_vreg_data, }, diff --git a/drivers/regulator/rt4831-regulator.c b/drivers/regulator/rt4831-regulator.c new file mode 100644 index 000000000000..3d4695ded629 --- /dev/null +++ b/drivers/regulator/rt4831-regulator.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/bitops.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> + +enum { + DSV_OUT_VLCM = 0, + DSV_OUT_VPOS, + DSV_OUT_VNEG, + DSV_OUT_MAX +}; + +#define RT4831_REG_DSVEN 0x09 +#define RT4831_REG_VLCM 0x0c +#define RT4831_REG_VPOS 0x0d +#define RT4831_REG_VNEG 0x0e +#define RT4831_REG_FLAGS 0x0f + +#define RT4831_VOLT_MASK GENMASK(5, 0) +#define RT4831_DSVMODE_SHIFT 5 +#define RT4831_DSVMODE_MASK GENMASK(7, 5) +#define RT4831_POSADEN_MASK BIT(4) +#define RT4831_NEGADEN_MASK BIT(3) +#define RT4831_POSEN_MASK BIT(2) +#define RT4831_NEGEN_MASK BIT(1) + +#define RT4831_OTP_MASK BIT(6) +#define RT4831_LCMOVP_MASK BIT(5) +#define RT4831_VPOSSCP_MASK BIT(3) +#define RT4831_VNEGSCP_MASK BIT(2) + +#define DSV_MODE_NORMAL (0x4 << RT4831_DSVMODE_SHIFT) +#define DSV_MODE_BYPASS (0x6 << RT4831_DSVMODE_SHIFT) +#define STEP_UV 50000 +#define VLCM_MIN_UV 4000000 +#define VLCM_MAX_UV 7150000 +#define VLCM_N_VOLTAGES ((VLCM_MAX_UV - VLCM_MIN_UV) / STEP_UV + 1) +#define VPN_MIN_UV 4000000 +#define VPN_MAX_UV 6500000 +#define VPN_N_VOLTAGES ((VPN_MAX_UV - VPN_MIN_UV) / STEP_UV + 1) + +static int rt4831_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + int rid = rdev_get_id(rdev); + unsigned int val, events = 0; + int ret; + + ret = regmap_read(regmap, RT4831_REG_FLAGS, &val); + if (ret) + return ret; + + if (val & RT4831_OTP_MASK) + events |= REGULATOR_ERROR_OVER_TEMP; + + if (rid == DSV_OUT_VLCM && (val & RT4831_LCMOVP_MASK)) + events |= REGULATOR_ERROR_OVER_CURRENT; + + if (rid == DSV_OUT_VPOS && (val & RT4831_VPOSSCP_MASK)) + events |= REGULATOR_ERROR_OVER_CURRENT; + + if (rid == DSV_OUT_VNEG && (val & RT4831_VNEGSCP_MASK)) + events |= REGULATOR_ERROR_OVER_CURRENT; + + *flags = events; + return 0; +} + +static const struct regulator_ops rt4831_dsvlcm_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_bypass = regulator_set_bypass_regmap, + .get_bypass = regulator_get_bypass_regmap, + .get_error_flags = rt4831_get_error_flags, +}; + +static const struct regulator_ops rt4831_dsvpn_ops = { + .list_voltage = regulator_list_voltage_linear, + .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, + .set_active_discharge = regulator_set_active_discharge_regmap, + .get_error_flags = rt4831_get_error_flags, +}; + +static const struct regulator_desc rt4831_regulator_descs[] = { + { + .name = "DSVLCM", + .ops = &rt4831_dsvlcm_ops, + .of_match = of_match_ptr("DSVLCM"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_VOLTAGE, + .id = DSV_OUT_VLCM, + .n_voltages = VLCM_N_VOLTAGES, + .min_uV = VLCM_MIN_UV, + .uV_step = STEP_UV, + .vsel_reg = RT4831_REG_VLCM, + .vsel_mask = RT4831_VOLT_MASK, + .bypass_reg = RT4831_REG_DSVEN, + .bypass_val_on = DSV_MODE_BYPASS, + .bypass_val_off = DSV_MODE_NORMAL, + }, + { + .name = "DSVP", + .ops = &rt4831_dsvpn_ops, + .of_match = of_match_ptr("DSVP"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_VOLTAGE, + .id = DSV_OUT_VPOS, + .n_voltages = VPN_N_VOLTAGES, + .min_uV = VPN_MIN_UV, + .uV_step = STEP_UV, + .vsel_reg = RT4831_REG_VPOS, + .vsel_mask = RT4831_VOLT_MASK, + .enable_reg = RT4831_REG_DSVEN, + .enable_mask = RT4831_POSEN_MASK, + .active_discharge_reg = RT4831_REG_DSVEN, + .active_discharge_mask = RT4831_POSADEN_MASK, + }, + { + .name = "DSVN", + .ops = &rt4831_dsvpn_ops, + .of_match = of_match_ptr("DSVN"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_VOLTAGE, + .id = DSV_OUT_VNEG, + .n_voltages = VPN_N_VOLTAGES, + .min_uV = VPN_MIN_UV, + .uV_step = STEP_UV, + .vsel_reg = RT4831_REG_VNEG, + .vsel_mask = RT4831_VOLT_MASK, + .enable_reg = RT4831_REG_DSVEN, + .enable_mask = RT4831_NEGEN_MASK, + .active_discharge_reg = RT4831_REG_DSVEN, + .active_discharge_mask = RT4831_NEGADEN_MASK, + } +}; + +static int rt4831_regulator_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + struct regulator_dev *rdev; + struct regulator_config config = {}; + int i, ret; + + regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "Failed to init regmap\n"); + return PTR_ERR(regmap); + } + + /* Configure DSV mode to normal by default */ + ret = regmap_update_bits(regmap, RT4831_REG_DSVEN, RT4831_DSVMODE_MASK, DSV_MODE_NORMAL); + if (ret) { + dev_err(&pdev->dev, "Failed to configure dsv mode to normal\n"); + return ret; + } + + config.dev = pdev->dev.parent; + config.regmap = regmap; + + for (i = 0; i < DSV_OUT_MAX; i++) { + rdev = devm_regulator_register(&pdev->dev, rt4831_regulator_descs + i, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register %d regulator\n", i); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id rt4831_regulator_match[] = { + { "rt4831-regulator", 0 }, + {} +}; +MODULE_DEVICE_TABLE(platform, rt4831_regulator_match); + +static struct platform_driver rt4831_regulator_driver = { + .driver = { + .name = "rt4831-regulator", + }, + .id_table = rt4831_regulator_match, + .probe = rt4831_regulator_probe, +}; +module_platform_driver(rt4831_regulator_driver); + +MODULE_AUTHOR("ChiYuan Huang <[email protected]>"); +MODULE_LICENSE("GPL v2"); diff --git a/lib/linear_ranges.c b/lib/linear_ranges.c index 9495ef3572b7..ced5c15d3f04 100644 --- a/lib/linear_ranges.c +++ b/lib/linear_ranges.c @@ -128,7 +128,7 @@ EXPORT_SYMBOL_GPL(linear_range_get_value_array); * @selector: address where found selector value is updated * @found: flag to indicate that given value was in the range * - * Return selector which which range value is closest match for given + * Return selector for which range value is closest match for given * input value. Value is matching if it is equal or smaller than given * value. If given value is in the range, then @found is set true. * @@ -168,11 +168,11 @@ EXPORT_SYMBOL_GPL(linear_range_get_selector_low); * @selector: address where found selector value is updated * @found: flag to indicate that given value was in the range * - * Scan array of ranges for selector which which range value matches given + * Scan array of ranges for selector for which range value matches given * input value. Value is matching if it is equal or smaller than given * value. If given value is found to be in a range scanning is stopped and * @found is set true. If a range with values smaller than given value is found - * but the range max is being smaller than given value, then the ranges + * but the range max is being smaller than given value, then the range's * biggest selector is updated to @selector but scanning ranges is continued * and @found is set to false. * @@ -209,7 +209,7 @@ EXPORT_SYMBOL_GPL(linear_range_get_selector_low_array); * @selector: address where found selector value is updated * @found: flag to indicate that given value was in the range * - * Return selector which which range value is closest match for given + * Return selector for which range value is closest match for given * input value. Value is matching if it is equal or higher than given * value. If given value is in the range, then @found is set true. * |