diff options
25 files changed, 1955 insertions, 470 deletions
diff --git a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml index 90727fdc1283..7023c597c3ed 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml @@ -15,6 +15,7 @@ properties: compatible: enum: - mps,mp5416 + - mps,mp5496 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt deleted file mode 100644 index 3d78d507e29f..000000000000 --- a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt +++ /dev/null @@ -1,92 +0,0 @@ -Bindings for the Generic PWM Regulator -====================================== - -Currently supports 2 modes of operation: - -Voltage Table: When in this mode, a voltage table (See below) of - predefined voltage <=> duty-cycle values must be - provided via DT. Limitations are that the regulator can - only operate at the voltages supplied in the table. - Intermediary duty-cycle values which would normally - allow finer grained voltage selection are ignored and - rendered useless. Although more control is given to - the user if the assumptions made in continuous-voltage - mode do not reign true. - -Continuous Voltage: This mode uses the regulator's maximum and minimum - supplied voltages specified in the - regulator-{min,max}-microvolt properties to calculate - appropriate duty-cycle values. This allows for a much - more fine grained solution when compared with - voltage-table mode above. This solution does make an - assumption that a %50 duty-cycle value will cause the - regulator voltage to run at half way between the - supplied max_uV and min_uV values. - -Required properties: --------------------- -- compatible: Should be "pwm-regulator" - -- pwms: PWM specification (See: ../pwm/pwm.txt) - -Only required for Voltage Table Mode: -- voltage-table: Voltage and Duty-Cycle table consisting of 2 cells - First cell is voltage in microvolts (uV) - Second cell is duty-cycle in percent (%) - -Optional properties for Continuous mode: -- pwm-dutycycle-unit: Integer value encoding the duty cycle unit. If not - defined, <100> is assumed, meaning that - pwm-dutycycle-range contains values expressed in - percent. - -- pwm-dutycycle-range: Should contain 2 entries. The first entry is encoding - the dutycycle for regulator-min-microvolt and the - second one the dutycycle for regulator-max-microvolt. - Duty cycle values are expressed in pwm-dutycycle-unit. - If not defined, <0 100> is assumed. - -NB: To be clear, if voltage-table is provided, then the device will be used -in Voltage Table Mode. If no voltage-table is provided, then the device will -be used in Continuous Voltage Mode. - -Optional properties: --------------------- -- enable-gpios: GPIO to use to enable/disable the regulator - -Any property defined as part of the core regulator binding can also be used. -(See: ../regulator/regulator.txt) - -Continuous Voltage With Enable GPIO Example: - pwm_regulator { - compatible = "pwm-regulator"; - pwms = <&pwm1 0 8448 0>; - enable-gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>; - regulator-min-microvolt = <1016000>; - regulator-max-microvolt = <1114000>; - regulator-name = "vdd_logic"; - /* unit == per-mille */ - pwm-dutycycle-unit = <1000>; - /* - * Inverted PWM logic, and the duty cycle range is limited - * to 30%-70%. - */ - pwm-dutycycle-range = <700 300>; /* */ - }; - -Voltage Table Example: - pwm_regulator { - compatible = "pwm-regulator"; - pwms = <&pwm1 0 8448 0>; - regulator-min-microvolt = <1016000>; - regulator-max-microvolt = <1114000>; - regulator-name = "vdd_logic"; - - /* Voltage Duty-Cycle */ - voltage-table = <1114000 0>, - <1095000 10>, - <1076000 20>, - <1056000 30>, - <1036000 40>, - <1016000 50>; - }; diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.yaml b/Documentation/devicetree/bindings/regulator/pwm-regulator.yaml new file mode 100644 index 000000000000..82b6f2fde422 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.yaml @@ -0,0 +1,126 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/pwm-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bindings for the Generic PWM Regulator + +maintainers: + - Brian Norris <briannorris@chromium.org> + - Lee Jones <lee@kernel.org> + - Alexandre Courbot <acourbot@nvidia.com> + +description: | + Currently supports 2 modes of operation: + + Voltage Table: + When in this mode, a voltage table (See below) of predefined voltage <=> + duty-cycle values must be provided via DT. Limitations are that the + regulator can only operate at the voltages supplied in the table. + Intermediary duty-cycle values which would normally allow finer grained + voltage selection are ignored and rendered useless. Although more control + is given to the user if the assumptions made in continuous-voltage mode do + not reign true. + + Continuous Voltage: + This mode uses the regulator's maximum and minimum supplied voltages + specified in the regulator-{min,max}-microvolt properties to calculate + appropriate duty-cycle values. This allows for a much more fine grained + solution when compared with voltage-table mode above. This solution does + make an assumption that a %50 duty-cycle value will cause the regulator + voltage to run at half way between the supplied max_uV and min_uV values. + + If voltage-table is provided, then the device will be used in Voltage Table + Mode. If no voltage-table is provided, then the device will be used in + Continuous Voltage Mode. + +allOf: + - $ref: regulator.yaml# + +properties: + compatible: + const: pwm-regulator + + pwms: + maxItems: 1 + + voltage-table: + description: Voltage and Duty-Cycle table. + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + items: + - description: voltage in microvolts (uV) + - description: duty-cycle in percent (%) + + enable-gpios: + description: Regulator enable GPIO + maxItems: 1 + + # Optional properties for Continuous mode: + pwm-dutycycle-unit: + description: + Integer value encoding the duty cycle unit. If not + defined, <100> is assumed, meaning that + pwm-dutycycle-range contains values expressed in + percent. + default: 100 + + pwm-dutycycle-range: + description: + Should contain 2 entries. The first entry is encoding + the dutycycle for regulator-min-microvolt and the + second one the dutycycle for regulator-max-microvolt. + Duty cycle values are expressed in pwm-dutycycle-unit. + If not defined, <0 100> is assumed. + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + - description: the dutycycle for regulator-min-microvolt + - description: the dutycycle for regulator-max-microvolt + default: [ 0 100 ] + +required: + - compatible + - pwms + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + // Continuous Voltage With Enable GPIO Example: + regulator { + compatible = "pwm-regulator"; + pwms = <&pwm1 0 8448 0>; + enable-gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>; + regulator-min-microvolt = <1016000>; + regulator-max-microvolt = <1114000>; + regulator-name = "vdd_logic"; + /* unit == per-mille */ + pwm-dutycycle-unit = <1000>; + /* + * Inverted PWM logic, and the duty cycle range is limited + * to 30%-70%. + */ + pwm-dutycycle-range = <700 300>; /* */ + }; + + - | + // Voltage Table Example: + regulator { + compatible = "pwm-regulator"; + pwms = <&pwm1 0 8448 0>; + regulator-min-microvolt = <1016000>; + regulator-max-microvolt = <1114000>; + regulator-name = "vdd_logic"; + + /* Voltage Duty-Cycle */ + voltage-table = <1114000 0>, + <1095000 10>, + <1076000 20>, + <1056000 30>, + <1036000 40>, + <1016000 50>; + }; +... diff --git a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml index 6a9a7eed466f..c233461cc980 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml @@ -30,6 +30,9 @@ description: For pm8841, s1, s2, s3, s4, s5, s6, s7, s8 + For pm8909, s1, s2, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, + l14, l15, l17, l18 + For pm8916, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18 @@ -78,6 +81,7 @@ properties: - qcom,rpm-mp5496-regulators - qcom,rpm-pm8226-regulators - qcom,rpm-pm8841-regulators + - qcom,rpm-pm8909-regulators - qcom,rpm-pm8916-regulators - qcom,rpm-pm8941-regulators - qcom,rpm-pm8950-regulators diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt deleted file mode 100644 index c2a39b121b1b..000000000000 --- a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt +++ /dev/null @@ -1,347 +0,0 @@ -Qualcomm SPMI Regulators - -- compatible: - Usage: required - Value type: <string> - Definition: must be one of: - "qcom,pm8004-regulators" - "qcom,pm8005-regulators" - "qcom,pm8226-regulators" - "qcom,pm8841-regulators" - "qcom,pm8916-regulators" - "qcom,pm8941-regulators" - "qcom,pm8950-regulators" - "qcom,pm8994-regulators" - "qcom,pmi8994-regulators" - "qcom,pm660-regulators" - "qcom,pm660l-regulators" - "qcom,pms405-regulators" - -- interrupts: - Usage: optional - Value type: <prop-encoded-array> - Definition: List of OCP interrupts. - -- interrupt-names: - Usage: required if 'interrupts' property present - Value type: <string-array> - Definition: List of strings defining the names of the - interrupts in the 'interrupts' property 1-to-1. - Supported values are "ocp-<regulator_name>", where - <regulator_name> corresponds to a voltage switch - type regulator. - -- vdd_s1-supply: -- vdd_s2-supply: -- vdd_s3-supply: -- vdd_s4-supply: -- vdd_s5-supply: -- vdd_s6-supply: -- vdd_s7-supply: -- vdd_s8-supply: - Usage: optional (pm8841 only) - Value type: <phandle> - Definition: Reference to regulator supplying the input pin, as - described in the data sheet. - -- vdd_s1-supply: -- vdd_s2-supply: -- vdd_s3-supply: -- vdd_s4-supply: -- vdd_l1_l3-supply: -- vdd_l2-supply: -- vdd_l4_l5_l6-supply: -- vdd_l7-supply: -- vdd_l8_l11_l14_l15_l16-supply: -- vdd_l9_l10_l12_l13_l17_l18-supply: - Usage: optional (pm8916 only) - Value type: <phandle> - Definition: Reference to regulator supplying the input pin, as - described in the data sheet. - -- vdd_s1-supply: -- vdd_s2-supply: -- vdd_s3-supply: -- vdd_l1_l3-supply: -- vdd_l2_lvs_1_2_3-supply: -- vdd_l4_l11-supply: -- vdd_l5_l7-supply: -- vdd_l6_l12_l14_l15-supply: -- vdd_l8_l16_l18_19-supply: -- vdd_l9_l10_l17_l22-supply: -- vdd_l13_l20_l23_l24-supply: -- vdd_l21-supply: -- vin_5vs-supply: - Usage: optional (pm8941 only) - Value type: <phandle> - Definition: Reference to regulator supplying the input pin, as - described in the data sheet. - -- vdd_s1-supply: -- vdd_s2-supply: -- vdd_s3-supply: -- vdd_s4-supply: -- vdd_s4-supply: -- vdd_s5-supply: -- vdd_s6-supply: -- vdd_l1_l19-supply: -- vdd_l2_l23-supply: -- vdd_l3-supply: -- vdd_l4_l5_l6_l7_l16-supply: -- vdd_l8_l11_l12_l17_l22-supply: -- vdd_l9_l10_l13_l14_l15_l18-supply: -- vdd_l20-supply: -- vdd_l21-supply: - Usage: optional (pm8950 only) - Value type: <phandle> - Definition: reference to regulator supplying the input pin, as - described in the data sheet - -- vdd_s1-supply: -- vdd_s2-supply: -- vdd_s3-supply: -- vdd_s4-supply: -- vdd_s5-supply: -- vdd_s6-supply: -- vdd_s7-supply: -- vdd_s8-supply: -- vdd_s9-supply: -- vdd_s10-supply: -- vdd_s11-supply: -- vdd_s12-supply: -- vdd_l1-supply: -- vdd_l2_l26_l28-supply: -- vdd_l3_l11-supply: -- vdd_l4_l27_l31-supply: -- vdd_l5_l7-supply: -- vdd_l6_l12_l32-supply: -- vdd_l8_l16_l30-supply: -- vdd_l9_l10_l18_l22-supply: -- vdd_l13_l19_l23_l24-supply: -- vdd_l14_l15-supply: -- vdd_l17_l29-supply: -- vdd_l20_l21-supply: -- vdd_l25-supply: -- vdd_lvs_1_2-supply: - Usage: optional (pm8994 only) - Value type: <phandle> - Definition: Reference to regulator supplying the input pin, as - described in the data sheet. - -- vdd_s1-supply: -- vdd_s2-supply: -- vdd_s3-supply: -- vdd_l1-supply: - Usage: optional (pmi8994 only) - Value type: <phandle> - Definition: Reference to regulator supplying the input pin, as - described in the data sheet. - -- vdd_l1_l6_l7-supply: -- vdd_l2_l3-supply: -- vdd_l5-supply: -- vdd_l8_l9_l10_l11_l12_l13_l14-supply: -- vdd_l15_l16_l17_l18_l19-supply: -- vdd_s1-supply: -- vdd_s2-supply: -- vdd_s3-supply: -- vdd_s5-supply: -- vdd_s6-supply: - Usage: optional (pm660 only) - Value type: <phandle> - Definition: Reference to regulator supplying the input pin, as - described in the data sheet. - -- vdd_l1_l9_l10-supply: -- vdd_l2-supply: -- vdd_l3_l5_l7_l8-supply: -- vdd_l4_l6-supply: -- vdd_s1-supply: -- vdd_s2-supply: -- vdd_s3-supply: -- vdd_s4-supply: -- vdd_s5-supply: - Usage: optional (pm660l only) - Value type: <phandle> - Definition: Reference to regulator supplying the input pin, as - described in the data sheet. - -- vdd_l1_l2-supply: -- vdd_l3_l8-supply: -- vdd_l4-supply: -- vdd_l5_l6-supply: -- vdd_l10_l11_l12_l13-supply: -- vdd_l7-supply: -- vdd_l9-supply: -- vdd_s1-supply: -- vdd_s2-supply: -- vdd_s3-supply: -- vdd_s4-supply: -- vdd_s5-supply - Usage: optional (pms405 only) - Value type: <phandle> - Definition: Reference to regulator supplying the input pin, as - described in the data sheet. - -- qcom,saw-reg: - Usage: optional - Value type: <phandle> - Description: Reference to syscon node defining the SAW registers. - - -The regulator node houses sub-nodes for each regulator within the device. Each -sub-node is identified using the node's name, with valid values listed for each -of the PMICs below. - -pm8004: - s2, s5 - -pm8005: - s1, s2, s3, s4 - -pm8841: - s1, s2, s3, s4, s5, s6, s7, s8 - -pm8916: - s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, - l14, l15, l16, l17, l18 - -pm8941: - s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, - l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3, - 5vs1, 5vs2 - -pm8994: - s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5, - l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, - l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, lvs1, lvs2 - -pmi8994: - s1, s2, s3, l1 - -The content of each sub-node is defined by the standard binding for regulators - -see regulator.txt - with additional custom properties described below: - -- regulator-initial-mode: - Usage: optional - Value type: <u32> - Description: 2 = Set initial mode to auto mode (automatically select - between HPM and LPM); not available on boost type - regulators. - - 1 = Set initial mode to high power mode (HPM), also referred - to as NPM. HPM consumes more ground current than LPM, but - it can source significantly higher load current. HPM is not - available on boost type regulators. For voltage switch type - regulators, HPM implies that over current protection and - soft start are active all the time. - - 0 = Set initial mode to low power mode (LPM). - -- qcom,ocp-max-retries: - Usage: optional - Value type: <u32> - Description: Maximum number of times to try toggling a voltage switch - off and back on as a result of consecutive over current - events. - -- qcom,ocp-retry-delay: - Usage: optional - Value type: <u32> - Description: Time to delay in milliseconds between each voltage switch - toggle after an over current event takes place. - -- qcom,pin-ctrl-enable: - Usage: optional - Value type: <u32> - Description: Bit mask specifying which hardware pins should be used to - enable the regulator, if any; supported bits are: - 0 = ignore all hardware enable signals - BIT(0) = follow HW0_EN signal - BIT(1) = follow HW1_EN signal - BIT(2) = follow HW2_EN signal - BIT(3) = follow HW3_EN signal - -- qcom,pin-ctrl-hpm: - Usage: optional - Value type: <u32> - Description: Bit mask specifying which hardware pins should be used to - force the regulator into high power mode, if any; - supported bits are: - 0 = ignore all hardware enable signals - BIT(0) = follow HW0_EN signal - BIT(1) = follow HW1_EN signal - BIT(2) = follow HW2_EN signal - BIT(3) = follow HW3_EN signal - BIT(4) = follow PMIC awake state - -- qcom,vs-soft-start-strength: - Usage: optional - Value type: <u32> - Description: This property sets the soft start strength for voltage - switch type regulators; supported values are: - 0 = 0.05 uA - 1 = 0.25 uA - 2 = 0.55 uA - 3 = 0.75 uA - -- qcom,saw-slave: - Usage: optional - Value type: <boo> - Description: SAW controlled gang slave. Will not be configured. - -- qcom,saw-leader: - Usage: optional - Value type: <boo> - Description: SAW controlled gang leader. Will be configured as - SAW regulator. - -Example: - - regulators { - compatible = "qcom,pm8941-regulators"; - vdd_l1_l3-supply = <&s1>; - - s1: s1 { - regulator-min-microvolt = <1300000>; - regulator-max-microvolt = <1400000>; - }; - - ... - - l1: l1 { - regulator-min-microvolt = <1225000>; - regulator-max-microvolt = <1300000>; - }; - - .... - }; - -Example 2: - - saw3: syscon@9A10000 { - compatible = "syscon"; - reg = <0x9A10000 0x1000>; - }; - - ... - - spm-regulators { - compatible = "qcom,pm8994-regulators"; - qcom,saw-reg = <&saw3>; - s8 { - qcom,saw-slave; - }; - s9 { - qcom,saw-slave; - }; - s10 { - qcom,saw-slave; - }; - pm8994_s11_saw: s11 { - qcom,saw-leader; - regulator-always-on; - regulator-min-microvolt = <900000>; - regulator-max-microvolt = <1140000>; - }; - }; diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml new file mode 100644 index 000000000000..8b7c4af4b551 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml @@ -0,0 +1,323 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/qcom,spmi-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SPMI Regulators + +maintainers: + - Robert Marko <robimarko@gmail.com> + +properties: + compatible: + enum: + - qcom,pm660-regulators + - qcom,pm660l-regulators + - qcom,pm8004-regulators + - qcom,pm8005-regulators + - qcom,pm8226-regulators + - qcom,pm8841-regulators + - qcom,pm8916-regulators + - qcom,pm8941-regulators + - qcom,pm8950-regulators + - qcom,pm8994-regulators + - qcom,pmi8994-regulators + - qcom,pmp8074-regulators + - qcom,pms405-regulators + + qcom,saw-reg: + description: Reference to syscon node defining the SAW registers + $ref: /schemas/types.yaml#/definitions/phandle + +patternProperties: + "^(5vs[1-2]|(l|s)[1-9][0-9]?|lvs[1-3])$": + description: List of regulators and its properties + type: object + $ref: regulator.yaml# + + properties: + qcom,ocp-max-retries: + description: + Maximum number of times to try toggling a voltage switch off and + back on as a result of consecutive over current events + $ref: /schemas/types.yaml#/definitions/uint32 + + qcom,ocp-retry-delay: + description: + Time to delay in milliseconds between each voltage switch toggle + after an over current event takes place + $ref: /schemas/types.yaml#/definitions/uint32 + + qcom,pin-ctrl-enable: + description: + Bit mask specifying which hardware pins should be used to enable the + regulator, if any. + Supported bits are + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 15 + + qcom,pin-ctrl-hpm: + description: + Bit mask specifying which hardware pins should be used to force the + regulator into high power mode, if any. + Supported bits are + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + BIT(4) = follow PMIC awake state + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 31 + + qcom,vs-soft-start-strength: + description: + This property sets the soft start strength for voltage switch type + regulators. + Supported values are + 0 = 0.05 uA + 1 = 0.25 uA + 2 = 0.55 uA + 3 = 0.75 uA + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 3 + + qcom,saw-slave: + description: SAW controlled gang slave. Will not be configured. + type: boolean + + qcom,saw-leader: + description: + SAW controlled gang leader. Will be configured as SAW regulator. + type: boolean + + unevaluatedProperties: false + +required: + - compatible + +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,pm660-regulators + then: + properties: + vdd_l15_l16_l17_l18_l19-supply: true + vdd_l1_l6_l7-supply: true + vdd_l2_l3-supply: true + vdd_l5-supply: true + vdd_l8_l9_l10_l11_l12_l13_l14-supply: true + patternProperties: + "^vdd_s[1-6]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm660l-regulators + then: + properties: + vdd_l1_l9_l10-supply: true + vdd_l2-supply: true + vdd_l3_l5_l7_l8-supply: true + vdd_l4_l6-supply: true + patternProperties: + "^vdd_s[1-5]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8004-regulators + then: + patternProperties: + "^vdd_s[25]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8005-regulators + then: + patternProperties: + "^vdd_s[1-4]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8226-regulators + then: + properties: + vdd_l10_l11_l13-supply: true + vdd_l12_l14-supply: true + vdd_l15_l16_l17_l18-supply: true + vdd_l19_l20_l21_l22_l23_l28-supply: true + vdd_l1_l2_l4_l5-supply: true + vdd_l25-supply: true + vdd_l3_l24_l26-supply: true + vdd_l6_l7_l8_l9_l27-supply: true + vdd_lvs1-supply: true + patternProperties: + "^vdd_s[1-5]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8841-regulators + then: + patternProperties: + "^vdd_s[1-8]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8916-regulators + then: + properties: + vdd_l1_l3-supply: true + vdd_l4_l5_l6-supply: true + vdd_l8_l11_l14_l15_l16-supply: true + vdd_l9_l10_l12_l13_l17_l18-supply: true + patternProperties: + "^vdd_l[27]-supply$": true + "^vdd_s[1-4]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8941-regulators + then: + properties: + interrupts: + items: + - description: Over-current protection interrupt for 5V S1 + - description: Over-current protection interrupt for 5V S2 + interrupt-names: + items: + - const: ocp-5vs1 + - const: ocp-5vs2 + vdd_l13_l20_l23_l24-supply: true + vdd_l1_l3-supply: true + vdd_l21-supply: true + vdd_l2_lvs_1_2_3-supply: true + vdd_l4_l11-supply: true + vdd_l5_l7-supply: true + vdd_l6_l12_l14_l15-supply: true + vdd_l8_l16_l18_19-supply: true + vdd_l9_l10_l17_l22-supply: true + vin_5vs-supply: true + patternProperties: + "^vdd_s[1-3]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8950-regulators + then: + properties: + vdd_l1_l19-supply: true + vdd_l20-supply: true + vdd_l21-supply: true + vdd_l2_l23-supply: true + vdd_l3-supply: true + vdd_l4_l5_l6_l7_l16-supply: true + vdd_l8_l11_l12_l17_l22-supply: true + vdd_l9_l10_l13_l14_l15_l18-supply: true + patternProperties: + "^vdd_s[1-6]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8994-regulators + then: + properties: + vdd_l1-supply: true + vdd_l13_l19_l23_l24-supply: true + vdd_l14_l15-supply: true + vdd_l17_l29-supply: true + vdd_l20_l21-supply: true + vdd_l25-supply: true + vdd_l2_l26_l28-supply: true + vdd_l3_l11-supply: true + vdd_l4_l27_l31-supply: true + vdd_l5_l7-supply: true + vdd_l6_l12_l32-supply: true + vdd_l8_l16_l30-supply: true + vdd_l9_l10_l18_l22-supply: true + vdd_lvs_1_2-supply: true + patternProperties: + "^vdd_s[1-9][0-2]?-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pmi8994-regulators + then: + properties: + vdd_l1-supply: true + patternProperties: + "^vdd_s[1-3]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pmp8074-regulators + then: + properties: + vdd_l10_l11_l12_l13-supply: true + vdd_l1_l2-supply: true + vdd_l3_l8-supply: true + vdd_l5_l6_l15-supply: true + patternProperties: + "^vdd_l[479]-supply$": true + "^vdd_s[1-5]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pms405-regulators + then: + properties: + vdd_s3-supply: true + +unevaluatedProperties: false + +examples: + - | + regulators { + compatible = "qcom,pm8941-regulators"; + vdd_l1_l3-supply = <&s1>; + + s1: s1 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1400000>; + }; + + l1: l1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1300000>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml index a9b66ececccf..6e8aa9eed3aa 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -23,6 +23,7 @@ properties: regulator-microvolt-offset: description: Offset applied to voltages to compensate for voltage drops + $ref: "/schemas/types.yaml#/definitions/uint32" regulator-min-microamp: description: smallest current consumers may set diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index cbe0f96ca342..23e3e4a35cc9 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -546,6 +546,16 @@ config REGULATOR_MAX1586 regulator via I2C bus. The provided regulator is suitable for PXA27x chips to control VCC_CORE and VCC_USIM voltages. +config REGULATOR_MAX597X + tristate "Maxim 597x power switch and monitor" + depends on I2C + depends on OF + depends on MFD_MAX597X + help + This driver controls a Maxim 5970/5978 switch via I2C bus. + The MAX5970/5978 is a smart switch with no output regulation, but + fault protection and voltage and current monitoring capabilities. + config REGULATOR_MAX77620 tristate "Maxim 77620/MAX20024 voltage regulator" depends on MFD_MAX77620 || COMPILE_TEST @@ -804,6 +814,14 @@ config REGULATOR_MT6360 2-channel buck with Thermal Shutdown and Overload Protection 6-channel High PSRR and Low Dropout LDO. +config REGULATOR_MT6370 + tristate "MT6370 SubPMIC Regulator" + depends on MFD_MT6370 + help + Say Y here to enable MT6370 regulator support. + This driver supports the control for DisplayBias voltages and one + general purpose LDO which is commonly used to drive the vibrator. + config REGULATOR_MT6380 tristate "MediaTek MT6380 PMIC" depends on MTK_PMIC_WRAP @@ -1047,6 +1065,16 @@ config REGULATOR_RT5033 RT5033 PMIC. The device supports multiple regulators like current source, LDO and Buck. +config REGULATOR_RT5120 + tristate "Richtek RT5120 PMIC Regulators" + depends on MFD_RT5120 + help + This adds support for voltage regulator in Richtek RT5120 PMIC. + It integrates 4 channels buck controller, 1 channel LDO, 1 EXTEN + to control external power source. Only BUCK1 is adjustable from + 600mV to 1395mV, per step 6.250mV. The others are all fixed voltage + by external hardware circuit. + config REGULATOR_RT5190A tristate "Richtek RT5190A PMIC" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 8d3ee8b6d41d..fa49bb6cc544 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o obj-$(CONFIG_REGULATOR_LTC3676) += ltc3676.o obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o +obj-$(CONFIG_REGULATOR_MAX597X) += max597x-regulator.o obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o obj-$(CONFIG_REGULATOR_MAX77650) += max77650-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o @@ -97,6 +98,7 @@ obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o +obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o @@ -126,6 +128,7 @@ 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_RT5120) += rt5120-regulator.o obj-$(CONFIG_REGULATOR_RT5190A) += rt5190a-regulator.o obj-$(CONFIG_REGULATOR_RT5759) += rt5759-regulator.o obj-$(CONFIG_REGULATOR_RT6160) += rt6160-regulator.o diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 1e54a833f2cf..7150b1d0159e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1565,6 +1565,9 @@ static int set_machine_constraints(struct regulator_dev *rdev) rdev->constraints->always_on = true; } + if (rdev->desc->off_on_delay) + rdev->last_off = ktime_get(); + /* If the constraints say the regulator should be on at this point * and we have control then make sure it is enabled. */ @@ -1592,8 +1595,6 @@ static int set_machine_constraints(struct regulator_dev *rdev) if (rdev->constraints->always_on) rdev->use_count++; - } else if (rdev->desc->off_on_delay) { - rdev->last_off = ktime_get(); } print_constraints(rdev); @@ -4783,22 +4784,26 @@ int regulator_bulk_get(struct device *dev, int num_consumers, consumers[i].consumer = regulator_get(dev, consumers[i].supply); if (IS_ERR(consumers[i].consumer)) { - ret = PTR_ERR(consumers[i].consumer); consumers[i].consumer = NULL; + ret = dev_err_probe(dev, PTR_ERR(consumers[i].consumer), + "Failed to get supply '%s'", + consumers[i].supply); goto err; } + + if (consumers[i].init_load_uA > 0) { + ret = regulator_set_load(consumers[i].consumer, + consumers[i].init_load_uA); + if (ret) { + i++; + goto err; + } + } } return 0; err: - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get supply '%s': %pe\n", - consumers[i].supply, ERR_PTR(ret)); - else - dev_dbg(dev, "Failed to get supply '%s', deferring\n", - consumers[i].supply); - while (--i >= 0) regulator_put(consumers[i].consumer); diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index 9113233f41cd..32823a87fd40 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c @@ -166,6 +166,34 @@ int devm_regulator_bulk_get(struct device *dev, int num_consumers, } EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); +/** + * devm_regulator_bulk_get_const - devm_regulator_bulk_get() w/ const data + * + * @dev: device to supply + * @num_consumers: number of consumers to register + * @in_consumers: const configuration of consumers + * @out_consumers: in_consumers is copied here and this is passed to + * devm_regulator_bulk_get(). + * + * 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. + */ +int devm_regulator_bulk_get_const(struct device *dev, int num_consumers, + const struct regulator_bulk_data *in_consumers, + struct regulator_bulk_data **out_consumers) +{ + *out_consumers = devm_kmemdup(dev, in_consumers, + num_consumers * sizeof(*in_consumers), + GFP_KERNEL); + if (*out_consumers == NULL) + return -ENOMEM; + + return devm_regulator_bulk_get(dev, num_consumers, *out_consumers); +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_get_const); + static void devm_rdev_release(struct device *dev, void *res) { regulator_unregister(*(struct regulator_dev **)res); diff --git a/drivers/regulator/max597x-regulator.c b/drivers/regulator/max597x-regulator.c new file mode 100644 index 000000000000..03c6027682d8 --- /dev/null +++ b/drivers/regulator/max597x-regulator.c @@ -0,0 +1,502 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device driver for regulators in MAX5970 and MAX5978 IC + * + * Copyright (c) 2022 9elements GmbH + * + * Author: Patrick Rudolph <patrick.rudolph@9elements.com> + */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/platform_device.h> + +#include <linux/mfd/max597x.h> + +struct max597x_regulator { + int num_switches, mon_rng, irng, shunt_micro_ohms, lim_uA; + struct regmap *regmap; +}; + +enum max597x_regulator_id { + MAX597X_SW0, + MAX597X_SW1, +}; + +static int max597x_uvp_ovp_check_mode(struct regulator_dev *rdev, int severity) +{ + int ret, reg; + + /* Status1 register contains the soft strap values sampled at POR */ + ret = regmap_read(rdev->regmap, MAX5970_REG_STATUS1, ®); + if (ret) + return ret; + + /* Check soft straps match requested mode */ + if (severity == REGULATOR_SEVERITY_PROT) { + if (STATUS1_PROT(reg) != STATUS1_PROT_SHUTDOWN) + return -EOPNOTSUPP; + + return 0; + } + if (STATUS1_PROT(reg) == STATUS1_PROT_SHUTDOWN) + return -EOPNOTSUPP; + + return 0; +} + +static int max597x_set_vp(struct regulator_dev *rdev, int lim_uV, int severity, + bool enable, bool overvoltage) +{ + int off_h, off_l, reg, ret; + struct max597x_regulator *data = rdev_get_drvdata(rdev); + int channel = rdev_get_id(rdev); + + if (overvoltage) { + if (severity == REGULATOR_SEVERITY_WARN) { + off_h = MAX5970_REG_CH_OV_WARN_H(channel); + off_l = MAX5970_REG_CH_OV_WARN_L(channel); + } else { + off_h = MAX5970_REG_CH_OV_CRIT_H(channel); + off_l = MAX5970_REG_CH_OV_CRIT_L(channel); + } + } else { + if (severity == REGULATOR_SEVERITY_WARN) { + off_h = MAX5970_REG_CH_UV_WARN_H(channel); + off_l = MAX5970_REG_CH_UV_WARN_L(channel); + } else { + off_h = MAX5970_REG_CH_UV_CRIT_H(channel); + off_l = MAX5970_REG_CH_UV_CRIT_L(channel); + } + } + + if (enable) + /* reg = ADC_MASK * (lim_uV / 1000000) / (data->mon_rng / 1000000) */ + reg = ADC_MASK * lim_uV / data->mon_rng; + else + reg = 0; + + ret = regmap_write(rdev->regmap, off_h, MAX5970_VAL2REG_H(reg)); + if (ret) + return ret; + + ret = regmap_write(rdev->regmap, off_l, MAX5970_VAL2REG_L(reg)); + if (ret) + return ret; + + return 0; +} + +static int max597x_set_uvp(struct regulator_dev *rdev, int lim_uV, int severity, + bool enable) +{ + int ret; + + /* + * MAX5970 has enable control as a special value in limit reg. Can't + * set limit but keep feature disabled or enable W/O given limit. + */ + if ((lim_uV && !enable) || (!lim_uV && enable)) + return -EINVAL; + + ret = max597x_uvp_ovp_check_mode(rdev, severity); + if (ret) + return ret; + + return max597x_set_vp(rdev, lim_uV, severity, enable, false); +} + +static int max597x_set_ovp(struct regulator_dev *rdev, int lim_uV, int severity, + bool enable) +{ + int ret; + + /* + * MAX5970 has enable control as a special value in limit reg. Can't + * set limit but keep feature disabled or enable W/O given limit. + */ + if ((lim_uV && !enable) || (!lim_uV && enable)) + return -EINVAL; + + ret = max597x_uvp_ovp_check_mode(rdev, severity); + if (ret) + return ret; + + return max597x_set_vp(rdev, lim_uV, severity, enable, true); +} + +static int max597x_set_ocp(struct regulator_dev *rdev, int lim_uA, + int severity, bool enable) +{ + int ret, val, reg; + unsigned int vthst, vthfst; + + struct max597x_regulator *data = rdev_get_drvdata(rdev); + int rdev_id = rdev_get_id(rdev); + /* + * MAX5970 doesn't has enable control for ocp. + * If limit is specified but enable is not set then hold the value in + * variable & later use it when ocp needs to be enabled. + */ + if (lim_uA != 0 && lim_uA != data->lim_uA) + data->lim_uA = lim_uA; + + if (severity != REGULATOR_SEVERITY_PROT) + return -EINVAL; + + if (enable) { + + /* Calc Vtrip threshold in uV. */ + vthst = + div_u64(mul_u32_u32(data->shunt_micro_ohms, data->lim_uA), + 1000000); + + /* + * As recommended in datasheed, add 20% margin to avoid + * spurious event & passive component tolerance. + */ + vthst = div_u64(mul_u32_u32(vthst, 120), 100); + + /* Calc fast Vtrip threshold in uV */ + vthfst = vthst * (MAX5970_FAST2SLOW_RATIO / 100); + + if (vthfst > data->irng) { + dev_err(&rdev->dev, "Current limit out of range\n"); + return -EINVAL; + } + /* Fast trip threshold to be programmed */ + val = div_u64(mul_u32_u32(0xFF, vthfst), data->irng); + } else + /* + * Since there is no option to disable ocp, set limit to max + * value + */ + val = 0xFF; + + reg = MAX5970_REG_DAC_FAST(rdev_id); + ret = regmap_write(rdev->regmap, reg, val); + + return ret; +} + +static int max597x_get_status(struct regulator_dev *rdev) +{ + int val, ret; + + ret = regmap_read(rdev->regmap, MAX5970_REG_STATUS3, &val); + if (ret) + return REGULATOR_FAILED_RETRY; + + if (val & MAX5970_STATUS3_ALERT) + return REGULATOR_STATUS_ERROR; + + ret = regulator_is_enabled_regmap(rdev); + if (ret < 0) + return ret; + + if (ret) + return REGULATOR_STATUS_ON; + + return REGULATOR_STATUS_OFF; +} + +static const struct regulator_ops max597x_switch_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = max597x_get_status, + .set_over_voltage_protection = max597x_set_ovp, + .set_under_voltage_protection = max597x_set_uvp, + .set_over_current_protection = max597x_set_ocp, +}; + +static int max597x_dt_parse(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *cfg) +{ + struct max597x_regulator *data = cfg->driver_data; + int ret = 0; + + ret = + of_property_read_u32(np, "shunt-resistor-micro-ohms", + &data->shunt_micro_ohms); + if (ret < 0) + dev_err(cfg->dev, + "property 'shunt-resistor-micro-ohms' not found, err %d\n", + ret); + return ret; + +} + +#define MAX597X_SWITCH(_ID, _ereg, _chan, _supply) { \ + .name = #_ID, \ + .of_match = of_match_ptr(#_ID), \ + .ops = &max597x_switch_ops, \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .id = MAX597X_##_ID, \ + .owner = THIS_MODULE, \ + .supply_name = _supply, \ + .enable_reg = _ereg, \ + .enable_mask = CHXEN((_chan)), \ + .of_parse_cb = max597x_dt_parse, \ +} + +static const struct regulator_desc regulators[] = { + MAX597X_SWITCH(SW0, MAX5970_REG_CHXEN, 0, "vss1"), + MAX597X_SWITCH(SW1, MAX5970_REG_CHXEN, 1, "vss2"), +}; + +static int max597x_regmap_read_clear(struct regmap *map, unsigned int reg, + unsigned int *val) +{ + int ret; + + ret = regmap_read(map, reg, val); + if (ret) + return ret; + + if (*val) + return regmap_write(map, reg, *val); + + return 0; +} + +static int max597x_irq_handler(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + struct regulator_err_state *stat; + struct max597x_regulator *d = (struct max597x_regulator *)rid->data; + int val, ret, i; + + ret = max597x_regmap_read_clear(d->regmap, MAX5970_REG_FAULT0, &val); + if (ret) + return REGULATOR_FAILED_RETRY; + + *dev_mask = 0; + for (i = 0; i < d->num_switches; i++) { + stat = &rid->states[i]; + stat->notifs = 0; + stat->errors = 0; + } + + for (i = 0; i < d->num_switches; i++) { + stat = &rid->states[i]; + + if (val & UV_STATUS_CRIT(i)) { + *dev_mask |= 1 << i; + stat->notifs |= REGULATOR_EVENT_UNDER_VOLTAGE; + stat->errors |= REGULATOR_ERROR_UNDER_VOLTAGE; + } else if (val & UV_STATUS_WARN(i)) { + *dev_mask |= 1 << i; + stat->notifs |= REGULATOR_EVENT_UNDER_VOLTAGE_WARN; + stat->errors |= REGULATOR_ERROR_UNDER_VOLTAGE_WARN; + } + } + + ret = max597x_regmap_read_clear(d->regmap, MAX5970_REG_FAULT1, &val); + if (ret) + return REGULATOR_FAILED_RETRY; + + for (i = 0; i < d->num_switches; i++) { + stat = &rid->states[i]; + + if (val & OV_STATUS_CRIT(i)) { + *dev_mask |= 1 << i; + stat->notifs |= REGULATOR_EVENT_REGULATION_OUT; + stat->errors |= REGULATOR_ERROR_REGULATION_OUT; + } else if (val & OV_STATUS_WARN(i)) { + *dev_mask |= 1 << i; + stat->notifs |= REGULATOR_EVENT_OVER_VOLTAGE_WARN; + stat->errors |= REGULATOR_ERROR_OVER_VOLTAGE_WARN; + } + } + + ret = max597x_regmap_read_clear(d->regmap, MAX5970_REG_FAULT2, &val); + if (ret) + return REGULATOR_FAILED_RETRY; + + for (i = 0; i < d->num_switches; i++) { + stat = &rid->states[i]; + + if (val & OC_STATUS_WARN(i)) { + *dev_mask |= 1 << i; + stat->notifs |= REGULATOR_EVENT_OVER_CURRENT_WARN; + stat->errors |= REGULATOR_ERROR_OVER_CURRENT_WARN; + } + } + + ret = regmap_read(d->regmap, MAX5970_REG_STATUS0, &val); + if (ret) + return REGULATOR_FAILED_RETRY; + + for (i = 0; i < d->num_switches; i++) { + stat = &rid->states[i]; + + if ((val & MAX5970_CB_IFAULTF(i)) + || (val & MAX5970_CB_IFAULTS(i))) { + *dev_mask |= 1 << i; + stat->notifs |= + REGULATOR_EVENT_OVER_CURRENT | + REGULATOR_EVENT_DISABLE; + stat->errors |= + REGULATOR_ERROR_OVER_CURRENT | REGULATOR_ERROR_FAIL; + + /* Clear the sub-IRQ status */ + regulator_disable_regmap(stat->rdev); + } + } + return 0; +} + +static const struct regmap_config max597x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX_REGISTERS, +}; + +static int max597x_adc_range(struct regmap *regmap, const int ch, + u32 *irng, u32 *mon_rng) +{ + unsigned int reg; + int ret; + + /* Decode current ADC range */ + ret = regmap_read(regmap, MAX5970_REG_STATUS2, ®); + if (ret) + return ret; + switch (MAX5970_IRNG(reg, ch)) { + case 0: + *irng = 100000; /* 100 mV */ + break; + case 1: + *irng = 50000; /* 50 mV */ + break; + case 2: + *irng = 25000; /* 25 mV */ + break; + default: + return -EINVAL; + } + + /* Decode current voltage monitor range */ + ret = regmap_read(regmap, MAX5970_REG_MON_RANGE, ®); + if (ret) + return ret; + + *mon_rng = MAX5970_MON_MAX_RANGE_UV >> MAX5970_MON(reg, ch); + + return 0; +} + +static int max597x_setup_irq(struct device *dev, + int irq, + struct regulator_dev *rdevs[MAX5970_NUM_SWITCHES], + int num_switches, struct max597x_regulator *data) +{ + struct regulator_irq_desc max597x_notif = { + .name = "max597x-irq", + .map_event = max597x_irq_handler, + .data = data, + }; + int errs = REGULATOR_ERROR_UNDER_VOLTAGE | + REGULATOR_ERROR_UNDER_VOLTAGE_WARN | + REGULATOR_ERROR_OVER_VOLTAGE_WARN | + REGULATOR_ERROR_REGULATION_OUT | + REGULATOR_ERROR_OVER_CURRENT | + REGULATOR_ERROR_OVER_CURRENT_WARN | REGULATOR_ERROR_FAIL; + void *irq_helper; + + /* Register notifiers - can fail if IRQ is not given */ + irq_helper = devm_regulator_irq_helper(dev, &max597x_notif, + irq, 0, errs, NULL, + &rdevs[0], num_switches); + if (IS_ERR(irq_helper)) { + if (PTR_ERR(irq_helper) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(dev, "IRQ disabled %pe\n", irq_helper); + } + + return 0; +} + +static int max597x_regulator_probe(struct platform_device *pdev) +{ + + + struct max597x_data *max597x = dev_get_drvdata(pdev->dev.parent); + struct max597x_regulator *data; + + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct regulator_dev *rdevs[MAX5970_NUM_SWITCHES]; + int num_switches = max597x->num_switches; + int ret, i; + + for (i = 0; i < num_switches; i++) { + data = + devm_kzalloc(max597x->dev, sizeof(struct max597x_regulator), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->num_switches = num_switches; + data->regmap = max597x->regmap; + + ret = max597x_adc_range(data->regmap, i, &max597x->irng[i], &max597x->mon_rng[i]); + if (ret < 0) + return ret; + + data->irng = max597x->irng[i]; + data->mon_rng = max597x->mon_rng[i]; + + config.dev = max597x->dev; + config.driver_data = (void *)data; + config.regmap = data->regmap; + rdev = devm_regulator_register(max597x->dev, + ®ulators[i], &config); + if (IS_ERR(rdev)) { + dev_err(max597x->dev, "failed to register regulator %s\n", + regulators[i].name); + return PTR_ERR(rdev); + } + rdevs[i] = rdev; + max597x->shunt_micro_ohms[i] = data->shunt_micro_ohms; + } + + if (max597x->irq) { + ret = + max597x_setup_irq(max597x->dev, max597x->irq, rdevs, num_switches, + data); + if (ret) { + dev_err(max597x->dev, "IRQ setup failed"); + return ret; + } + } + + return ret; +} + +static struct platform_driver max597x_regulator_driver = { + .driver = { + .name = "max597x-regulator", + }, + .probe = max597x_regulator_probe, +}; + +module_platform_driver(max597x_regulator_driver); + + +MODULE_AUTHOR("Patrick Rudolph <patrick.rudolph@9elements.com>"); +MODULE_DESCRIPTION("MAX5970_hot-swap controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/mp5416.c b/drivers/regulator/mp5416.c index 39cebec0edb6..82892d71c2c9 100644 --- a/drivers/regulator/mp5416.c +++ b/drivers/regulator/mp5416.c @@ -6,14 +6,14 @@ // // Author: Saravanan Sekar <sravanhome@gmail.com> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> #include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/regulator/driver.h> -#include <linux/i2c.h> #define MP5416_REG_CTL0 0x00 #define MP5416_REG_CTL1 0x01 @@ -174,10 +174,22 @@ 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] = { + 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), + MP5416BUCK("buck4", 4, mp5416_I_limits2, MP5416_REG_CTL2, BIT(5), 1), + MP5416LDO("ldo1", 1, BIT(4)), + MP5416LDO("ldo2", 2, BIT(3)), + MP5416LDO("ldo3", 3, BIT(2)), + MP5416LDO("ldo4", 4, BIT(1)), +}; + static int mp5416_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct regulator_config config = { NULL, }; + static const struct regulator_desc *desc; struct regulator_dev *rdev; struct regmap *regmap; int i; @@ -188,12 +200,16 @@ static int mp5416_i2c_probe(struct i2c_client *client) return PTR_ERR(regmap); } + desc = of_device_get_match_data(dev); + if (!desc) + return -ENODEV; + config.dev = dev; config.regmap = regmap; for (i = 0; i < MP5416_MAX_REGULATORS; i++) { rdev = devm_regulator_register(dev, - &mp5416_regulators_desc[i], + &desc[i], &config); if (IS_ERR(rdev)) { dev_err(dev, "Failed to register regulator!\n"); @@ -205,13 +221,15 @@ static int mp5416_i2c_probe(struct i2c_client *client) } static const struct of_device_id mp5416_of_match[] = { - { .compatible = "mps,mp5416" }, + { .compatible = "mps,mp5416", .data = &mp5416_regulators_desc }, + { .compatible = "mps,mp5496", .data = &mp5496_regulators_desc }, {}, }; MODULE_DEVICE_TABLE(of, mp5416_of_match); static const struct i2c_device_id mp5416_id[] = { { "mp5416", }, + { "mp5496", }, { }, }; MODULE_DEVICE_TABLE(i2c, mp5416_id); diff --git a/drivers/regulator/mt6370-regulator.c b/drivers/regulator/mt6370-regulator.c new file mode 100644 index 000000000000..e73f5a46cb9a --- /dev/null +++ b/drivers/regulator/mt6370-regulator.c @@ -0,0 +1,390 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <linux/bits.h> +#include <linux/gpio/consumer.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +enum { + MT6370_IDX_DSVBOOST = 0, + MT6370_IDX_DSVPOS, + MT6370_IDX_DSVNEG, + MT6370_IDX_VIBLDO, + MT6370_MAX_IDX +}; + +#define MT6370_REG_LDO_CFG 0x180 +#define MT6370_REG_LDO_VOUT 0x181 +#define MT6370_REG_DB_CTRL1 0x1B0 +#define MT6370_REG_DB_CTRL2 0x1B1 +#define MT6370_REG_DB_VBST 0x1B2 +#define MT6370_REG_DB_VPOS 0x1B3 +#define MT6370_REG_DB_VNEG 0x1B4 +#define MT6370_REG_LDO_STAT 0x1DC +#define MT6370_REG_DB_STAT 0x1DF + +#define MT6370_LDOOMS_MASK BIT(7) +#define MT6370_LDOEN_MASK BIT(7) +#define MT6370_LDOVOUT_MASK GENMASK(3, 0) +#define MT6370_DBPERD_MASK (BIT(7) | BIT(4)) +#define MT6370_DBEXTEN_MASK BIT(0) +#define MT6370_DBVPOSEN_MASK BIT(6) +#define MT6370_DBVPOSDISG_MASK BIT(5) +#define MT6370_DBVNEGEN_MASK BIT(3) +#define MT6370_DBVNEGDISG_MASK BIT(2) +#define MT6370_DBALLON_MASK (MT6370_DBVPOSEN_MASK | MT6370_DBVNEGEN_MASK) +#define MT6370_DBSLEW_MASK GENMASK(7, 6) +#define MT6370_DBVOUT_MASK GENMASK(5, 0) +#define MT6370_LDOOC_EVT_MASK BIT(7) +#define MT6370_POSSCP_EVT_MASK BIT(7) +#define MT6370_NEGSCP_EVT_MASK BIT(6) +#define MT6370_BSTOCP_EVT_MASK BIT(5) +#define MT6370_POSOCP_EVT_MASK BIT(4) +#define MT6370_NEGOCP_EVT_MASK BIT(3) + +#define MT6370_LDO_MINUV 1600000 +#define MT6370_LDO_STPUV 200000 +#define MT6370_LDO_N_VOLT 13 +#define MT6370_DBVBOOST_MINUV 4000000 +#define MT6370_DBVBOOST_STPUV 50000 +#define MT6370_DBVBOOST_N_VOLT 45 +#define MT6370_DBVOUT_MINUV 4000000 +#define MT6370_DBVOUT_STPUV 50000 +#define MT6370_DBVOUT_N_VOLT 41 + +struct mt6370_priv { + struct device *dev; + struct regmap *regmap; + struct regulator_dev *rdev[MT6370_MAX_IDX]; + bool use_external_ctrl; +}; + +static const unsigned int mt6370_vpos_ramp_tbl[] = { 8540, 5840, 4830, 3000 }; +static const unsigned int mt6370_vneg_ramp_tbl[] = { 10090, 6310, 5050, 3150 }; + +static int mt6370_get_error_flags(struct regulator_dev *rdev, + unsigned int *flags) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int stat_reg, stat, rpt_flags = 0; + int rid = rdev_get_id(rdev), ret; + + if (rid == MT6370_IDX_VIBLDO) + stat_reg = MT6370_REG_LDO_STAT; + else + stat_reg = MT6370_REG_DB_STAT; + + ret = regmap_read(regmap, stat_reg, &stat); + if (ret) + return ret; + + switch (rid) { + case MT6370_IDX_DSVBOOST: + if (stat & MT6370_BSTOCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + case MT6370_IDX_DSVPOS: + if (stat & MT6370_POSSCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE; + + if (stat & MT6370_POSOCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + case MT6370_IDX_DSVNEG: + if (stat & MT6370_NEGSCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_UNDER_VOLTAGE; + + if (stat & MT6370_NEGOCP_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + default: + if (stat & MT6370_LDOOC_EVT_MASK) + rpt_flags |= REGULATOR_ERROR_OVER_CURRENT; + break; + } + + *flags = rpt_flags; + return 0; +} + +static const struct regulator_ops mt6370_dbvboost_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_bypass = regulator_get_bypass_regmap, + .set_bypass = regulator_set_bypass_regmap, + .get_error_flags = mt6370_get_error_flags, +}; + +static const struct regulator_ops mt6370_dbvout_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .get_error_flags = mt6370_get_error_flags, +}; + +static const struct regulator_ops mt6370_ldo_ops = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .get_error_flags = mt6370_get_error_flags, +}; + +static int mt6370_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct mt6370_priv *priv = config->driver_data; + struct gpio_desc *enable_gpio; + int ret; + + enable_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np), "enable", 0, + GPIOD_OUT_HIGH | + GPIOD_FLAGS_BIT_NONEXCLUSIVE, + desc->name); + if (IS_ERR(enable_gpio)) { + config->ena_gpiod = NULL; + return 0; + } + + /* + * RG control by default + * Only if all are using external pin, change all by external control + */ + if (priv->use_external_ctrl) { + ret = regmap_update_bits(priv->regmap, MT6370_REG_DB_CTRL1, + MT6370_DBEXTEN_MASK, + MT6370_DBEXTEN_MASK); + if (ret) + return ret; + } + + config->ena_gpiod = enable_gpio; + priv->use_external_ctrl = true; + return 0; +} + +static const struct regulator_desc mt6370_regulator_descs[] = { + { + .name = "mt6370-dsv-vbst", + .of_match = of_match_ptr("dsvbst"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_DSVBOOST, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &mt6370_dbvboost_ops, + .min_uV = MT6370_DBVBOOST_MINUV, + .uV_step = MT6370_DBVBOOST_STPUV, + .n_voltages = MT6370_DBVBOOST_N_VOLT, + .vsel_reg = MT6370_REG_DB_VBST, + .vsel_mask = MT6370_DBVOUT_MASK, + .bypass_reg = MT6370_REG_DB_CTRL1, + .bypass_mask = MT6370_DBPERD_MASK, + .bypass_val_on = MT6370_DBPERD_MASK, + }, + { + .name = "mt6370-dsv-vpos", + .of_match = of_match_ptr("dsvpos"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_DSVPOS, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .of_parse_cb = mt6370_of_parse_cb, + .ops = &mt6370_dbvout_ops, + .min_uV = MT6370_DBVOUT_MINUV, + .uV_step = MT6370_DBVOUT_STPUV, + .n_voltages = MT6370_DBVOUT_N_VOLT, + .vsel_reg = MT6370_REG_DB_VPOS, + .vsel_mask = MT6370_DBVOUT_MASK, + .enable_reg = MT6370_REG_DB_CTRL2, + .enable_mask = MT6370_DBVPOSEN_MASK, + .ramp_reg = MT6370_REG_DB_VPOS, + .ramp_mask = MT6370_DBSLEW_MASK, + .ramp_delay_table = mt6370_vpos_ramp_tbl, + .n_ramp_values = ARRAY_SIZE(mt6370_vpos_ramp_tbl), + .active_discharge_reg = MT6370_REG_DB_CTRL2, + .active_discharge_mask = MT6370_DBVPOSDISG_MASK, + .active_discharge_on = MT6370_DBVPOSDISG_MASK, + }, + { + .name = "mt6370-dsv-vneg", + .of_match = of_match_ptr("dsvneg"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_DSVNEG, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .of_parse_cb = mt6370_of_parse_cb, + .ops = &mt6370_dbvout_ops, + .min_uV = MT6370_DBVOUT_MINUV, + .uV_step = MT6370_DBVOUT_STPUV, + .n_voltages = MT6370_DBVOUT_N_VOLT, + .vsel_reg = MT6370_REG_DB_VNEG, + .vsel_mask = MT6370_DBVOUT_MASK, + .enable_reg = MT6370_REG_DB_CTRL2, + .enable_mask = MT6370_DBVNEGEN_MASK, + .ramp_reg = MT6370_REG_DB_VNEG, + .ramp_mask = MT6370_DBSLEW_MASK, + .ramp_delay_table = mt6370_vneg_ramp_tbl, + .n_ramp_values = ARRAY_SIZE(mt6370_vneg_ramp_tbl), + .active_discharge_reg = MT6370_REG_DB_CTRL2, + .active_discharge_mask = MT6370_DBVNEGDISG_MASK, + .active_discharge_on = MT6370_DBVNEGDISG_MASK, + }, + { + .name = "mt6370-vib-ldo", + .of_match = of_match_ptr("vibldo"), + .regulators_node = of_match_ptr("regulators"), + .id = MT6370_IDX_VIBLDO, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .ops = &mt6370_ldo_ops, + .min_uV = MT6370_LDO_MINUV, + .uV_step = MT6370_LDO_STPUV, + .n_voltages = MT6370_LDO_N_VOLT, + .vsel_reg = MT6370_REG_LDO_VOUT, + .vsel_mask = MT6370_LDOVOUT_MASK, + .enable_reg = MT6370_REG_LDO_VOUT, + .enable_mask = MT6370_LDOEN_MASK, + .active_discharge_reg = MT6370_REG_LDO_CFG, + .active_discharge_mask = MT6370_LDOOMS_MASK, + .active_discharge_on = MT6370_LDOOMS_MASK, + } +}; + +static irqreturn_t mt6370_scp_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE, + NULL); + return IRQ_HANDLED; +} + +static irqreturn_t mt6370_ocp_handler(int irq, void *data) +{ + struct regulator_dev *rdev = data; + + regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL); + return IRQ_HANDLED; +} + +static int mt6370_regulator_irq_register(struct mt6370_priv *priv) +{ + struct platform_device *pdev = to_platform_device(priv->dev); + static const struct { + const char *name; + int rid; + irq_handler_t handler; + } mt6370_irqs[] = { + { "db_vpos_scp", MT6370_IDX_DSVPOS, mt6370_scp_handler }, + { "db_vneg_scp", MT6370_IDX_DSVNEG, mt6370_scp_handler }, + { "db_vbst_ocp", MT6370_IDX_DSVBOOST, mt6370_ocp_handler }, + { "db_vpos_ocp", MT6370_IDX_DSVPOS, mt6370_ocp_handler }, + { "db_vneg_ocp", MT6370_IDX_DSVNEG, mt6370_ocp_handler }, + { "ldo_oc", MT6370_IDX_VIBLDO, mt6370_ocp_handler } + }; + struct regulator_dev *rdev; + int i, irq, ret; + + for (i = 0; i < ARRAY_SIZE(mt6370_irqs); i++) { + irq = platform_get_irq_byname(pdev, mt6370_irqs[i].name); + + rdev = priv->rdev[mt6370_irqs[i].rid]; + + ret = devm_request_threaded_irq(priv->dev, irq, NULL, + mt6370_irqs[i].handler, 0, + mt6370_irqs[i].name, rdev); + if (ret) { + dev_err(priv->dev, + "Failed to register (%d) interrupt\n", i); + return ret; + } + } + + return 0; +} + +static int mt6370_regualtor_register(struct mt6370_priv *priv) +{ + struct regulator_dev *rdev; + struct regulator_config cfg = {}; + struct device *parent = priv->dev->parent; + int i; + + cfg.dev = parent; + cfg.driver_data = priv; + + for (i = 0; i < MT6370_MAX_IDX; i++) { + rdev = devm_regulator_register(priv->dev, + mt6370_regulator_descs + i, + &cfg); + if (IS_ERR(rdev)) { + dev_err(priv->dev, + "Failed to register (%d) regulator\n", i); + return PTR_ERR(rdev); + } + + priv->rdev[i] = rdev; + } + + return 0; +} + +static int mt6370_regulator_probe(struct platform_device *pdev) +{ + struct mt6370_priv *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "Failed to init regmap\n"); + return -ENODEV; + } + + ret = mt6370_regualtor_register(priv); + if (ret) + return ret; + + return mt6370_regulator_irq_register(priv); +} + +static const struct platform_device_id mt6370_devid_table[] = { + { "mt6370-regulator", 0}, + {} +}; +MODULE_DEVICE_TABLE(platform, mt6370_devid_table); + +static struct platform_driver mt6370_regulator_driver = { + .driver = { + .name = "mt6370-regulator", + }, + .id_table = mt6370_devid_table, + .probe = mt6370_regulator_probe, +}; +module_platform_driver(mt6370_regulator_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Mediatek MT6370 Regulator Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/mt6380-regulator.c b/drivers/regulator/mt6380-regulator.c index 2e6b61d3b0cf..43234296df36 100644 --- a/drivers/regulator/mt6380-regulator.c +++ b/drivers/regulator/mt6380-regulator.c @@ -319,7 +319,7 @@ static const struct platform_device_id mt6380_platform_ids[] = { }; MODULE_DEVICE_TABLE(platform, mt6380_platform_ids); -static const struct of_device_id mt6380_of_match[] = { +static const struct of_device_id __maybe_unused mt6380_of_match[] = { { .compatible = "mediatek,mt6380-regulator", }, { /* sentinel */ }, }; diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index f54d4f176882..e12b681c72e5 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -264,8 +264,12 @@ static int of_get_regulation_constraints(struct device *dev, } suspend_np = of_get_child_by_name(np, regulator_states[i]); - if (!suspend_np || !suspend_state) + if (!suspend_np) continue; + if (!suspend_state) { + of_node_put(suspend_np); + continue; + } if (!of_property_read_u32(suspend_np, "regulator-mode", &pval)) { diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index ef6e47d025ca..59024c639141 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -205,6 +205,7 @@ static const struct regulator_ops rpm_mp5496_ops = { .is_enabled = rpm_reg_is_enabled, .list_voltage = regulator_list_voltage_linear_range, + .get_voltage = rpm_reg_get_voltage, .set_voltage = rpm_reg_set_voltage, }; @@ -357,10 +358,10 @@ static const struct regulator_desc pm8941_switch = { static const struct regulator_desc pm8916_pldo = { .linear_ranges = (struct linear_range[]) { - REGULATOR_LINEAR_RANGE(750000, 0, 208, 12500), + REGULATOR_LINEAR_RANGE(1750000, 0, 127, 12500), }, .n_linear_ranges = 1, - .n_voltages = 209, + .n_voltages = 128, .ops = &rpm_smps_ldo_ops, }; @@ -783,6 +784,29 @@ static const struct rpm_regulator_data rpm_pm8841_regulators[] = { {} }; +static const struct rpm_regulator_data rpm_pm8909_regulators[] = { + { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8916_buck_lvo_smps, "vdd_s1" }, + { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8916_buck_hvo_smps, "vdd_s2" }, + { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8916_nldo, "vdd_l1" }, + { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8916_nldo, "vdd_l2_l5" }, + { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8916_nldo, "vdd_l3_l6_l10" }, + { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8916_pldo, "vdd_l4_l7" }, + { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8226_pldo, "vdd_l2_l5" }, + { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8226_pldo, "vdd_l3_l6_l10" }, + { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8226_pldo, "vdd_l4_l7" }, + { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8916_pldo, "vdd_l8_l11_l15_l18" }, + { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8916_pldo, "vdd_l9_l12_l14_l17" }, + { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8916_nldo, "vdd_l3_l6_l10" }, + { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8226_pldo, "vdd_l8_l11_l15_l18" }, + { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8916_pldo, "vdd_l9_l12_l14_l17" }, + { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8916_pldo, "vdd_l13" }, + { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8916_pldo, "vdd_l9_l12_l14_l17" }, + { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8916_pldo, "vdd_l8_l11_l15_l18" }, + { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8916_pldo, "vdd_l9_l12_l14_l17" }, + { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8916_pldo, "vdd_l8_l11_l15_l18" }, + {} +}; + static const struct rpm_regulator_data rpm_pm8916_regulators[] = { { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8916_buck_lvo_smps, "vdd_s1" }, { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8916_buck_lvo_smps, "vdd_s2" }, @@ -1221,6 +1245,7 @@ static const struct rpm_regulator_data rpm_pm2250_regulators[] = { static const struct of_device_id rpm_of_match[] = { { .compatible = "qcom,rpm-mp5496-regulators", .data = &rpm_mp5496_regulators }, { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators }, + { .compatible = "qcom,rpm-pm8909-regulators", .data = &rpm_pm8909_regulators }, { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators }, { .compatible = "qcom,rpm-pm8226-regulators", .data = &rpm_pm8226_regulators }, { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators }, diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 02bfce981150..a2d0292a92fd 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -164,6 +164,8 @@ enum spmi_regulator_subtype { SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL3 = 0x0f, SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL4 = 0x10, SPMI_REGULATOR_SUBTYPE_HFS430 = 0x0a, + SPMI_REGULATOR_SUBTYPE_HT_P150 = 0x35, + SPMI_REGULATOR_SUBTYPE_HT_P600 = 0x3d, }; enum spmi_common_regulator_registers { @@ -544,6 +546,14 @@ static struct spmi_voltage_range hfs430_ranges[] = { SPMI_VOLTAGE_RANGE(0, 320000, 320000, 2040000, 2040000, 8000), }; +static struct spmi_voltage_range ht_p150_ranges[] = { + SPMI_VOLTAGE_RANGE(0, 1616000, 1616000, 3304000, 3304000, 8000), +}; + +static struct spmi_voltage_range ht_p600_ranges[] = { + SPMI_VOLTAGE_RANGE(0, 1704000, 1704000, 1896000, 1896000, 8000), +}; + static DEFINE_SPMI_SET_POINTS(pldo); static DEFINE_SPMI_SET_POINTS(nldo1); static DEFINE_SPMI_SET_POINTS(nldo2); @@ -564,6 +574,8 @@ static DEFINE_SPMI_SET_POINTS(nldo660); static DEFINE_SPMI_SET_POINTS(ht_lvpldo); static DEFINE_SPMI_SET_POINTS(ht_nldo); static DEFINE_SPMI_SET_POINTS(hfs430); +static DEFINE_SPMI_SET_POINTS(ht_p150); +static DEFINE_SPMI_SET_POINTS(ht_p600); static inline int spmi_vreg_read(struct spmi_regulator *vreg, u16 addr, u8 *buf, int len) @@ -1458,6 +1470,8 @@ static const struct regulator_ops spmi_hfs430_ops = { static const struct spmi_regulator_mapping supported_regulators[] = { /* type subtype dig_min dig_max ltype ops setpoints hpm_min */ + SPMI_VREG(LDO, HT_P600, 0, INF, HFS430, hfs430, ht_p600, 10000), + SPMI_VREG(LDO, HT_P150, 0, INF, HFS430, hfs430, ht_p150, 10000), SPMI_VREG(BUCK, GP_CTL, 0, INF, SMPS, smps, smps, 100000), SPMI_VREG(BUCK, HFS430, 0, INF, HFS430, hfs430, hfs430, 10000), SPMI_VREG(LDO, N300, 0, INF, LDO, ldo, nldo1, 10000), @@ -2125,6 +2139,28 @@ static const struct spmi_regulator_data pm8005_regulators[] = { { } }; +static const struct spmi_regulator_data pmp8074_regulators[] = { + { "s1", 0x1400, "vdd_s1"}, + { "s2", 0x1700, "vdd_s2"}, + { "s3", 0x1a00, "vdd_s3"}, + { "s4", 0x1d00, "vdd_s4"}, + { "s5", 0x2000, "vdd_s5"}, + { "l1", 0x4000, "vdd_l1_l2"}, + { "l2", 0x4100, "vdd_l1_l2"}, + { "l3", 0x4200, "vdd_l3_l8"}, + { "l4", 0x4300, "vdd_l4"}, + { "l5", 0x4400, "vdd_l5_l6_l15"}, + { "l6", 0x4500, "vdd_l5_l6_l15"}, + { "l7", 0x4600, "vdd_l7"}, + { "l8", 0x4700, "vdd_l3_l8"}, + { "l9", 0x4800, "vdd_l9"}, + /* l10 is currently unsupported HT_P50 */ + { "l11", 0x4a00, "vdd_l10_l11_l12_l13"}, + { "l12", 0x4b00, "vdd_l10_l11_l12_l13"}, + { "l13", 0x4c00, "vdd_l10_l11_l12_l13"}, + { } +}; + static const struct spmi_regulator_data pms405_regulators[] = { { "s3", 0x1a00, "vdd_s3"}, { } @@ -2142,6 +2178,7 @@ static const struct of_device_id qcom_spmi_regulator_match[] = { { .compatible = "qcom,pmi8994-regulators", .data = &pmi8994_regulators }, { .compatible = "qcom,pm660-regulators", .data = &pm660_regulators }, { .compatible = "qcom,pm660l-regulators", .data = &pm660l_regulators }, + { .compatible = "qcom,pmp8074-regulators", .data = &pmp8074_regulators }, { .compatible = "qcom,pms405-regulators", .data = &pms405_regulators }, { } }; diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index fa8706a352ce..105f694a67e6 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -187,15 +187,11 @@ static int attiny_update_status(struct backlight_device *bl) { struct attiny_lcd *state = bl_get_data(bl); struct regmap *regmap = state->regmap; - int brightness = bl->props.brightness; + int brightness = backlight_get_brightness(bl); int ret, i; mutex_lock(&state->lock); - if (bl->props.power != FB_BLANK_UNBLANK || - bl->props.fb_blank != FB_BLANK_UNBLANK) - brightness = 0; - for (i = 0; i < 10; i++) { ret = regmap_write(regmap, REG_PWM, brightness); if (!ret) diff --git a/drivers/regulator/rt5120-regulator.c b/drivers/regulator/rt5120-regulator.c new file mode 100644 index 000000000000..8173ede09414 --- /dev/null +++ b/drivers/regulator/rt5120-regulator.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <linux/bits.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/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> + +#define RT5120_REG_PGSTAT 0x03 +#define RT5120_REG_CH1VID 0x06 +#define RT5120_REG_CH1SLPVID 0x07 +#define RT5120_REG_ENABLE 0x08 +#define RT5120_REG_MODECTL 0x09 +#define RT5120_REG_UVOVPROT 0x0A +#define RT5120_REG_SLPCTL 0x0C +#define RT5120_REG_INTSTAT 0x1E +#define RT5120_REG_DISCHG 0x1F + +#define RT5120_OUTPG_MASK(rid) BIT(rid + 1) +#define RT5120_OUTUV_MASK(rid) BIT(rid + 9) +#define RT5120_OUTOV_MASK(rid) BIT(rid + 16) +#define RT5120_CH1VID_MASK GENMASK(6, 0) +#define RT5120_RIDEN_MASK(rid) BIT(rid + 1) +#define RT5120_RADEN_MASK(rid) BIT(rid) +#define RT5120_FPWM_MASK(rid) BIT(rid + 1) +#define RT5120_UVHICCUP_MASK BIT(1) +#define RT5120_OVHICCUP_MASK BIT(0) +#define RT5120_HOTDIE_MASK BIT(1) + +#define RT5120_BUCK1_MINUV 600000 +#define RT5120_BUCK1_MAXUV 1393750 +#define RT5120_BUCK1_STEPUV 6250 +#define RT5120_BUCK1_NUM_VOLT 0x80 + +#define RT5120_AUTO_MODE 0 +#define RT5120_FPWM_MODE 1 + +enum { + RT5120_REGULATOR_BUCK1 = 0, + RT5120_REGULATOR_BUCK2, + RT5120_REGULATOR_BUCK3, + RT5120_REGULATOR_BUCK4, + RT5120_REGULATOR_LDO, + RT5120_REGULATOR_EXTEN, + RT5120_MAX_REGULATOR +}; + +struct rt5120_priv { + struct device *dev; + struct regmap *regmap; + struct regulator_desc rdesc[RT5120_MAX_REGULATOR]; +}; + +static int rt5120_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + int rid = rdev_get_id(rdev); + unsigned int mask = RT5120_FPWM_MASK(rid), val; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = 0; + break; + case REGULATOR_MODE_FAST: + val = RT5120_FPWM_MASK(rid); + break; + default: + return -EINVAL; + } + + return regmap_update_bits(regmap, RT5120_REG_MODECTL, mask, val); +} + +static unsigned int rt5120_buck_get_mode(struct regulator_dev *rdev) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + int ret, rid = rdev_get_id(rdev); + unsigned int val; + + ret = regmap_read(regmap, RT5120_REG_MODECTL, &val); + if (ret) + return REGULATOR_MODE_INVALID; + + if (val & RT5120_FPWM_MASK(rid)) + return REGULATOR_MODE_FAST; + + return REGULATOR_MODE_NORMAL; +} + +static int rt5120_regulator_get_error_flags(struct regulator_dev *rdev, + unsigned int *flags) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int stat, hd_stat, cur_flags = 0; + int rid = rdev_get_id(rdev), ret; + + /* + * reg 0x03/0x04/0x05 to indicate PG/UV/OV + * use block read to descrease I/O xfer time + */ + ret = regmap_raw_read(regmap, RT5120_REG_PGSTAT, &stat, 3); + if (ret) + return ret; + + ret = regmap_read(regmap, RT5120_REG_INTSTAT, &hd_stat); + if (ret) + return ret; + + if (!(stat & RT5120_OUTPG_MASK(rid))) { + if (stat & RT5120_OUTUV_MASK(rid)) + cur_flags |= REGULATOR_ERROR_UNDER_VOLTAGE; + + if (stat & RT5120_OUTOV_MASK(rid)) + cur_flags |= REGULATOR_ERROR_REGULATION_OUT; + } + + if (hd_stat & RT5120_HOTDIE_MASK) + cur_flags |= REGULATOR_ERROR_OVER_TEMP; + + *flags = cur_flags; + return 0; +} + +static int rt5120_buck1_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + int sel; + + if (uV < RT5120_BUCK1_MINUV || uV > RT5120_BUCK1_MAXUV) + return -EINVAL; + + sel = (uV - RT5120_BUCK1_MINUV) / RT5120_BUCK1_STEPUV; + return regmap_write(regmap, RT5120_REG_CH1SLPVID, sel); +} + +static int rt5120_regulator_set_suspend_enable(struct regulator_dev *rdev) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + int rid = rdev_get_id(rdev); + unsigned int mask = RT5120_RIDEN_MASK(rid); + + return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, mask); +} + +static int rt5120_regulator_set_suspend_disable(struct regulator_dev *rdev) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + int rid = rdev_get_id(rdev); + unsigned int mask = RT5120_RIDEN_MASK(rid); + + return regmap_update_bits(regmap, RT5120_REG_SLPCTL, mask, 0); +} + +static const struct regulator_ops rt5120_buck1_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_active_discharge = regulator_set_active_discharge_regmap, + .set_mode = rt5120_buck_set_mode, + .get_mode = rt5120_buck_get_mode, + .get_error_flags = rt5120_regulator_get_error_flags, + .set_suspend_voltage = rt5120_buck1_set_suspend_voltage, + .set_suspend_enable = rt5120_regulator_set_suspend_enable, + .set_suspend_disable = rt5120_regulator_set_suspend_disable, +}; + +static const struct regulator_ops rt5120_buck234_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_mode = rt5120_buck_set_mode, + .get_mode = rt5120_buck_get_mode, + .get_error_flags = rt5120_regulator_get_error_flags, + .set_suspend_enable = rt5120_regulator_set_suspend_enable, + .set_suspend_disable = rt5120_regulator_set_suspend_disable, +}; + +static const struct regulator_ops rt5120_ldo_ops = { + .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 = rt5120_regulator_get_error_flags, + .set_suspend_enable = rt5120_regulator_set_suspend_enable, + .set_suspend_disable = rt5120_regulator_set_suspend_disable, +}; + +static const struct regulator_ops rt5120_exten_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_suspend_enable = rt5120_regulator_set_suspend_enable, + .set_suspend_disable = rt5120_regulator_set_suspend_disable, +}; + +static unsigned int rt5120_buck_of_map_mode(unsigned int mode) +{ + switch (mode) { + case RT5120_AUTO_MODE: + return REGULATOR_MODE_NORMAL; + case RT5120_FPWM_MODE: + return REGULATOR_MODE_FAST; + default: + return REGULATOR_MODE_INVALID; + } +} + +static void rt5120_fillin_regulator_desc(struct regulator_desc *desc, int rid) +{ + static const char * const name[] = { + "buck1", "buck2", "buck3", "buck4", "ldo", "exten" }; + static const char * const sname[] = { + "vin1", "vin2", "vin3", "vin4", "vinldo", NULL }; + + /* Common regulator property */ + desc->name = name[rid]; + desc->supply_name = sname[rid]; + desc->owner = THIS_MODULE; + desc->type = REGULATOR_VOLTAGE; + desc->id = rid; + desc->enable_reg = RT5120_REG_ENABLE; + desc->enable_mask = RT5120_RIDEN_MASK(rid); + desc->active_discharge_reg = RT5120_REG_DISCHG; + desc->active_discharge_mask = RT5120_RADEN_MASK(rid); + desc->active_discharge_on = RT5120_RADEN_MASK(rid); + /* Config n_voltages to 1 for all*/ + desc->n_voltages = 1; + + /* Only buck support mode change */ + if (rid >= RT5120_REGULATOR_BUCK1 && rid <= RT5120_REGULATOR_BUCK4) + desc->of_map_mode = rt5120_buck_of_map_mode; + + /* RID specific property init */ + switch (rid) { + case RT5120_REGULATOR_BUCK1: + /* Only buck1 support voltage change by I2C */ + 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->ops = &rt5120_buck1_ops; + break; + case RT5120_REGULATOR_BUCK2 ... RT5120_REGULATOR_BUCK4: + desc->ops = &rt5120_buck234_ops; + break; + case RT5120_REGULATOR_LDO: + desc->ops = &rt5120_ldo_ops; + break; + default: + desc->ops = &rt5120_exten_ops; + } +} + +static int rt5120_of_parse_cb(struct rt5120_priv *priv, int rid, + struct of_regulator_match *match) +{ + struct regulator_desc *desc = priv->rdesc + rid; + struct regulator_init_data *init_data = match->init_data; + + if (!init_data || rid == RT5120_REGULATOR_BUCK1) + return 0; + + if (init_data->constraints.min_uV != init_data->constraints.max_uV) { + dev_err(priv->dev, "Variable voltage for fixed regulator\n"); + return -EINVAL; + } + + desc->fixed_uV = init_data->constraints.min_uV; + return 0; +} + +static struct of_regulator_match rt5120_regu_match[RT5120_MAX_REGULATOR] = { + [RT5120_REGULATOR_BUCK1] = { .name = "buck1", }, + [RT5120_REGULATOR_BUCK2] = { .name = "buck2", }, + [RT5120_REGULATOR_BUCK3] = { .name = "buck3", }, + [RT5120_REGULATOR_BUCK4] = { .name = "buck4", }, + [RT5120_REGULATOR_LDO] = { .name = "ldo", }, + [RT5120_REGULATOR_EXTEN] = { .name = "exten", } +}; + +static int rt5120_parse_regulator_dt_data(struct rt5120_priv *priv) +{ + struct device *dev = priv->dev->parent; + struct device_node *reg_node; + int i, ret; + + for (i = 0; i < RT5120_MAX_REGULATOR; i++) { + rt5120_fillin_regulator_desc(priv->rdesc + i, i); + + rt5120_regu_match[i].desc = priv->rdesc + i; + } + + reg_node = of_get_child_by_name(dev->of_node, "regulators"); + if (!reg_node) { + dev_err(priv->dev, "Couldn't find 'regulators' node\n"); + return -ENODEV; + } + + ret = of_regulator_match(priv->dev, reg_node, rt5120_regu_match, + ARRAY_SIZE(rt5120_regu_match)); + + of_node_put(reg_node); + + if (ret < 0) { + dev_err(priv->dev, + "Error parsing regulator init data (%d)\n", ret); + return ret; + } + + for (i = 0; i < RT5120_MAX_REGULATOR; i++) { + ret = rt5120_of_parse_cb(priv, i, rt5120_regu_match + i); + if (ret) { + dev_err(priv->dev, "Failed in [%d] of_passe_cb\n", i); + return ret; + } + } + + return 0; +} + +static int rt5120_device_property_init(struct rt5120_priv *priv) +{ + struct device *dev = priv->dev->parent; + struct device_node *np = dev->of_node; + bool prot_enable; + unsigned int prot_enable_val = 0; + + /* Assign UV/OV HW protection behavior */ + prot_enable = of_property_read_bool(np, + "richtek,enable-undervolt-hiccup"); + if (prot_enable) + prot_enable_val |= RT5120_UVHICCUP_MASK; + + prot_enable = of_property_read_bool(np, + "richtek,enable-overvolt-hiccup"); + if (prot_enable) + prot_enable_val |= RT5120_OVHICCUP_MASK; + + return regmap_update_bits(priv->regmap, RT5120_REG_UVOVPROT, + RT5120_UVHICCUP_MASK | RT5120_OVHICCUP_MASK, + prot_enable_val); +} + +static int rt5120_regulator_probe(struct platform_device *pdev) +{ + struct rt5120_priv *priv; + struct regulator_dev *rdev; + struct regulator_config config = {}; + int i, ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = &pdev->dev; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "Failed to init regmap\n"); + return -ENODEV; + } + + ret = rt5120_device_property_init(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to do property init\n"); + return ret; + } + + ret = rt5120_parse_regulator_dt_data(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to parse dt data\n"); + return ret; + } + + config.dev = &pdev->dev; + config.regmap = priv->regmap; + + for (i = 0; i < RT5120_MAX_REGULATOR; i++) { + config.of_node = rt5120_regu_match[i].of_node; + config.init_data = rt5120_regu_match[i].init_data; + + rdev = devm_regulator_register(&pdev->dev, priv->rdesc + i, + &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "Failed to register regulator [%d]\n", i); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id rt5120_regulator_dev_table[] = { + { "rt5120-regulator", 0 }, + {} +}; +MODULE_DEVICE_TABLE(platform, rt5120_regulator_dev_table); + +static struct platform_driver rt5120_regulator_driver = { + .driver = { + .name = "rt5120-regulator", + }, + .id_table = rt5120_regulator_dev_table, + .probe = rt5120_regulator_probe, +}; +module_platform_driver(rt5120_regulator_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Richtek RT5120 regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/rt5190a-regulator.c b/drivers/regulator/rt5190a-regulator.c index 155d4afd00b1..4a3397b32582 100644 --- a/drivers/regulator/rt5190a-regulator.c +++ b/drivers/regulator/rt5190a-regulator.c @@ -224,6 +224,9 @@ static int rt5190a_of_parse_cb(struct rt5190a_priv *priv, int rid, bool latchup_enable; unsigned int mask = RT5190A_RID_BITMASK(rid), val; + if (!init_data) + return 0; + switch (rid) { case RT5190A_IDX_BUCK1: case RT5190A_IDX_BUCK4: diff --git a/drivers/regulator/scmi-regulator.c b/drivers/regulator/scmi-regulator.c index 41ae7ac27ff6..b9918f4fd241 100644 --- a/drivers/regulator/scmi-regulator.c +++ b/drivers/regulator/scmi-regulator.c @@ -343,6 +343,7 @@ static int scmi_regulator_probe(struct scmi_device *sdev) * plausible SCMI Voltage Domain number, all belonging to this SCMI * platform instance node (handle->dev->of_node). */ + 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) { ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo); diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index bd7b2f287250..afa336be1cc9 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -309,7 +309,7 @@ out: * * Return: 0 on success or appropriate error value when fails */ -static int ti_abb_set_voltage_sel(struct regulator_dev *rdev, unsigned sel) +static int ti_abb_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) { const struct regulator_desc *desc = rdev->desc; struct ti_abb *abb = rdev_get_drvdata(rdev); @@ -344,7 +344,7 @@ static int ti_abb_set_voltage_sel(struct regulator_dev *rdev, unsigned sel) info = &abb->info[sel]; /* - * When Linux kernel is starting up, we are'nt sure of the + * When Linux kernel is starting up, we aren't sure of the * Bias configuration that bootloader has configured. * So, we get to know the actual setting the first time * we are asked to transition. diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index bbf6590a6dec..bc6cda706d1f 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -171,10 +171,13 @@ struct regulator; /** * struct regulator_bulk_data - Data used for bulk regulator operations. * - * @supply: The name of the supply. Initialised by the user before - * using the bulk regulator APIs. - * @consumer: The regulator consumer for the supply. This will be managed - * by the bulk API. + * @supply: The name of the supply. Initialised by the user before + * using the bulk regulator APIs. + * @init_load_uA: After getting the regulator, regulator_set_load() will be + * called with this load. Initialised by the user before + * using the bulk regulator APIs. + * @consumer: The regulator consumer for the supply. This will be managed + * by the bulk API. * * The regulator APIs provide a series of regulator_bulk_() API calls as * a convenience to consumers which require multiple supplies. This @@ -182,6 +185,7 @@ struct regulator; */ struct regulator_bulk_data { const char *supply; + int init_load_uA; struct regulator *consumer; /* private: Internal use */ @@ -240,6 +244,10 @@ int __must_check regulator_bulk_get(struct device *dev, int num_consumers, struct regulator_bulk_data *consumers); int __must_check devm_regulator_bulk_get(struct device *dev, int num_consumers, struct regulator_bulk_data *consumers); +int __must_check devm_regulator_bulk_get_const( + struct device *dev, int num_consumers, + const struct regulator_bulk_data *in_consumers, + struct regulator_bulk_data **out_consumers); int __must_check regulator_bulk_enable(int num_consumers, struct regulator_bulk_data *consumers); int regulator_bulk_disable(int num_consumers, diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 0228caaa6741..f9a7461e72b8 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -348,6 +348,7 @@ enum regulator_type { * @ramp_delay_table: Table for mapping the regulator ramp-rate values. Values * should be given in units of V/S (uV/uS). See the * regulator_set_ramp_delay_regmap(). + * @n_ramp_values: number of elements at @ramp_delay_table. * * @enable_time: Time taken for initial enable of regulator (in uS). * @off_on_delay: guard time (in uS), before re-enabling a regulator |