diff options
50 files changed, 2862 insertions, 762 deletions
diff --git a/Documentation/devicetree/bindings/regulator/arizona-regulator.txt b/Documentation/devicetree/bindings/regulator/arizona-regulator.txt index 443564d7784f..69bf41949b01 100644 --- a/Documentation/devicetree/bindings/regulator/arizona-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/arizona-regulator.txt @@ -5,7 +5,8 @@ of analogue I/O. This document lists regulator specific bindings, see the primary binding document: - ../mfd/arizona.txt + For Wolfson Microelectronic Arizona codecs: ../mfd/arizona.txt + For Cirrus Logic Madera codecs: ../mfd/madera.txt Optional properties: - wlf,ldoena : GPIO specifier for the GPIO controlling LDOENA diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml b/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml index d289c2f7455a..a650b457085d 100644 --- a/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml @@ -12,10 +12,13 @@ maintainers: description: Any property defined as part of the core regulator binding, defined in - regulator.txt, can also be used. However a fixed voltage regulator is + regulator.yaml, can also be used. However a fixed voltage regulator is expected to have the regulator-min-microvolt and regulator-max-microvolt to be the same. +allOf: + - $ref: "regulator.yaml#" + properties: compatible: const: regulator-fixed diff --git a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt b/Documentation/devicetree/bindings/regulator/gpio-regulator.txt deleted file mode 100644 index dd25e73b5d79..000000000000 --- a/Documentation/devicetree/bindings/regulator/gpio-regulator.txt +++ /dev/null @@ -1,57 +0,0 @@ -GPIO controlled regulators - -Required properties: -- compatible : Must be "regulator-gpio". -- regulator-name : Defined in regulator.txt as optional, but required - here. -- gpios : Array of one or more GPIO pins used to select the - regulator voltage/current listed in "states". -- states : Selection of available voltages/currents provided by - this regulator and matching GPIO configurations to - achieve them. If there are no states in the "states" - array, use a fixed regulator instead. - -Optional properties: -- enable-gpios : GPIO used to enable/disable the regulator. - Warning, the GPIO phandle flags are ignored and the - GPIO polarity is controlled solely by the presence - of "enable-active-high" DT property. This is due to - compatibility with old DTs. -- enable-active-high : Polarity of "enable-gpio" GPIO is active HIGH. - Default is active LOW. -- gpios-states : On operating systems, that don't support reading back - gpio values in output mode (most notably linux), this - array provides the state of GPIO pins set when - requesting them from the gpio controller. Systems, - that are capable of preserving state when requesting - the lines, are free to ignore this property. - 0: LOW, 1: HIGH. Default is LOW if nothing else - is specified. -- startup-delay-us : Startup time in microseconds. -- regulator-type : Specifies what is being regulated, must be either - "voltage" or "current", defaults to voltage. - -Any property defined as part of the core regulator binding defined in -regulator.txt can also be used. - -Example: - - mmciv: gpio-regulator { - compatible = "regulator-gpio"; - - regulator-name = "mmci-gpio-supply"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2600000>; - regulator-boot-on; - - enable-gpios = <&gpio0 23 0x4>; - gpios = <&gpio0 24 0x4 - &gpio0 25 0x4>; - states = <1800000 0x3 - 2200000 0x2 - 2600000 0x1 - 2900000 0x0>; - - startup-delay-us = <100000>; - enable-active-high; - }; diff --git a/Documentation/devicetree/bindings/regulator/gpio-regulator.yaml b/Documentation/devicetree/bindings/regulator/gpio-regulator.yaml new file mode 100644 index 000000000000..9d3b28417fb6 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/gpio-regulator.yaml @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/gpio-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GPIO controlled regulators + +maintainers: + - Liam Girdwood <lgirdwood@gmail.com> + - Mark Brown <broonie@kernel.org> + +description: + Any property defined as part of the core regulator binding, defined in + regulator.txt, can also be used. + +allOf: + - $ref: "regulator.yaml#" + +properties: + compatible: + const: regulator-gpio + + regulator-name: true + + enable-gpios: + description: GPIO to use to enable/disable the regulator. + Warning, the GPIO phandle flags are ignored and the GPIO polarity is + controlled solely by the presence of "enable-active-high" DT property. + This is due to compatibility with old DTs. + maxItems: 1 + + gpios: + description: Array of one or more GPIO pins used to select the regulator + voltage/current listed in "states". + minItems: 1 + maxItems: 8 # Should be enough... + + gpios-states: + description: | + On operating systems, that don't support reading back gpio values in + output mode (most notably linux), this array provides the state of GPIO + pins set when requesting them from the gpio controller. Systems, that are + capable of preserving state when requesting the lines, are free to ignore + this property. + 0: LOW + 1: HIGH + Default is LOW if nothing else is specified. + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-array + - maxItems: 8 + items: + enum: [ 0, 1 ] + default: 0 + + states: + description: Selection of available voltages/currents provided by this + regulator and matching GPIO configurations to achieve them. If there are + no states in the "states" array, use a fixed regulator instead. + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32-matrix + - maxItems: 8 + items: + items: + - description: Voltage in microvolts + - description: GPIO group state value + + startup-delay-us: + description: startup time in microseconds + + enable-active-high: + description: Polarity of "enable-gpio" GPIO is active HIGH. Default is + active LOW. + type: boolean + + gpio-open-drain: + description: + GPIO is open drain type. If this property is missing then default + assumption is false. + type: boolean + + regulator-type: + description: Specifies what is being regulated. + allOf: + - $ref: /schemas/types.yaml#/definitions/string + - enum: + - voltage + - current + default: voltage + +required: + - compatible + - regulator-name + - gpios + - states + +examples: + - | + gpio-regulator { + compatible = "regulator-gpio"; + + regulator-name = "mmci-gpio-supply"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2600000>; + regulator-boot-on; + + enable-gpios = <&gpio0 23 0x4>; + gpios = <&gpio0 24 0x4 + &gpio0 25 0x4>; + states = <1800000 0x3>, + <2200000 0x2>, + <2600000 0x1>, + <2900000 0x0>; + + startup-delay-us = <100000>; + enable-active-high; + }; +... diff --git a/Documentation/devicetree/bindings/regulator/max8660.txt b/Documentation/devicetree/bindings/regulator/max8660.txt deleted file mode 100644 index 8ba994d8a142..000000000000 --- a/Documentation/devicetree/bindings/regulator/max8660.txt +++ /dev/null @@ -1,47 +0,0 @@ -Maxim MAX8660 voltage regulator - -Required properties: -- compatible: must be one of "maxim,max8660", "maxim,max8661" -- reg: I2C slave address, usually 0x34 -- any required generic properties defined in regulator.txt - -Example: - - i2c_master { - max8660@34 { - compatible = "maxim,max8660"; - reg = <0x34>; - - regulators { - regulator@0 { - regulator-compatible= "V3(DCDC)"; - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1800000>; - }; - - regulator@1 { - regulator-compatible= "V4(DCDC)"; - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1800000>; - }; - - regulator@2 { - regulator-compatible= "V5(LDO)"; - regulator-min-microvolt = <1700000>; - regulator-max-microvolt = <2000000>; - }; - - regulator@3 { - regulator-compatible= "V6(LDO)"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - }; - - regulator@4 { - regulator-compatible= "V7(LDO)"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - }; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/regulator/max8660.yaml b/Documentation/devicetree/bindings/regulator/max8660.yaml new file mode 100644 index 000000000000..9c038698f880 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max8660.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/max8660.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX8660 voltage regulator + +maintainers: + - Daniel Mack <zonque@gmail.com> + +properties: + $nodename: + pattern: "pmic@[0-9a-f]{1,2}" + compatible: + enum: + - maxim,max8660 + - maxim,max8661 + + reg: + maxItems: 1 + + regulators: + type: object + + patternProperties: + "regulator-.+": + $ref: "regulator.yaml#" + + additionalProperties: false + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@34 { + compatible = "maxim,max8660"; + reg = <0x34>; + + regulators { + regulator-V3 { + regulator-compatible= "V3(DCDC)"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1800000>; + }; + + regulator-V4 { + regulator-compatible= "V4(DCDC)"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1800000>; + }; + + regulator-V5 { + regulator-compatible= "V5(LDO)"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2000000>; + }; + + regulator-V6 { + regulator-compatible= "V6(LDO)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + regulator-V7 { + regulator-compatible= "V7(LDO)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt index 406f2e570c50..430b8622bda1 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt @@ -4,11 +4,13 @@ Qualcomm SPMI Regulators Usage: required Value type: <string> Definition: must be one of: + "qcom,pm8005-regulators" "qcom,pm8841-regulators" "qcom,pm8916-regulators" "qcom,pm8941-regulators" "qcom,pm8994-regulators" "qcom,pmi8994-regulators" + "qcom,pms405-regulators" - interrupts: Usage: optional @@ -110,6 +112,23 @@ Qualcomm SPMI Regulators 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> @@ -120,6 +139,9 @@ 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. +pm8005: + s1, s2, s3, s4 + pm8841: s1, s2, s3, s4, s5, s6, s7, s8 diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 0a3f087d5844..487ccd8370b3 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -1,139 +1 @@ -Voltage/Current Regulators - -Optional properties: -- regulator-name: A string used as a descriptive name for regulator outputs -- regulator-min-microvolt: smallest voltage consumers may set -- regulator-max-microvolt: largest voltage consumers may set -- regulator-microvolt-offset: Offset applied to voltages to compensate for voltage drops -- regulator-min-microamp: smallest current consumers may set -- regulator-max-microamp: largest current consumers may set -- regulator-input-current-limit-microamp: maximum input current regulator allows -- regulator-always-on: boolean, regulator should never be disabled -- regulator-boot-on: bootloader/firmware enabled regulator -- regulator-allow-bypass: allow the regulator to go into bypass mode -- regulator-allow-set-load: allow the regulator performance level to be configured -- <name>-supply: phandle to the parent supply/regulator node -- regulator-ramp-delay: ramp delay for regulator(in uV/us) - For hardware which supports disabling ramp rate, it should be explicitly - initialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay. -- regulator-enable-ramp-delay: The time taken, in microseconds, for the supply - rail to reach the target voltage, plus/minus whatever tolerance the board - design requires. This property describes the total system ramp time - required due to the combination of internal ramping of the regulator itself, - and board design issues such as trace capacitance and load on the supply. -- regulator-settling-time-us: Settling time, in microseconds, for voltage - change if regulator have the constant time for any level voltage change. - This is useful when regulator have exponential voltage change. -- regulator-settling-time-up-us: Settling time, in microseconds, for voltage - increase if the regulator needs a constant time to settle after voltage - increases of any level. This is useful for regulators with exponential - voltage changes. -- regulator-settling-time-down-us: Settling time, in microseconds, for voltage - decrease if the regulator needs a constant time to settle after voltage - decreases of any level. This is useful for regulators with exponential - voltage changes. -- regulator-soft-start: Enable soft start so that voltage ramps slowly -- regulator-state-standby sub-root node for Standby mode - : equivalent with standby Linux sleep state, which provides energy savings - with a relatively quick transition back time. -- regulator-state-mem sub-root node for Suspend-to-RAM mode - : suspend to memory, the device goes to sleep, but all data stored in memory, - only some external interrupt can wake the device. -- regulator-state-disk sub-root node for Suspend-to-DISK mode - : suspend to disk, this state operates similarly to Suspend-to-RAM, - but includes a final step of writing memory contents to disk. -- regulator-state-[mem/disk/standby] node has following common properties: - - regulator-on-in-suspend: regulator should be on in suspend state. - - regulator-off-in-suspend: regulator should be off in suspend state. - - regulator-suspend-min-microvolt: minimum voltage may be set in - suspend state. - - regulator-suspend-max-microvolt: maximum voltage may be set in - suspend state. - - regulator-suspend-microvolt: the default voltage which regulator - would be set in suspend. This property is now deprecated, instead - setting voltage for suspend mode via the API which regulator - driver provides is recommended. - - regulator-changeable-in-suspend: whether the default voltage and - the regulator on/off in suspend can be changed in runtime. - - regulator-mode: operating mode in the given suspend state. - The set of possible operating modes depends on the capabilities of - every hardware so the valid modes are documented on each regulator - device tree binding document. -- regulator-initial-mode: initial operating mode. The set of possible operating - modes depends on the capabilities of every hardware so each device binding - documentation explains which values the regulator supports. -- regulator-allowed-modes: list of operating modes that software is allowed to - configure for the regulator at run-time. Elements may be specified in any - order. The set of possible operating modes depends on the capabilities of - every hardware so each device binding document explains which values the - regulator supports. -- regulator-system-load: Load in uA present on regulator that is not captured by - any consumer request. -- regulator-pull-down: Enable pull down resistor when the regulator is disabled. -- regulator-over-current-protection: Enable over current protection. -- regulator-active-discharge: tristate, enable/disable active discharge of - regulators. The values are: - 0: Disable active discharge. - 1: Enable active discharge. - Absence of this property will leave configuration to default. -- regulator-coupled-with: Regulators with which the regulator - is coupled. The linkage is 2-way - all coupled regulators should be linked - with each other. A regulator should not be coupled with its supplier. -- regulator-coupled-max-spread: Array of maximum spread between voltages of - coupled regulators in microvolts, each value in the array relates to the - corresponding couple specified by the regulator-coupled-with property. -- regulator-max-step-microvolt: Maximum difference between current and target - voltages that can be changed safely in a single step. - -Deprecated properties: -- regulator-compatible: If a regulator chip contains multiple - regulators, and if the chip's binding contains a child node that - describes each regulator, then this property indicates which regulator - this child node is intended to configure. If this property is missing, - the node's name will be used instead. - -Example: - - xyzreg: regulator@0 { - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <2500000>; - regulator-always-on; - vin-supply = <&vin>; - - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - -Regulator Consumers: -Consumer nodes can reference one or more of its supplies/ -regulators using the below bindings. - -- <name>-supply: phandle to the regulator node - -These are the same bindings that a regulator in the above -example used to reference its own supply, in which case -its just seen as a special case of a regulator being a -consumer itself. - -Example of a consumer device node (mmc) referencing two -regulators (twl_reg1 and twl_reg2), - - twl_reg1: regulator@0 { - ... - ... - ... - }; - - twl_reg2: regulator@1 { - ... - ... - ... - }; - - mmc: mmc@0 { - ... - ... - vmmc-supply = <&twl_reg1>; - vmmcaux-supply = <&twl_reg2>; - }; +This file has moved to regulator.yaml. diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml new file mode 100644 index 000000000000..02c3043ce419 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -0,0 +1,200 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Voltage/Current Regulators + +maintainers: + - Liam Girdwood <lgirdwood@gmail.com> + - Mark Brown <broonie@kernel.org> + +properties: + regulator-name: + description: A string used as a descriptive name for regulator outputs + $ref: "/schemas/types.yaml#/definitions/string" + + regulator-min-microvolt: + description: smallest voltage consumers may set + + regulator-max-microvolt: + description: largest voltage consumers may set + + regulator-microvolt-offset: + description: Offset applied to voltages to compensate for voltage drops + + regulator-min-microamp: + description: smallest current consumers may set + + regulator-max-microamp: + description: largest current consumers may set + + regulator-input-current-limit-microamp: + description: maximum input current regulator allows + + regulator-always-on: + description: boolean, regulator should never be disabled + type: boolean + + regulator-boot-on: + description: bootloader/firmware enabled regulator + type: boolean + + regulator-allow-bypass: + description: allow the regulator to go into bypass mode + type: boolean + + regulator-allow-set-load: + description: allow the regulator performance level to be configured + type: boolean + + regulator-ramp-delay: + description: ramp delay for regulator(in uV/us) For hardware which supports + disabling ramp rate, it should be explicitly initialised to zero (regulator-ramp-delay + = <0>) for disabling ramp delay. + $ref: "/schemas/types.yaml#/definitions/uint32" + + regulator-enable-ramp-delay: + description: The time taken, in microseconds, for the supply rail to + reach the target voltage, plus/minus whatever tolerance the board + design requires. This property describes the total system ramp time + required due to the combination of internal ramping of the regulator + itself, and board design issues such as trace capacitance and load + on the supply. + $ref: "/schemas/types.yaml#/definitions/uint32" + + regulator-settling-time-us: + description: Settling time, in microseconds, for voltage change if regulator + have the constant time for any level voltage change. This is useful + when regulator have exponential voltage change. + + regulator-settling-time-up-us: + description: Settling time, in microseconds, for voltage increase if + the regulator needs a constant time to settle after voltage increases + of any level. This is useful for regulators with exponential voltage + changes. + + regulator-settling-time-down-us: + description: Settling time, in microseconds, for voltage decrease if + the regulator needs a constant time to settle after voltage decreases + of any level. This is useful for regulators with exponential voltage + changes. + + regulator-soft-start: + description: Enable soft start so that voltage ramps slowly + type: boolean + + regulator-initial-mode: + description: initial operating mode. The set of possible operating modes + depends on the capabilities of every hardware so each device binding + documentation explains which values the regulator supports. + $ref: "/schemas/types.yaml#/definitions/uint32" + + regulator-allowed-modes: + description: list of operating modes that software is allowed to configure + for the regulator at run-time. Elements may be specified in any order. + The set of possible operating modes depends on the capabilities of + every hardware so each device binding document explains which values + the regulator supports. + $ref: "/schemas/types.yaml#/definitions/uint32-array" + + regulator-system-load: + description: Load in uA present on regulator that is not captured by + any consumer request. + $ref: "/schemas/types.yaml#/definitions/uint32" + + regulator-pull-down: + description: Enable pull down resistor when the regulator is disabled. + type: boolean + + regulator-over-current-protection: + description: Enable over current protection. + type: boolean + + regulator-active-discharge: + description: | + tristate, enable/disable active discharge of regulators. The values are: + 0: Disable active discharge. + 1: Enable active discharge. + Absence of this property will leave configuration to default. + allOf: + - $ref: "/schemas/types.yaml#/definitions/uint32" + - enum: [ 0, 1 ] + + regulator-coupled-with: + description: Regulators with which the regulator is coupled. The linkage + is 2-way - all coupled regulators should be linked with each other. + A regulator should not be coupled with its supplier. + $ref: "/schemas/types.yaml#/definitions/phandle-array" + + regulator-coupled-max-spread: + description: Array of maximum spread between voltages of coupled regulators + in microvolts, each value in the array relates to the corresponding + couple specified by the regulator-coupled-with property. + $ref: "/schemas/types.yaml#/definitions/uint32" + + regulator-max-step-microvolt: + description: Maximum difference between current and target voltages + that can be changed safely in a single step. + +patternProperties: + ".*-supply$": + description: Input supply phandle(s) for this node + + regulator-state-(standby|mem|disk): + type: object + description: + sub-nodes for regulator state in Standby, Suspend-to-RAM, and + Suspend-to-DISK modes. Equivalent with standby, mem, and disk Linux + sleep states. + + properties: + regulator-on-in-suspend: + description: regulator should be on in suspend state. + type: boolean + + regulator-off-in-suspend: + description: regulator should be off in suspend state. + type: boolean + + regulator-suspend-min-microvolt: + description: minimum voltage may be set in suspend state. + + regulator-suspend-max-microvolt: + description: maximum voltage may be set in suspend state. + + regulator-suspend-microvolt: + description: the default voltage which regulator would be set in + suspend. This property is now deprecated, instead setting voltage + for suspend mode via the API which regulator driver provides is + recommended. + + regulator-changeable-in-suspend: + description: whether the default voltage and the regulator on/off + in suspend can be changed in runtime. + type: boolean + + regulator-mode: + description: operating mode in the given suspend state. The set + of possible operating modes depends on the capabilities of every + hardware so the valid modes are documented on each regulator device + tree binding document. + $ref: "/schemas/types.yaml#/definitions/uint32" + + additionalProperties: false + +examples: + - | + xyzreg: regulator@0 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + vin-supply = <&vin>; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/regulator/slg51000.txt b/Documentation/devicetree/bindings/regulator/slg51000.txt new file mode 100644 index 000000000000..aa0733e49b90 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/slg51000.txt @@ -0,0 +1,88 @@ +* Dialog Semiconductor SLG51000 Voltage Regulator + +Required properties: +- compatible : Should be "dlg,slg51000" for SLG51000 +- reg : Specifies the I2C slave address. +- xxx-supply: Input voltage supply regulator for ldo3 to ldo7. + These entries are required if regulators are enabled for a device. + An absence of these properties can cause the regulator registration to fail. + If some of input supply is powered through battery or always-on supply then + also it is required to have these parameters with proper node handle of always + on power supply. + vin3-supply: Input supply for ldo3 + vin4-supply: Input supply for ldo4 + vin5-supply: Input supply for ldo5 + vin6-supply: Input supply for ldo6 + vin7-supply: Input supply for ldo7 + +Optional properties: +- interrupt-parent : Specifies the reference to the interrupt controller. +- interrupts : IRQ line information. +- dlg,cs-gpios : Specify a valid GPIO for chip select + +Sub-nodes: +- regulators : This node defines the settings for the regulators. + The content of the sub-node is defined by the standard binding + for regulators; see regulator.txt. + + The SLG51000 regulators are bound using their names listed below: + ldo1 + ldo2 + ldo3 + ldo4 + ldo5 + ldo6 + ldo7 + +Optional properties for regulators: +- enable-gpios : Specify a valid GPIO for platform control of the regulator. + +Example: + pmic: slg51000@75 { + compatible = "dlg,slg51000"; + reg = <0x75>; + + regulators { + ldo1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3300000>; + }; + + ldo2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3300000>; + }; + + ldo3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3750000>; + }; + + ldo4 { + regulator-name = "ldo4"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3750000>; + }; + + ldo5 { + regulator-name = "ldo5"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1200000>; + }; + + ldo6 { + regulator-name = "ldo6"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1200000>; + }; + + ldo7 { + regulator-name = "ldo7"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3750000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-booster.txt b/Documentation/devicetree/bindings/regulator/st,stm32-booster.txt new file mode 100644 index 000000000000..479ad4c8758e --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/st,stm32-booster.txt @@ -0,0 +1,18 @@ +STM32 BOOSTER - Booster for ADC analog input switches + +Some STM32 devices embed a 3.3V booster supplied by Vdda, that can be used +to supply ADC analog input switches. + +Required properties: +- compatible: Should be one of: + "st,stm32h7-booster" + "st,stm32mp1-booster" +- st,syscfg: Phandle to system configuration controller. +- vdda-supply: Phandle to the vdda input analog voltage. + +Example: + booster: regulator-booster { + compatible = "st,stm32mp1-booster"; + st,syscfg = <&syscfg>; + vdda-supply = <&vdda>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e61476a388b1..aa738a14bf6e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4714,6 +4714,7 @@ F: Documentation/devicetree/bindings/mfd/da90*.txt F: Documentation/devicetree/bindings/input/da90??-onkey.txt F: Documentation/devicetree/bindings/thermal/da90??-thermal.txt F: Documentation/devicetree/bindings/regulator/da92*.txt +F: Documentation/devicetree/bindings/regulator/slg51000.txt F: Documentation/devicetree/bindings/watchdog/da90??-wdt.txt F: Documentation/devicetree/bindings/sound/da[79]*.txt F: drivers/gpio/gpio-da90??.c @@ -4729,6 +4730,7 @@ F: drivers/power/supply/da9052-battery.c F: drivers/power/supply/da91??-*.c F: drivers/regulator/da903x.c F: drivers/regulator/da9???-regulator.[ch] +F: drivers/regulator/slg51000-regulator.[ch] F: drivers/thermal/da90??-thermal.c F: drivers/rtc/rtc-da90??.c F: drivers/video/backlight/da90??_bl.c diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 379424d72ae7..8ec6a4f5eb05 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -15,6 +15,7 @@ #include <linux/io.h> #include <linux/init.h> #include <linux/gpio.h> +#include <linux/gpio/machine.h> #include <linux/leds.h> #include <linux/delay.h> #include <linux/mmc/host.h> @@ -398,7 +399,6 @@ static struct pca953x_platform_data crag6410_pca_data = { /* VDDARM is controlled by DVS1 connected to GPK(0) */ static struct wm831x_buckv_pdata vddarm_pdata = { .dvs_control_src = 1, - .dvs_gpio = S3C64XX_GPK(0), }; static struct regulator_consumer_supply vddarm_consumers[] = { @@ -596,6 +596,24 @@ static struct wm831x_pdata crag_pmic_pdata = { .touch = &touch_pdata, }; +/* + * VDDARM is eventually ending up as a regulator hanging on the MFD cell device + * "wm831x-buckv.1" spawn from drivers/mfd/wm831x-core.c. + * + * From the note on the platform data we can see that this is clearly DVS1 + * and assigned as dcdc1 resource to the MFD core which sets .id of the cell + * spawning the DVS1 platform device to 1, then the cell platform device + * name is calculated from 10*instance + id resulting in the device name + * "wm831x-buckv.11" + */ +static struct gpiod_lookup_table crag_pmic_gpiod_table = { + .dev_id = "wm831x-buckv.11", + .table = { + GPIO_LOOKUP("GPIOK", 0, "dvs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct i2c_board_info i2c_devs0[] = { { I2C_BOARD_INFO("24c08", 0x50), }, { I2C_BOARD_INFO("tca6408", 0x20), @@ -836,6 +854,7 @@ static void __init crag6410_machine_init(void) s3c_fb_set_platdata(&crag6410_lcd_pdata); dwc2_hsotg_set_platdata(&crag6410_hsotg_pdata); + gpiod_add_lookup_table(&crag_pmic_gpiod_table); i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0)); i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); diff --git a/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi index f09f3e03f708..108667ce4f31 100644 --- a/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998-mtp.dtsi @@ -27,6 +27,23 @@ status = "okay"; }; +&pm8005_lsid1 { + pm8005-regulators { + compatible = "qcom,pm8005-regulators"; + + vdd_s1-supply = <&vph_pwr>; + + pm8005_s1: s1 { /* VDD_GFX supply */ + regulator-min-microvolt = <524000>; + regulator-max-microvolt = <1100000>; + regulator-enable-ramp-delay = <500>; + + /* hack until we rig up the gpu consumer */ + regulator-always-on; + }; + }; +}; + &qusb2phy { status = "okay"; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 47a67c4deed4..3ee99d070608 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4257,8 +4257,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * * Returns: * On successful request the GPIO pin is configured in accordance with - * provided @dflags. If the node does not have the requested GPIO - * property, NULL is returned. + * provided @dflags. * * In case of error an ERR_PTR() is returned. */ @@ -4280,9 +4279,6 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, index, &flags); if (!desc || IS_ERR(desc)) { - /* If it is not there, just return NULL */ - if (PTR_ERR(desc) == -ENOENT) - return NULL; return desc; } diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800-regulator.c index 69ae25886181..69ae25886181 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800-regulator.c diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index b5d0e07a62d7..7928960563e6 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -136,19 +136,20 @@ config REGULATOR_AB8500 signal AB8500 PMIC config REGULATOR_ARIZONA_LDO1 - tristate "Wolfson Arizona class devices LDO1" - depends on MFD_ARIZONA + tristate "Cirrus Madera and Wolfson Arizona class devices LDO1" + depends on MFD_ARIZONA || MFD_MADERA depends on SND_SOC help - Support for the LDO1 regulators found on Wolfson Arizona class - devices. + Support for the LDO1 regulators found on Cirrus Logic Madera codecs + and Wolfson Microelectronic Arizona codecs. config REGULATOR_ARIZONA_MICSUPP - tristate "Wolfson Arizona class devices MICSUPP" - depends on MFD_ARIZONA + tristate "Cirrus Madera and Wolfson Arizona class devices MICSUPP" + depends on MFD_ARIZONA || MFD_MADERA depends on SND_SOC help - Support for the MICSUPP regulators found on Wolfson Arizona class + Support for the MICSUPP regulators found on Cirrus Logic Madera codecs + and Wolfson Microelectronic Arizona codecs devices. config REGULATOR_AS3711 @@ -258,7 +259,7 @@ config REGULATOR_DA9062 config REGULATOR_DA9063 tristate "Dialog Semiconductor DA9063 regulators" - depends on MFD_DA9063 + depends on MFD_DA9063 && OF help Say y here to support the BUCKs and LDOs regulators found on DA9063 PMICs. @@ -829,6 +830,26 @@ config REGULATOR_SKY81452 This driver can also be built as a module. If so, the module will be called sky81452-regulator. +config REGULATOR_SLG51000 + tristate "Dialog Semiconductor SLG51000 regulators" + depends on I2C + select REGMAP_I2C + help + Say y here to support for the Dialog Semiconductor SLG51000. + The SLG51000 is seven compact and customizable low dropout + regulators. + +config REGULATOR_STM32_BOOSTER + tristate "STMicroelectronics STM32 BOOSTER" + depends on ARCH_STM32 || COMPILE_TEST + help + This driver supports internal booster (3V3) embedded in some + STMicroelectronics STM32 chips. It can be used to supply ADC analog + input switches when vdda supply is below 2.7V. + + This driver can also be built as a module. If so, the module + will be called stm32-booster. + config REGULATOR_STM32_VREFBUF tristate "STMicroelectronics STM32 VREFBUF" depends on ARCH_STM32 || COMPILE_TEST diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 93f53840e8f1..eef73b5a35a4 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_88PG86X) += 88pg86x.o -obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o +obj-$(CONFIG_REGULATOR_88PM800) += 88pm800-regulator.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_CPCAP) += cpcap-regulator.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o @@ -104,6 +104,8 @@ obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o +obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o +obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index e4bc7b1e5ccd..1a3d7b720f5e 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -25,6 +25,10 @@ #include <linux/mfd/arizona/pdata.h> #include <linux/mfd/arizona/registers.h> +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/pdata.h> +#include <linux/mfd/madera/registers.h> + struct arizona_ldo1 { struct regulator_dev *regulator; struct regmap *regmap; @@ -158,6 +162,31 @@ static const struct regulator_init_data arizona_ldo1_wm5110 = { .num_consumer_supplies = 1, }; +static const struct regulator_desc madera_ldo1 = { + .name = "LDO1", + .supply_name = "LDOVDD", + .type = REGULATOR_VOLTAGE, + .ops = &arizona_ldo1_ops, + + .vsel_reg = MADERA_LDO1_CONTROL_1, + .vsel_mask = MADERA_LDO1_VSEL_MASK, + .min_uV = 900000, + .uV_step = 25000, + .n_voltages = 13, + .enable_time = 3000, + + .owner = THIS_MODULE, +}; + +static const struct regulator_init_data madera_ldo1_default = { + .constraints = { + .min_uV = 1200000, + .max_uV = 1200000, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, +}; + static int arizona_ldo1_of_get_pdata(struct arizona_ldo1_pdata *pdata, struct regulator_config *config, const struct regulator_desc *desc, @@ -320,6 +349,32 @@ static int arizona_ldo1_remove(struct platform_device *pdev) return 0; } +static int madera_ldo1_probe(struct platform_device *pdev) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + struct arizona_ldo1 *ldo1; + bool external_dcvdd; + int ret; + + ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL); + if (!ldo1) + return -ENOMEM; + + ldo1->regmap = madera->regmap; + + ldo1->init_data = madera_ldo1_default; + + ret = arizona_ldo1_common_init(pdev, ldo1, &madera_ldo1, + &madera->pdata.ldo1, + &external_dcvdd); + if (ret) + return ret; + + madera->internal_dcvdd = !external_dcvdd; + + return 0; +} + static struct platform_driver arizona_ldo1_driver = { .probe = arizona_ldo1_probe, .remove = arizona_ldo1_remove, @@ -328,10 +383,36 @@ static struct platform_driver arizona_ldo1_driver = { }, }; -module_platform_driver(arizona_ldo1_driver); +static struct platform_driver madera_ldo1_driver = { + .probe = madera_ldo1_probe, + .remove = arizona_ldo1_remove, + .driver = { + .name = "madera-ldo1", + }, +}; + +static struct platform_driver * const madera_ldo1_drivers[] = { + &arizona_ldo1_driver, + &madera_ldo1_driver, +}; + +static int __init arizona_ldo1_init(void) +{ + return platform_register_drivers(madera_ldo1_drivers, + ARRAY_SIZE(madera_ldo1_drivers)); +} +module_init(arizona_ldo1_init); + +static void __exit madera_ldo1_exit(void) +{ + platform_unregister_drivers(madera_ldo1_drivers, + ARRAY_SIZE(madera_ldo1_drivers)); +} +module_exit(madera_ldo1_exit); /* Module information */ MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_DESCRIPTION("Arizona LDO1 driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:arizona-ldo1"); +MODULE_ALIAS("platform:madera-ldo1"); diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index be0d46da51a1..ae1a5de3e57d 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -16,7 +16,6 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> -#include <linux/gpio.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <sound/soc.h> @@ -25,6 +24,10 @@ #include <linux/mfd/arizona/pdata.h> #include <linux/mfd/arizona/registers.h> +#include <linux/mfd/madera/core.h> +#include <linux/mfd/madera/pdata.h> +#include <linux/mfd/madera/registers.h> + #include <linux/regulator/arizona-micsupp.h> struct arizona_micsupp { @@ -200,6 +203,28 @@ static const struct regulator_init_data arizona_micsupp_ext_default = { .num_consumer_supplies = 1, }; +static const struct regulator_desc madera_micsupp = { + .name = "MICVDD", + .supply_name = "CPVDD1", + .type = REGULATOR_VOLTAGE, + .n_voltages = 40, + .ops = &arizona_micsupp_ops, + + .vsel_reg = MADERA_LDO2_CONTROL_1, + .vsel_mask = MADERA_LDO2_VSEL_MASK, + .enable_reg = MADERA_MIC_CHARGE_PUMP_1, + .enable_mask = MADERA_CPMIC_ENA, + .bypass_reg = MADERA_MIC_CHARGE_PUMP_1, + .bypass_mask = MADERA_CPMIC_BYPASS, + + .linear_ranges = arizona_micsupp_ext_ranges, + .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges), + + .enable_time = 3000, + + .owner = THIS_MODULE, +}; + static int arizona_micsupp_of_get_pdata(struct arizona_micsupp_pdata *pdata, struct regulator_config *config, const struct regulator_desc *desc) @@ -316,6 +341,24 @@ static int arizona_micsupp_probe(struct platform_device *pdev) &arizona->pdata.micvdd); } +static int madera_micsupp_probe(struct platform_device *pdev) +{ + struct madera *madera = dev_get_drvdata(pdev->dev.parent); + struct arizona_micsupp *micsupp; + + micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL); + if (!micsupp) + return -ENOMEM; + + micsupp->regmap = madera->regmap; + micsupp->dapm = &madera->dapm; + micsupp->dev = madera->dev; + micsupp->init_data = arizona_micsupp_ext_default; + + return arizona_micsupp_common_init(pdev, micsupp, &madera_micsupp, + &madera->pdata.micvdd); +} + static struct platform_driver arizona_micsupp_driver = { .probe = arizona_micsupp_probe, .driver = { @@ -323,10 +366,35 @@ static struct platform_driver arizona_micsupp_driver = { }, }; -module_platform_driver(arizona_micsupp_driver); +static struct platform_driver madera_micsupp_driver = { + .probe = madera_micsupp_probe, + .driver = { + .name = "madera-micsupp", + }, +}; + +static struct platform_driver * const arizona_micsupp_drivers[] = { + &arizona_micsupp_driver, + &madera_micsupp_driver, +}; + +static int __init arizona_micsupp_init(void) +{ + return platform_register_drivers(arizona_micsupp_drivers, + ARRAY_SIZE(arizona_micsupp_drivers)); +} +module_init(arizona_micsupp_init); + +static void __exit arizona_micsupp_exit(void) +{ + platform_unregister_drivers(arizona_micsupp_drivers, + ARRAY_SIZE(arizona_micsupp_drivers)); +} +module_exit(arizona_micsupp_exit); /* Module information */ MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_DESCRIPTION("Arizona microphone supply driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:arizona-micsupp"); +MODULE_ALIAS("platform:madera-micsupp"); diff --git a/drivers/regulator/bd70528-regulator.c b/drivers/regulator/bd70528-regulator.c index 30e3ed430a8a..0248a61f1006 100644 --- a/drivers/regulator/bd70528-regulator.c +++ b/drivers/regulator/bd70528-regulator.c @@ -4,7 +4,6 @@ #include <linux/delay.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/mfd/rohm-bd70528.h> diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index fde4264da6ff..8c22cfb76173 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -4,7 +4,6 @@ #include <linux/delay.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/mfd/rohm-bd718x7.h> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c894cf0d8a28..86ae1825cec1 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1,12 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* - * core.c -- Voltage/Current Regulator framework. - * - * Copyright 2007, 2008 Wolfson Microelectronics PLC. - * Copyright 2008 SlimLogic Ltd. - * - * Author: Liam Girdwood <lrg@slimlogic.co.uk> - */ +// +// core.c -- Voltage/Current Regulator framework. +// +// Copyright 2007, 2008 Wolfson Microelectronics PLC. +// Copyright 2008 SlimLogic Ltd. +// +// Author: Liam Girdwood <lrg@slimlogic.co.uk> #include <linux/kernel.h> #include <linux/init.h> @@ -23,6 +22,7 @@ #include <linux/regmap.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/consumer.h> +#include <linux/regulator/coupler.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/module.h> @@ -50,6 +50,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); +static LIST_HEAD(regulator_coupler_list); static bool has_full_constraints; static struct dentry *debugfs_root; @@ -93,7 +94,6 @@ struct regulator_supply_alias { static int _regulator_is_enabled(struct regulator_dev *rdev); static int _regulator_disable(struct regulator *regulator); -static int _regulator_get_voltage(struct regulator_dev *rdev); static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); static int _notifier_call_chain(struct regulator_dev *rdev, @@ -102,15 +102,12 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV); static int regulator_balance_voltage(struct regulator_dev *rdev, suspend_state_t state); -static int regulator_set_voltage_rdev(struct regulator_dev *rdev, - int min_uV, int max_uV, - suspend_state_t state); static struct regulator *create_regulator(struct regulator_dev *rdev, struct device *dev, const char *supply_name); static void _regulator_put(struct regulator *regulator); -static const char *rdev_get_name(struct regulator_dev *rdev) +const char *rdev_get_name(struct regulator_dev *rdev) { if (rdev->constraints && rdev->constraints->name) return rdev->constraints->name; @@ -424,8 +421,8 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp } /* Platform voltage constraint check */ -static int regulator_check_voltage(struct regulator_dev *rdev, - int *min_uV, int *max_uV) +int regulator_check_voltage(struct regulator_dev *rdev, + int *min_uV, int *max_uV) { BUG_ON(*min_uV > *max_uV); @@ -457,9 +454,9 @@ static int regulator_check_states(suspend_state_t state) /* Make sure we select a voltage that suits the needs of all * regulator consumers */ -static int regulator_check_consumers(struct regulator_dev *rdev, - int *min_uV, int *max_uV, - suspend_state_t state) +int regulator_check_consumers(struct regulator_dev *rdev, + int *min_uV, int *max_uV, + suspend_state_t state) { struct regulator *regulator; struct regulator_voltage *voltage; @@ -570,7 +567,7 @@ static ssize_t regulator_uV_show(struct device *dev, ssize_t ret; regulator_lock(rdev); - ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev)); + ret = sprintf(buf, "%d\n", regulator_get_voltage_rdev(rdev)); regulator_unlock(rdev); return ret; @@ -941,7 +938,7 @@ static int drms_uA_update(struct regulator_dev *rdev) rdev_err(rdev, "failed to set load %d\n", current_uA); } else { /* get output voltage */ - output_uV = _regulator_get_voltage(rdev); + output_uV = regulator_get_voltage_rdev(rdev); if (output_uV <= 0) { rdev_err(rdev, "invalid output voltage found\n"); return -EINVAL; @@ -1054,7 +1051,7 @@ static void print_constraints(struct regulator_dev *rdev) if (!constraints->min_uV || constraints->min_uV != constraints->max_uV) { - ret = _regulator_get_voltage(rdev); + ret = regulator_get_voltage_rdev(rdev); if (ret > 0) count += scnprintf(buf + count, len - count, "at %d mV ", ret / 1000); @@ -1113,7 +1110,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, if (rdev->constraints->apply_uV && rdev->constraints->min_uV && rdev->constraints->max_uV) { int target_min, target_max; - int current_uV = _regulator_get_voltage(rdev); + int current_uV = regulator_get_voltage_rdev(rdev); if (current_uV == -ENOTRECOVERABLE) { /* This regulator can't be read and must be initialized */ @@ -1123,7 +1120,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, _regulator_do_set_voltage(rdev, rdev->constraints->min_uV, rdev->constraints->max_uV); - current_uV = _regulator_get_voltage(rdev); + current_uV = regulator_get_voltage_rdev(rdev); } if (current_uV < 0) { @@ -1645,9 +1642,9 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev) { if (rdev->constraints && rdev->constraints->enable_time) return rdev->constraints->enable_time; - if (!rdev->desc->ops->enable_time) - return rdev->desc->enable_time; - return rdev->desc->ops->enable_time(rdev); + if (rdev->desc->ops->enable_time) + return rdev->desc->ops->enable_time(rdev); + return rdev->desc->enable_time; } static struct regulator_supply_alias *regulator_find_supply_alias( @@ -3065,7 +3062,7 @@ static int _regulator_call_set_voltage(struct regulator_dev *rdev, struct pre_voltage_change_data data; int ret; - data.old_uV = _regulator_get_voltage(rdev); + data.old_uV = regulator_get_voltage_rdev(rdev); data.min_uV = min_uV; data.max_uV = max_uV; ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, @@ -3089,7 +3086,7 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, struct pre_voltage_change_data data; int ret; - data.old_uV = _regulator_get_voltage(rdev); + data.old_uV = regulator_get_voltage_rdev(rdev); data.min_uV = uV; data.max_uV = uV; ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, @@ -3107,6 +3104,66 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, return ret; } +static int _regulator_set_voltage_sel_step(struct regulator_dev *rdev, + int uV, int new_selector) +{ + const struct regulator_ops *ops = rdev->desc->ops; + int diff, old_sel, curr_sel, ret; + + /* Stepping is only needed if the regulator is enabled. */ + if (!_regulator_is_enabled(rdev)) + goto final_set; + + if (!ops->get_voltage_sel) + return -EINVAL; + + old_sel = ops->get_voltage_sel(rdev); + if (old_sel < 0) + return old_sel; + + diff = new_selector - old_sel; + if (diff == 0) + return 0; /* No change needed. */ + + if (diff > 0) { + /* Stepping up. */ + for (curr_sel = old_sel + rdev->desc->vsel_step; + curr_sel < new_selector; + curr_sel += rdev->desc->vsel_step) { + /* + * Call the callback directly instead of using + * _regulator_call_set_voltage_sel() as we don't + * want to notify anyone yet. Same in the branch + * below. + */ + ret = ops->set_voltage_sel(rdev, curr_sel); + if (ret) + goto try_revert; + } + } else { + /* Stepping down. */ + for (curr_sel = old_sel - rdev->desc->vsel_step; + curr_sel > new_selector; + curr_sel -= rdev->desc->vsel_step) { + ret = ops->set_voltage_sel(rdev, curr_sel); + if (ret) + goto try_revert; + } + } + +final_set: + /* The final selector will trigger the notifiers. */ + return _regulator_call_set_voltage_sel(rdev, uV, new_selector); + +try_revert: + /* + * At least try to return to the previous voltage if setting a new + * one failed. + */ + (void)ops->set_voltage_sel(rdev, old_sel); + return ret; +} + static int _regulator_set_voltage_time(struct regulator_dev *rdev, int old_uV, int new_uV) { @@ -3142,7 +3199,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, unsigned int selector; int old_selector = -1; const struct regulator_ops *ops = rdev->desc->ops; - int old_uV = _regulator_get_voltage(rdev); + int old_uV = regulator_get_voltage_rdev(rdev); trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); @@ -3169,7 +3226,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, best_val = ops->list_voltage(rdev, selector); else - best_val = _regulator_get_voltage(rdev); + best_val = regulator_get_voltage_rdev(rdev); } } else if (ops->set_voltage_sel) { @@ -3180,6 +3237,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, selector = ret; if (old_selector == selector) ret = 0; + else if (rdev->desc->vsel_step) + ret = _regulator_set_voltage_sel_step( + rdev, best_val, selector); else ret = _regulator_call_set_voltage_sel( rdev, best_val, selector); @@ -3288,7 +3348,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, * changing the voltage. */ if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { - current_uV = _regulator_get_voltage(rdev); + current_uV = regulator_get_voltage_rdev(rdev); if (min_uV <= current_uV && current_uV <= max_uV) { voltage->min_uV = min_uV; voltage->max_uV = max_uV; @@ -3325,8 +3385,8 @@ out: return ret; } -static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, - int max_uV, suspend_state_t state) +int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, + int max_uV, suspend_state_t state) { int best_supply_uV = 0; int supply_change_uV = 0; @@ -3354,7 +3414,7 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, best_supply_uV += rdev->desc->min_dropout_uV; - current_supply_uV = _regulator_get_voltage(rdev->supply->rdev); + current_supply_uV = regulator_get_voltage_rdev(rdev->supply->rdev); if (current_supply_uV < 0) { ret = current_supply_uV; goto out; @@ -3405,7 +3465,7 @@ static int regulator_limit_voltage_step(struct regulator_dev *rdev, return 1; if (*current_uV < 0) { - *current_uV = _regulator_get_voltage(rdev); + *current_uV = regulator_get_voltage_rdev(rdev); if (*current_uV < 0) return *current_uV; @@ -3434,11 +3494,10 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, struct coupling_desc *c_desc = &rdev->coupling_desc; struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; struct regulation_constraints *constraints = rdev->constraints; - int max_spread = constraints->max_spread; int desired_min_uV = 0, desired_max_uV = INT_MAX; int max_current_uV = 0, min_current_uV = INT_MAX; int highest_min_uV = 0, target_uV, possible_uV; - int i, ret; + int i, ret, max_spread; bool done; *current_uV = -1; @@ -3492,6 +3551,8 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, } } + max_spread = constraints->max_spread[0]; + /* * Let target_uV be equal to the desired one if possible. * If not, set it to minimum voltage, allowed by other coupled @@ -3509,7 +3570,7 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, if (!_regulator_is_enabled(c_rdevs[i])) continue; - tmp_act = _regulator_get_voltage(c_rdevs[i]); + tmp_act = regulator_get_voltage_rdev(c_rdevs[i]); if (tmp_act < 0) return tmp_act; @@ -3551,7 +3612,7 @@ finish: if (n_coupled > 1 && *current_uV == -1) { if (_regulator_is_enabled(rdev)) { - ret = _regulator_get_voltage(rdev); + ret = regulator_get_voltage_rdev(rdev); if (ret < 0) return ret; @@ -3573,9 +3634,11 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, struct regulator_dev **c_rdevs; struct regulator_dev *best_rdev; struct coupling_desc *c_desc = &rdev->coupling_desc; + struct regulator_coupler *coupler = c_desc->coupler; int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev; - bool best_c_rdev_done, c_rdev_done[MAX_COUPLED]; unsigned int delta, best_delta; + unsigned long c_rdev_done = 0; + bool best_c_rdev_done; c_rdevs = c_desc->coupled_rdevs; n_coupled = c_desc->n_coupled; @@ -3592,8 +3655,9 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, return -EPERM; } - for (i = 0; i < n_coupled; i++) - c_rdev_done[i] = false; + /* Invoke custom balancer for customized couplers */ + if (coupler && coupler->balance_voltage) + return coupler->balance_voltage(coupler, rdev, state); /* * Find the best possible voltage change on each loop. Leave the loop @@ -3620,7 +3684,7 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, */ int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0; - if (c_rdev_done[i]) + if (test_bit(i, &c_rdev_done)) continue; ret = regulator_get_optimal_voltage(c_rdevs[i], @@ -3655,7 +3719,8 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, if (ret < 0) goto out; - c_rdev_done[best_c_rdev] = best_c_rdev_done; + if (best_c_rdev_done) + set_bit(best_c_rdev, &c_rdev_done); } while (n_coupled > 1); @@ -3911,7 +3976,7 @@ out: } EXPORT_SYMBOL_GPL(regulator_sync_voltage); -static int _regulator_get_voltage(struct regulator_dev *rdev) +int regulator_get_voltage_rdev(struct regulator_dev *rdev) { int sel, ret; bool bypassed; @@ -3928,7 +3993,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) return -EPROBE_DEFER; } - return _regulator_get_voltage(rdev->supply->rdev); + return regulator_get_voltage_rdev(rdev->supply->rdev); } } @@ -3944,7 +4009,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { ret = rdev->desc->fixed_uV; } else if (rdev->supply) { - ret = _regulator_get_voltage(rdev->supply->rdev); + ret = regulator_get_voltage_rdev(rdev->supply->rdev); } else { return -EINVAL; } @@ -3969,7 +4034,7 @@ int regulator_get_voltage(struct regulator *regulator) int ret; regulator_lock_dependent(regulator->rdev, &ww_ctx); - ret = _regulator_get_voltage(regulator->rdev); + ret = regulator_get_voltage_rdev(regulator->rdev); regulator_unlock_dependent(regulator->rdev, &ww_ctx); return ret; @@ -4707,8 +4772,60 @@ static int regulator_register_resolve_supply(struct device *dev, void *data) return 0; } +int regulator_coupler_register(struct regulator_coupler *coupler) +{ + mutex_lock(®ulator_list_mutex); + list_add_tail(&coupler->list, ®ulator_coupler_list); + mutex_unlock(®ulator_list_mutex); + + return 0; +} + +static struct regulator_coupler * +regulator_find_coupler(struct regulator_dev *rdev) +{ + struct regulator_coupler *coupler; + int err; + + /* + * Note that regulators are appended to the list and the generic + * coupler is registered first, hence it will be attached at last + * if nobody cared. + */ + list_for_each_entry_reverse(coupler, ®ulator_coupler_list, list) { + err = coupler->attach_regulator(coupler, rdev); + if (!err) { + if (!coupler->balance_voltage && + rdev->coupling_desc.n_coupled > 2) + goto err_unsupported; + + return coupler; + } + + if (err < 0) + return ERR_PTR(err); + + if (err == 1) + continue; + + break; + } + + return ERR_PTR(-EINVAL); + +err_unsupported: + if (coupler->detach_regulator) + coupler->detach_regulator(coupler, rdev); + + rdev_err(rdev, + "Voltage balancing for multiple regulator couples is unimplemented\n"); + + return ERR_PTR(-EPERM); +} + static void regulator_resolve_coupling(struct regulator_dev *rdev) { + struct regulator_coupler *coupler = rdev->coupling_desc.coupler; struct coupling_desc *c_desc = &rdev->coupling_desc; int n_coupled = c_desc->n_coupled; struct regulator_dev *c_rdev; @@ -4724,6 +4841,12 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev) if (!c_rdev) continue; + if (c_rdev->coupling_desc.coupler != coupler) { + rdev_err(rdev, "coupler mismatch with %s\n", + rdev_get_name(c_rdev)); + return; + } + regulator_lock(c_rdev); c_desc->coupled_rdevs[i] = c_rdev; @@ -4737,10 +4860,12 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev) static void regulator_remove_coupling(struct regulator_dev *rdev) { + struct regulator_coupler *coupler = rdev->coupling_desc.coupler; struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc; struct regulator_dev *__c_rdev, *c_rdev; unsigned int __n_coupled, n_coupled; int i, k; + int err; n_coupled = c_desc->n_coupled; @@ -4770,21 +4895,33 @@ static void regulator_remove_coupling(struct regulator_dev *rdev) c_desc->coupled_rdevs[i] = NULL; c_desc->n_resolved--; } + + if (coupler && coupler->detach_regulator) { + err = coupler->detach_regulator(coupler, rdev); + if (err) + rdev_err(rdev, "failed to detach from coupler: %d\n", + err); + } + + kfree(rdev->coupling_desc.coupled_rdevs); + rdev->coupling_desc.coupled_rdevs = NULL; } static int regulator_init_coupling(struct regulator_dev *rdev) { - int n_phandles; + int err, n_phandles; + size_t alloc_size; if (!IS_ENABLED(CONFIG_OF)) n_phandles = 0; else n_phandles = of_get_n_coupled(rdev); - if (n_phandles + 1 > MAX_COUPLED) { - rdev_err(rdev, "too many regulators coupled\n"); - return -EPERM; - } + alloc_size = sizeof(*rdev) * (n_phandles + 1); + + rdev->coupling_desc.coupled_rdevs = kzalloc(alloc_size, GFP_KERNEL); + if (!rdev->coupling_desc.coupled_rdevs) + return -ENOMEM; /* * Every regulator should always have coupling descriptor filled with @@ -4798,23 +4935,35 @@ static int regulator_init_coupling(struct regulator_dev *rdev) if (n_phandles == 0) return 0; - /* regulator, which can't change its voltage, can't be coupled */ - if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { - rdev_err(rdev, "voltage operation not allowed\n"); + if (!of_check_coupling_data(rdev)) return -EPERM; - } - if (rdev->constraints->max_spread <= 0) { - rdev_err(rdev, "wrong max_spread value\n"); - return -EPERM; + rdev->coupling_desc.coupler = regulator_find_coupler(rdev); + if (IS_ERR(rdev->coupling_desc.coupler)) { + err = PTR_ERR(rdev->coupling_desc.coupler); + rdev_err(rdev, "failed to get coupler: %d\n", err); + return err; } - if (!of_check_coupling_data(rdev)) + return 0; +} + +static int generic_coupler_attach(struct regulator_coupler *coupler, + struct regulator_dev *rdev) +{ + if (rdev->coupling_desc.n_coupled > 2) { + rdev_err(rdev, + "Voltage balancing for multiple regulator couples is unimplemented\n"); return -EPERM; + } return 0; } +static struct regulator_coupler generic_regulator_coupler = { + .attach_regulator = generic_coupler_attach, +}; + /** * regulator_register - register regulator * @regulator_desc: regulator to register @@ -4976,7 +5125,9 @@ regulator_register(const struct regulator_desc *regulator_desc, if (ret < 0) goto wash; + mutex_lock(®ulator_list_mutex); ret = regulator_init_coupling(rdev); + mutex_unlock(®ulator_list_mutex); if (ret < 0) goto wash; @@ -5025,6 +5176,7 @@ regulator_register(const struct regulator_desc *regulator_desc, unset_supplies: mutex_lock(®ulator_list_mutex); unset_regulator_supplies(rdev); + regulator_remove_coupling(rdev); mutex_unlock(®ulator_list_mutex); wash: kfree(rdev->constraints); @@ -5278,7 +5430,7 @@ static void regulator_summary_show_subtree(struct seq_file *s, rdev->use_count, rdev->open_count, rdev->bypass_count, regulator_opmode_to_str(opmode)); - seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000); + seq_printf(s, "%5dmV ", regulator_get_voltage_rdev(rdev) / 1000); seq_printf(s, "%5dmA ", _regulator_get_current_limit_unlocked(rdev) / 1000); @@ -5480,6 +5632,8 @@ static int __init regulator_init(void) #endif regulator_dummy_init(); + regulator_coupler_register(&generic_regulator_coupler); + return ret; } diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index d3284361e594..f80781d58a28 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -90,7 +90,7 @@ #define CPCAP_REG_OFF_MODE_SEC BIT(15) /** - * SoC specific configuraion for CPCAP regulator. There are at least three + * SoC specific configuration for CPCAP regulator. There are at least three * different SoCs each with their own parameters: omap3, omap4 and tegra2. * * The assign_reg and assign_mask seem to allow toggling between primary diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c index a02e0488410f..2ffc64622451 100644 --- a/drivers/regulator/da9062-regulator.c +++ b/drivers/regulator/da9062-regulator.c @@ -493,12 +493,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO1_CONT, .desc.enable_mask = DA9062AA_LDO1_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO1_A, .desc.vsel_mask = DA9062AA_VLDO1_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO1_A, __builtin_ffs((int)DA9062AA_LDO1_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -525,12 +526,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (600))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO2_CONT, .desc.enable_mask = DA9062AA_LDO2_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO2_A, .desc.vsel_mask = DA9062AA_VLDO2_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO2_A, __builtin_ffs((int)DA9062AA_LDO2_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -557,12 +559,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO3_CONT, .desc.enable_mask = DA9062AA_LDO3_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO3_A, .desc.vsel_mask = DA9062AA_VLDO3_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO3_A, __builtin_ffs((int)DA9062AA_LDO3_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -589,12 +592,13 @@ static const struct da9062_regulator_info local_da9061_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO4_CONT, .desc.enable_mask = DA9062AA_LDO4_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO4_A, .desc.vsel_mask = DA9062AA_VLDO4_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO4_A, __builtin_ffs((int)DA9062AA_LDO4_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -769,12 +773,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO1_CONT, .desc.enable_mask = DA9062AA_LDO1_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO1_A, .desc.vsel_mask = DA9062AA_VLDO1_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO1_A, __builtin_ffs((int)DA9062AA_LDO1_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -801,12 +806,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (600))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO2_CONT, .desc.enable_mask = DA9062AA_LDO2_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO2_A, .desc.vsel_mask = DA9062AA_VLDO2_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO2_A, __builtin_ffs((int)DA9062AA_LDO2_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -833,12 +839,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO3_CONT, .desc.enable_mask = DA9062AA_LDO3_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO3_A, .desc.vsel_mask = DA9062AA_VLDO3_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO3_A, __builtin_ffs((int)DA9062AA_LDO3_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - @@ -865,12 +872,13 @@ static const struct da9062_regulator_info local_da9062_regulator_info[] = { .desc.ops = &da9062_ldo_ops, .desc.min_uV = (900) * 1000, .desc.uV_step = (50) * 1000, - .desc.n_voltages = ((3600) - (900))/(50) + 1, + .desc.n_voltages = ((3600) - (900))/(50) + 1 + + DA9062AA_VLDO_A_MIN_SEL, .desc.enable_reg = DA9062AA_LDO4_CONT, .desc.enable_mask = DA9062AA_LDO4_EN_MASK, .desc.vsel_reg = DA9062AA_VLDO4_A, .desc.vsel_mask = DA9062AA_VLDO4_A_MASK, - .desc.linear_min_sel = 0, + .desc.linear_min_sel = DA9062AA_VLDO_A_MIN_SEL, .sleep = REG_FIELD(DA9062AA_VLDO4_A, __builtin_ffs((int)DA9062AA_LDO4_SL_A_MASK) - 1, sizeof(unsigned int) * 8 - diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 6f9ce1a6e44d..02f816318fba 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -19,7 +19,6 @@ #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/mfd/da9063/core.h> -#include <linux/mfd/da9063/pdata.h> #include <linux/mfd/da9063/registers.h> @@ -28,6 +27,49 @@ REG_FIELD(_reg, __builtin_ffs((int)_mask) - 1, \ sizeof(unsigned int) * 8 - __builtin_clz((_mask)) - 1) +/* DA9063 and DA9063L regulator IDs */ +enum { + /* BUCKs */ + DA9063_ID_BCORE1, + DA9063_ID_BCORE2, + DA9063_ID_BPRO, + DA9063_ID_BMEM, + DA9063_ID_BIO, + DA9063_ID_BPERI, + + /* BCORE1 and BCORE2 in merged mode */ + DA9063_ID_BCORES_MERGED, + /* BMEM and BIO in merged mode */ + DA9063_ID_BMEM_BIO_MERGED, + /* When two BUCKs are merged, they cannot be reused separately */ + + /* LDOs on both DA9063 and DA9063L */ + DA9063_ID_LDO3, + DA9063_ID_LDO7, + DA9063_ID_LDO8, + DA9063_ID_LDO9, + DA9063_ID_LDO11, + + /* DA9063-only LDOs */ + DA9063_ID_LDO1, + DA9063_ID_LDO2, + DA9063_ID_LDO4, + DA9063_ID_LDO5, + DA9063_ID_LDO6, + DA9063_ID_LDO10, +}; + +/* Old regulator platform data */ +struct da9063_regulator_data { + int id; + struct regulator_init_data *initdata; +}; + +struct da9063_regulators_pdata { + unsigned n_regulators; + struct da9063_regulator_data *regulator_data; +}; + /* Regulator capabilities and registers description */ struct da9063_regulator_info { struct regulator_desc desc; @@ -592,7 +634,6 @@ static const struct regulator_init_data *da9063_get_regulator_initdata( return NULL; } -#ifdef CONFIG_OF static struct of_regulator_match da9063_matches[] = { [DA9063_ID_BCORE1] = { .name = "bcore1" }, [DA9063_ID_BCORE2] = { .name = "bcore2" }, @@ -670,20 +711,10 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( *da9063_reg_matches = da9063_matches; return pdata; } -#else -static struct da9063_regulators_pdata *da9063_parse_regulators_dt( - struct platform_device *pdev, - struct of_regulator_match **da9063_reg_matches) -{ - *da9063_reg_matches = NULL; - return ERR_PTR(-ENODEV); -} -#endif static int da9063_regulator_probe(struct platform_device *pdev) { struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); - struct da9063_pdata *da9063_pdata = dev_get_platdata(da9063->dev); struct of_regulator_match *da9063_reg_matches = NULL; struct da9063_regulators_pdata *regl_pdata; const struct da9063_dev_model *model; @@ -693,11 +724,7 @@ static int da9063_regulator_probe(struct platform_device *pdev) bool bcores_merged, bmem_bio_merged; int id, irq, n, n_regulators, ret, val; - regl_pdata = da9063_pdata ? da9063_pdata->regulators_pdata : NULL; - - if (!regl_pdata) - regl_pdata = da9063_parse_regulators_dt(pdev, - &da9063_reg_matches); + regl_pdata = da9063_parse_regulators_dt(pdev, &da9063_reg_matches); if (IS_ERR(regl_pdata) || regl_pdata->n_regulators == 0) { dev_err(&pdev->dev, diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index da37b4ccd834..0309823d2c72 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -289,6 +289,8 @@ static struct da9211_pdata *da9211_parse_regulators_dt( 0, GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, "da9211-enable"); + if (IS_ERR(pdata->gpiod_ren[n])) + pdata->gpiod_ren[n] = NULL; n++; } diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index b9ae45d2d199..4986cc5064a1 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -1,10 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* - * helpers.c -- Voltage/Current Regulator framework helper functions. - * - * Copyright 2007, 2008 Wolfson Microelectronics PLC. - * Copyright 2008 SlimLogic Ltd. - */ +// +// helpers.c -- Voltage/Current Regulator framework helper functions. +// +// Copyright 2007, 2008 Wolfson Microelectronics PLC. +// Copyright 2008 SlimLogic Ltd. #include <linux/kernel.h> #include <linux/err.h> diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index 0db367b54ae7..8d9731e4052b 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -467,7 +467,7 @@ static int max77620_regulator_is_enabled(struct regulator_dev *rdev) { struct max77620_regulator *pmic = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); - int ret = 1; + int ret; if (pmic->active_fps_src[id] != MAX77620_FPS_SRC_NONE) return 1; @@ -758,6 +758,24 @@ static struct max77620_regulator_info max20024_regs_info[MAX77620_NUM_REGS] = { RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), }; +static struct max77620_regulator_info max77663_regs_info[MAX77620_NUM_REGS] = { + RAIL_SD(SD0, sd0, "in-sd0", SD0, 600000, 3387500, 12500, 0xFF, NONE), + RAIL_SD(SD1, sd1, "in-sd1", SD1, 800000, 1587500, 12500, 0xFF, NONE), + RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE), + RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE), + RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE), + + RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000), + RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000), + RAIL_LDO(LDO2, ldo2, "in-ldo2", P, 800000, 3950000, 50000), + RAIL_LDO(LDO3, ldo3, "in-ldo3-5", P, 800000, 3950000, 50000), + RAIL_LDO(LDO4, ldo4, "in-ldo4-6", P, 800000, 1587500, 12500), + RAIL_LDO(LDO5, ldo5, "in-ldo3-5", P, 800000, 3950000, 50000), + RAIL_LDO(LDO6, ldo6, "in-ldo4-6", P, 800000, 3950000, 50000), + RAIL_LDO(LDO7, ldo7, "in-ldo7-8", N, 800000, 3950000, 50000), + RAIL_LDO(LDO8, ldo8, "in-ldo7-8", N, 800000, 3950000, 50000), +}; + static int max77620_regulator_probe(struct platform_device *pdev) { struct max77620_chip *max77620_chip = dev_get_drvdata(pdev->dev.parent); @@ -782,9 +800,14 @@ static int max77620_regulator_probe(struct platform_device *pdev) case MAX77620: rinfo = max77620_regs_info; break; - default: + case MAX20024: rinfo = max20024_regs_info; break; + case MAX77663: + rinfo = max77663_regs_info; + break; + default: + return -EINVAL; } config.regmap = pmic->rmap; @@ -878,6 +901,7 @@ static const struct dev_pm_ops max77620_regulator_pm_ops = { static const struct platform_device_id max77620_regulator_devtype[] = { { .name = "max77620-pmic", }, { .name = "max20024-pmic", }, + { .name = "max77663-pmic", }, {}, }; MODULE_DEVICE_TABLE(platform, max77620_regulator_devtype); diff --git a/drivers/regulator/max77650-regulator.c b/drivers/regulator/max77650-regulator.c index 5c4f86c98510..e57fc9197d62 100644 --- a/drivers/regulator/max77650-regulator.c +++ b/drivers/regulator/max77650-regulator.c @@ -20,6 +20,8 @@ #define MAX77650_REGULATOR_V_LDO_MASK GENMASK(6, 0) #define MAX77650_REGULATOR_V_SBB_MASK GENMASK(5, 0) +#define MAX77651_REGULATOR_V_SBB1_MASK GENMASK(5, 2) +#define MAX77651_REGULATOR_V_SBB1_RANGE_MASK GENMASK(1, 0) #define MAX77650_REGULATOR_AD_MASK BIT(3) #define MAX77650_REGULATOR_AD_DISABLED 0x00 @@ -41,43 +43,22 @@ struct max77650_regulator_desc { unsigned int regB; }; -static const unsigned int max77651_sbb1_regulator_volt_table[] = { - 2400000, 3200000, 4000000, 4800000, - 2450000, 3250000, 4050000, 4850000, - 2500000, 3300000, 4100000, 4900000, - 2550000, 3350000, 4150000, 4950000, - 2600000, 3400000, 4200000, 5000000, - 2650000, 3450000, 4250000, 5050000, - 2700000, 3500000, 4300000, 5100000, - 2750000, 3550000, 4350000, 5150000, - 2800000, 3600000, 4400000, 5200000, - 2850000, 3650000, 4450000, 5250000, - 2900000, 3700000, 4500000, 0, - 2950000, 3750000, 4550000, 0, - 3000000, 3800000, 4600000, 0, - 3050000, 3850000, 4650000, 0, - 3100000, 3900000, 4700000, 0, - 3150000, 3950000, 4750000, 0, +static struct max77650_regulator_desc max77651_SBB1_desc; + +static const unsigned int max77651_sbb1_volt_range_sel[] = { + 0x0, 0x1, 0x2, 0x3 }; -#define MAX77651_REGULATOR_SBB1_SEL_DEC(_val) \ - (((_val & 0x3c) >> 2) | ((_val & 0x03) << 4)) -#define MAX77651_REGULATOR_SBB1_SEL_ENC(_val) \ - (((_val & 0x30) >> 4) | ((_val & 0x0f) << 2)) - -#define MAX77650_REGULATOR_SBB1_SEL_DECR(_val) \ - do { \ - _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \ - _val--; \ - _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \ - } while (0) - -#define MAX77650_REGULATOR_SBB1_SEL_INCR(_val) \ - do { \ - _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \ - _val++; \ - _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \ - } while (0) +static const struct regulator_linear_range max77651_sbb1_volt_ranges[] = { + /* range index 0 */ + REGULATOR_LINEAR_RANGE(2400000, 0x00, 0x0f, 50000), + /* range index 1 */ + REGULATOR_LINEAR_RANGE(3200000, 0x00, 0x0f, 50000), + /* range index 2 */ + REGULATOR_LINEAR_RANGE(4000000, 0x00, 0x0f, 50000), + /* range index 3 */ + REGULATOR_LINEAR_RANGE(4800000, 0x00, 0x09, 50000), +}; static const unsigned int max77650_current_limit_table[] = { 1000000, 866000, 707000, 500000, @@ -127,96 +108,6 @@ static int max77650_regulator_disable(struct regulator_dev *rdev) MAX77650_REGULATOR_DISABLED); } -static int max77650_regulator_set_voltage_sel(struct regulator_dev *rdev, - unsigned int sel) -{ - int rv = 0, curr, diff; - bool ascending; - - /* - * If the regulator is disabled, we can program the desired - * voltage right away. - */ - if (!max77650_regulator_is_enabled(rdev)) - return regulator_set_voltage_sel_regmap(rdev, sel); - - /* - * Otherwise we need to manually ramp the output voltage up/down - * one step at a time. - */ - - curr = regulator_get_voltage_sel_regmap(rdev); - if (curr < 0) - return curr; - - diff = curr - sel; - if (diff == 0) - return 0; /* Already there. */ - else if (diff > 0) - ascending = false; - else - ascending = true; - - /* - * Make sure we'll get to the right voltage and break the loop even if - * the selector equals 0. - */ - for (ascending ? curr++ : curr--;; ascending ? curr++ : curr--) { - rv = regulator_set_voltage_sel_regmap(rdev, curr); - if (rv) - return rv; - - if (curr == sel) - break; - } - - return 0; -} - -/* - * Special case: non-linear voltage table for max77651 SBB1 - software - * must ensure the voltage is ramped in 50mV increments. - */ -static int max77651_regulator_sbb1_set_voltage_sel(struct regulator_dev *rdev, - unsigned int sel) -{ - int rv = 0, curr, vcurr, vdest, vdiff; - - /* - * If the regulator is disabled, we can program the desired - * voltage right away. - */ - if (!max77650_regulator_is_enabled(rdev)) - return regulator_set_voltage_sel_regmap(rdev, sel); - - curr = regulator_get_voltage_sel_regmap(rdev); - if (curr < 0) - return curr; - - if (curr == sel) - return 0; /* Already there. */ - - vcurr = max77651_sbb1_regulator_volt_table[curr]; - vdest = max77651_sbb1_regulator_volt_table[sel]; - vdiff = vcurr - vdest; - - for (;;) { - if (vdiff > 0) - MAX77650_REGULATOR_SBB1_SEL_DECR(curr); - else - MAX77650_REGULATOR_SBB1_SEL_INCR(curr); - - rv = regulator_set_voltage_sel_regmap(rdev, curr); - if (rv) - return rv; - - if (curr == sel) - break; - }; - - return 0; -} - static const struct regulator_ops max77650_regulator_LDO_ops = { .is_enabled = max77650_regulator_is_enabled, .enable = max77650_regulator_enable, @@ -224,7 +115,7 @@ static const struct regulator_ops max77650_regulator_LDO_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = max77650_regulator_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_active_discharge = regulator_set_active_discharge_regmap, }; @@ -235,20 +126,20 @@ static const struct regulator_ops max77650_regulator_SBB_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = max77650_regulator_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_current_limit = regulator_get_current_limit_regmap, .set_current_limit = regulator_set_current_limit_regmap, .set_active_discharge = regulator_set_active_discharge_regmap, }; -/* Special case for max77651 SBB1 - non-linear voltage mapping. */ +/* Special case for max77651 SBB1 - pickable linear-range voltage mapping. */ static const struct regulator_ops max77651_SBB1_regulator_ops = { .is_enabled = max77650_regulator_is_enabled, .enable = max77650_regulator_enable, .disable = max77650_regulator_disable, - .list_voltage = regulator_list_voltage_table, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = max77651_regulator_sbb1_set_voltage_sel, + .list_voltage = regulator_list_voltage_pickable_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, + .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap, .get_current_limit = regulator_get_current_limit_regmap, .set_current_limit = regulator_set_current_limit_regmap, .set_active_discharge = regulator_set_active_discharge_regmap, @@ -265,6 +156,7 @@ static struct max77650_regulator_desc max77650_LDO_desc = { .min_uV = 1350000, .uV_step = 12500, .n_voltages = 128, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_LDO_MASK, .vsel_reg = MAX77650_REG_CNFG_LDO_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -290,6 +182,7 @@ static struct max77650_regulator_desc max77650_SBB0_desc = { .min_uV = 800000, .uV_step = 25000, .n_voltages = 64, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB0_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -319,6 +212,7 @@ static struct max77650_regulator_desc max77650_SBB1_desc = { .min_uV = 800000, .uV_step = 12500, .n_voltages = 64, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB1_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -345,9 +239,14 @@ static struct max77650_regulator_desc max77651_SBB1_desc = { .supply_name = "in-sbb1", .id = MAX77650_REGULATOR_ID_SBB1, .ops = &max77651_SBB1_regulator_ops, - .volt_table = max77651_sbb1_regulator_volt_table, - .n_voltages = ARRAY_SIZE(max77651_sbb1_regulator_volt_table), - .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, + .linear_range_selectors = max77651_sbb1_volt_range_sel, + .linear_ranges = max77651_sbb1_volt_ranges, + .n_linear_ranges = ARRAY_SIZE(max77651_sbb1_volt_ranges), + .n_voltages = 58, + .vsel_step = 1, + .vsel_range_mask = MAX77651_REGULATOR_V_SBB1_RANGE_MASK, + .vsel_range_reg = MAX77650_REG_CNFG_SBB1_A, + .vsel_mask = MAX77651_REGULATOR_V_SBB1_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB1_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED, @@ -376,6 +275,7 @@ static struct max77650_regulator_desc max77650_SBB2_desc = { .min_uV = 800000, .uV_step = 50000, .n_voltages = 64, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB2_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -405,6 +305,7 @@ static struct max77650_regulator_desc max77651_SBB2_desc = { .min_uV = 2400000, .uV_step = 50000, .n_voltages = 64, + .vsel_step = 1, .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, .vsel_reg = MAX77650_REG_CNFG_SBB2_A, .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, @@ -496,3 +397,4 @@ module_platform_driver(max77650_regulator_driver); MODULE_DESCRIPTION("MAXIM 77650/77651 regulator driver"); MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:max77650-regulator"); diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index ea7b50397300..7b8ec8c0bd15 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -14,9 +14,7 @@ #include <linux/kernel.h> #include <linux/bug.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/slab.h> -#include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 2a123b87d9f2..ccd5da63cdf2 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -13,11 +13,9 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/max8952.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/regulator/of_regulator.h> #include <linux/slab.h> @@ -37,7 +35,8 @@ enum { struct max8952_data { struct i2c_client *client; struct max8952_platform_data *pdata; - + struct gpio_desc *vid0_gpiod; + struct gpio_desc *vid1_gpiod; bool vid0; bool vid1; }; @@ -87,16 +86,15 @@ static int max8952_set_voltage_sel(struct regulator_dev *rdev, { struct max8952_data *max8952 = rdev_get_drvdata(rdev); - if (!gpio_is_valid(max8952->pdata->gpio_vid0) || - !gpio_is_valid(max8952->pdata->gpio_vid1)) { + if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) { /* DVS not supported */ return -EPERM; } max8952->vid0 = selector & 0x1; max8952->vid1 = (selector >> 1) & 0x1; - gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0); - gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1); + gpiod_set_value(max8952->vid0_gpiod, max8952->vid0); + gpiod_set_value(max8952->vid1_gpiod, max8952->vid1); return 0; } @@ -134,9 +132,6 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev) if (!pd) return NULL; - pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0); - pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1); - if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode)) dev_warn(dev, "Default mode not specified, assuming 0\n"); @@ -179,7 +174,7 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev) static int max8952_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct max8952_platform_data *pdata = dev_get_platdata(&client->dev); struct regulator_config config = { }; struct max8952_data *max8952; @@ -187,7 +182,7 @@ static int max8952_pmic_probe(struct i2c_client *client, struct gpio_desc *gpiod; enum gpiod_flags gflags; - int ret = 0, err = 0; + int ret = 0; if (client->dev.of_node) pdata = max8952_parse_dt(&client->dev); @@ -240,32 +235,31 @@ static int max8952_pmic_probe(struct i2c_client *client, max8952->vid0 = pdata->default_mode & 0x1; max8952->vid1 = (pdata->default_mode >> 1) & 0x1; - if (gpio_is_valid(pdata->gpio_vid0) && - gpio_is_valid(pdata->gpio_vid1)) { - unsigned long gpio_flags; - - gpio_flags = max8952->vid0 ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - if (devm_gpio_request_one(&client->dev, pdata->gpio_vid0, - gpio_flags, "MAX8952 VID0")) - err = 1; - - gpio_flags = max8952->vid1 ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - if (devm_gpio_request_one(&client->dev, pdata->gpio_vid1, - gpio_flags, "MAX8952 VID1")) - err = 2; - } else - err = 3; - - if (err) { + /* Fetch vid0 and vid1 GPIOs if available */ + gflags = max8952->vid0 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + max8952->vid0_gpiod = devm_gpiod_get_index_optional(&client->dev, + "max8952,vid", + 0, gflags); + if (IS_ERR(max8952->vid0_gpiod)) + return PTR_ERR(max8952->vid0_gpiod); + gflags = max8952->vid1 ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + max8952->vid1_gpiod = devm_gpiod_get_index_optional(&client->dev, + "max8952,vid", + 1, gflags); + if (IS_ERR(max8952->vid1_gpiod)) + return PTR_ERR(max8952->vid1_gpiod); + + /* If either VID GPIO is missing just disable this */ + if (!max8952->vid0_gpiod || !max8952->vid1_gpiod) { dev_warn(&client->dev, "VID0/1 gpio invalid: " - "DVS not available.\n"); + "DVS not available.\n"); max8952->vid0 = 0; max8952->vid1 = 0; - /* Mark invalid */ - pdata->gpio_vid0 = -1; - pdata->gpio_vid1 = -1; + /* Make sure if we have any descriptors they get set to low */ + if (max8952->vid0_gpiod) + gpiod_set_value(max8952->vid0_gpiod, 0); + if (max8952->vid1_gpiod) + gpiod_set_value(max8952->vid1_gpiod, 0); /* Disable Pulldown of EN only */ max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 0ead1164e4d6..397918ebba55 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -21,7 +21,8 @@ static const char *const regulator_states[PM_SUSPEND_MAX + 1] = { [PM_SUSPEND_MAX] = "regulator-state-disk", }; -static void of_get_regulation_constraints(struct device_node *np, +static int of_get_regulation_constraints(struct device *dev, + struct device_node *np, struct regulator_init_data **init_data, const struct regulator_desc *desc) { @@ -30,8 +31,13 @@ static void of_get_regulation_constraints(struct device_node *np, struct device_node *suspend_np; unsigned int mode; int ret, i, len; + int n_phandles; u32 pval; + n_phandles = of_count_phandle_with_args(np, "regulator-coupled-with", + NULL); + n_phandles = max(n_phandles, 0); + constraints->name = of_get_property(np, "regulator-name", NULL); if (!of_property_read_u32(np, "regulator-min-microvolt", &pval)) @@ -163,9 +169,17 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-system-load", &pval)) constraints->system_load = pval; - if (!of_property_read_u32(np, "regulator-coupled-max-spread", - &pval)) - constraints->max_spread = pval; + if (n_phandles) { + constraints->max_spread = devm_kzalloc(dev, + sizeof(*constraints->max_spread) * n_phandles, + GFP_KERNEL); + + if (!constraints->max_spread) + return -ENOMEM; + + of_property_read_u32_array(np, "regulator-coupled-max-spread", + constraints->max_spread, n_phandles); + } if (!of_property_read_u32(np, "regulator-max-step-microvolt", &pval)) @@ -242,6 +256,8 @@ static void of_get_regulation_constraints(struct device_node *np, suspend_state = NULL; suspend_np = NULL; } + + return 0; } /** @@ -267,7 +283,9 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, if (!init_data) return NULL; /* Out of memory? */ - of_get_regulation_constraints(node, &init_data, desc); + if (of_get_regulation_constraints(dev, node, &init_data, desc)) + return NULL; + return init_data; } EXPORT_SYMBOL_GPL(of_get_regulator_init_data); @@ -473,7 +491,8 @@ int of_get_n_coupled(struct regulator_dev *rdev) /* Looks for "to_find" device_node in src's "regulator-coupled-with" property */ static bool of_coupling_find_node(struct device_node *src, - struct device_node *to_find) + struct device_node *to_find, + int *index) { int n_phandles, i; bool found = false; @@ -495,8 +514,10 @@ static bool of_coupling_find_node(struct device_node *src, of_node_put(tmp); - if (found) + if (found) { + *index = i; break; + } } return found; @@ -517,22 +538,23 @@ static bool of_coupling_find_node(struct device_node *src, */ bool of_check_coupling_data(struct regulator_dev *rdev) { - int max_spread = rdev->constraints->max_spread; struct device_node *node = rdev->dev.of_node; int n_phandles = of_get_n_coupled(rdev); struct device_node *c_node; + int index; int i; bool ret = true; - if (max_spread <= 0) { - dev_err(&rdev->dev, "max_spread value invalid\n"); - return false; - } - /* iterate over rdev's phandles */ for (i = 0; i < n_phandles; i++) { + int max_spread = rdev->constraints->max_spread[i]; int c_max_spread, c_n_phandles; + if (max_spread <= 0) { + dev_err(&rdev->dev, "max_spread value invalid\n"); + return false; + } + c_node = of_parse_phandle(node, "regulator-coupled-with", i); @@ -549,22 +571,23 @@ bool of_check_coupling_data(struct regulator_dev *rdev) goto clean; } - if (of_property_read_u32(c_node, "regulator-coupled-max-spread", - &c_max_spread)) { + if (!of_coupling_find_node(c_node, node, &index)) { + dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n"); ret = false; goto clean; } - if (c_max_spread != max_spread) { - dev_err(&rdev->dev, - "coupled regulators max_spread mismatch\n"); + if (of_property_read_u32_index(c_node, "regulator-coupled-max-spread", + index, &c_max_spread)) { ret = false; goto clean; } - if (!of_coupling_find_node(c_node, node)) { - dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n"); + if (c_max_spread != max_spread) { + dev_err(&rdev->dev, + "coupled regulators max_spread mismatch\n"); ret = false; + goto clean; } clean: diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 6dfc9e176360..7f51c5fc8194 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -96,6 +96,8 @@ enum spmi_regulator_logical_type { SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS, SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS, SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO, + SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426, + SPMI_REGULATOR_LOGICAL_TYPE_HFS430, }; enum spmi_regulator_type { @@ -142,11 +144,13 @@ enum spmi_regulator_subtype { SPMI_REGULATOR_SUBTYPE_5V_BOOST = 0x01, SPMI_REGULATOR_SUBTYPE_FTS_CTL = 0x08, SPMI_REGULATOR_SUBTYPE_FTS2p5_CTL = 0x09, + SPMI_REGULATOR_SUBTYPE_FTS426_CTL = 0x0a, SPMI_REGULATOR_SUBTYPE_BB_2A = 0x01, SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL1 = 0x0d, SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL2 = 0x0e, SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL3 = 0x0f, SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL4 = 0x10, + SPMI_REGULATOR_SUBTYPE_HFS430 = 0x0a, }; enum spmi_common_regulator_registers { @@ -162,6 +166,18 @@ enum spmi_common_regulator_registers { SPMI_COMMON_REG_STEP_CTRL = 0x61, }; +/* + * Second common register layout used by newer devices starting with ftsmps426 + * Note that some of the registers from the first common layout remain + * unchanged and their definition is not duplicated. + */ +enum spmi_ftsmps426_regulator_registers { + SPMI_FTSMPS426_REG_VOLTAGE_LSB = 0x40, + SPMI_FTSMPS426_REG_VOLTAGE_MSB = 0x41, + SPMI_FTSMPS426_REG_VOLTAGE_ULS_LSB = 0x68, + SPMI_FTSMPS426_REG_VOLTAGE_ULS_MSB = 0x69, +}; + enum spmi_vs_registers { SPMI_VS_REG_OCP = 0x4a, SPMI_VS_REG_SOFT_START = 0x4c, @@ -221,6 +237,14 @@ enum spmi_common_control_register_index { #define SPMI_COMMON_MODE_FOLLOW_HW_EN0_MASK 0x01 #define SPMI_COMMON_MODE_FOLLOW_ALL_MASK 0x1f +#define SPMI_FTSMPS426_MODE_BYPASS_MASK 3 +#define SPMI_FTSMPS426_MODE_RETENTION_MASK 4 +#define SPMI_FTSMPS426_MODE_LPM_MASK 5 +#define SPMI_FTSMPS426_MODE_AUTO_MASK 6 +#define SPMI_FTSMPS426_MODE_HPM_MASK 7 + +#define SPMI_FTSMPS426_MODE_MASK 0x07 + /* Common regulator pull down control register layout */ #define SPMI_COMMON_PULL_DOWN_ENABLE_MASK 0x80 @@ -266,6 +290,25 @@ enum spmi_common_control_register_index { #define SPMI_FTSMPS_STEP_MARGIN_NUM 4 #define SPMI_FTSMPS_STEP_MARGIN_DEN 5 +#define SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK 0x03 +#define SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT 0 + +/* Clock rate in kHz of the FTSMPS426 regulator reference clock. */ +#define SPMI_FTSMPS426_CLOCK_RATE 4800 + +#define SPMI_HFS430_CLOCK_RATE 1600 + +/* Minimum voltage stepper delay for each step. */ +#define SPMI_FTSMPS426_STEP_DELAY 2 + +/* + * The ratio SPMI_FTSMPS426_STEP_MARGIN_NUM/SPMI_FTSMPS426_STEP_MARGIN_DEN is + * used to adjust the step rate in order to account for oscillator variance. + */ +#define SPMI_FTSMPS426_STEP_MARGIN_NUM 10 +#define SPMI_FTSMPS426_STEP_MARGIN_DEN 11 + + /* VSET value to decide the range of ULT SMPS */ #define ULT_SMPS_RANGE_SPLIT 0x60 @@ -439,6 +482,10 @@ static struct spmi_voltage_range ftsmps2p5_ranges[] = { SPMI_VOLTAGE_RANGE(1, 160000, 1360000, 2200000, 2200000, 10000), }; +static struct spmi_voltage_range ftsmps426_ranges[] = { + SPMI_VOLTAGE_RANGE(0, 0, 320000, 1352000, 1352000, 4000), +}; + static struct spmi_voltage_range boost_ranges[] = { SPMI_VOLTAGE_RANGE(0, 4000000, 4000000, 5550000, 5550000, 50000), }; @@ -464,6 +511,10 @@ static struct spmi_voltage_range ult_pldo_ranges[] = { SPMI_VOLTAGE_RANGE(0, 1750000, 1750000, 3337500, 3337500, 12500), }; +static struct spmi_voltage_range hfs430_ranges[] = { + SPMI_VOLTAGE_RANGE(0, 320000, 320000, 2040000, 2040000, 8000), +}; + static DEFINE_SPMI_SET_POINTS(pldo); static DEFINE_SPMI_SET_POINTS(nldo1); static DEFINE_SPMI_SET_POINTS(nldo2); @@ -472,12 +523,14 @@ static DEFINE_SPMI_SET_POINTS(ln_ldo); static DEFINE_SPMI_SET_POINTS(smps); static DEFINE_SPMI_SET_POINTS(ftsmps); static DEFINE_SPMI_SET_POINTS(ftsmps2p5); +static DEFINE_SPMI_SET_POINTS(ftsmps426); static DEFINE_SPMI_SET_POINTS(boost); static DEFINE_SPMI_SET_POINTS(boost_byp); static DEFINE_SPMI_SET_POINTS(ult_lo_smps); static DEFINE_SPMI_SET_POINTS(ult_ho_smps); static DEFINE_SPMI_SET_POINTS(ult_nldo); static DEFINE_SPMI_SET_POINTS(ult_pldo); +static DEFINE_SPMI_SET_POINTS(hfs430); static inline int spmi_vreg_read(struct spmi_regulator *vreg, u16 addr, u8 *buf, int len) @@ -739,18 +792,31 @@ spmi_regulator_common_set_voltage(struct regulator_dev *rdev, unsigned selector) return spmi_vreg_write(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, buf, 2); } +static int spmi_regulator_common_list_voltage(struct regulator_dev *rdev, + unsigned selector); + +static int spmi_regulator_ftsmps426_set_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 buf[2]; + int mV; + + mV = spmi_regulator_common_list_voltage(rdev, selector) / 1000; + + buf[0] = mV & 0xff; + buf[1] = mV >> 8; + return spmi_vreg_write(vreg, SPMI_FTSMPS426_REG_VOLTAGE_LSB, buf, 2); +} + static int spmi_regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_selector, unsigned int new_selector) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); - const struct spmi_voltage_range *range; int diff_uV; - range = spmi_regulator_find_range(vreg); - if (!range) - return -EINVAL; - - diff_uV = abs(new_selector - old_selector) * range->step_uV; + diff_uV = abs(spmi_regulator_common_list_voltage(rdev, new_selector) - + spmi_regulator_common_list_voltage(rdev, old_selector)); return DIV_ROUND_UP(diff_uV, vreg->slew_rate); } @@ -770,6 +836,21 @@ static int spmi_regulator_common_get_voltage(struct regulator_dev *rdev) return spmi_hw_selector_to_sw(vreg, voltage_sel, range); } +static int spmi_regulator_ftsmps426_get_voltage(struct regulator_dev *rdev) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + const struct spmi_voltage_range *range; + u8 buf[2]; + int uV; + + spmi_vreg_read(vreg, SPMI_FTSMPS426_REG_VOLTAGE_LSB, buf, 2); + + uV = (((unsigned int)buf[1] << 8) | (unsigned int)buf[0]) * 1000; + range = vreg->set_points->range; + + return (uV - range->set_point_min_uV) / range->step_uV; +} + static int spmi_regulator_single_map_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { @@ -903,13 +984,33 @@ static unsigned int spmi_regulator_common_get_mode(struct regulator_dev *rdev) spmi_vreg_read(vreg, SPMI_COMMON_REG_MODE, ®, 1); - if (reg & SPMI_COMMON_MODE_HPM_MASK) - return REGULATOR_MODE_NORMAL; + reg &= SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK; - if (reg & SPMI_COMMON_MODE_AUTO_MASK) + switch (reg) { + case SPMI_COMMON_MODE_HPM_MASK: + return REGULATOR_MODE_NORMAL; + case SPMI_COMMON_MODE_AUTO_MASK: return REGULATOR_MODE_FAST; + default: + return REGULATOR_MODE_IDLE; + } +} - return REGULATOR_MODE_IDLE; +static unsigned int spmi_regulator_ftsmps426_get_mode(struct regulator_dev *rdev) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 reg; + + spmi_vreg_read(vreg, SPMI_COMMON_REG_MODE, ®, 1); + + switch (reg) { + case SPMI_FTSMPS426_MODE_HPM_MASK: + return REGULATOR_MODE_NORMAL; + case SPMI_FTSMPS426_MODE_AUTO_MASK: + return REGULATOR_MODE_FAST; + default: + return REGULATOR_MODE_IDLE; + } } static int @@ -917,12 +1018,43 @@ spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); u8 mask = SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK; - u8 val = 0; + u8 val; - if (mode == REGULATOR_MODE_NORMAL) + switch (mode) { + case REGULATOR_MODE_NORMAL: val = SPMI_COMMON_MODE_HPM_MASK; - else if (mode == REGULATOR_MODE_FAST) + break; + case REGULATOR_MODE_FAST: val = SPMI_COMMON_MODE_AUTO_MASK; + break; + default: + val = 0; + break; + } + + return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask); +} + +static int +spmi_regulator_ftsmps426_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 mask = SPMI_FTSMPS426_MODE_MASK; + u8 val; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = SPMI_FTSMPS426_MODE_HPM_MASK; + break; + case REGULATOR_MODE_FAST: + val = SPMI_FTSMPS426_MODE_AUTO_MASK; + break; + case REGULATOR_MODE_IDLE: + val = SPMI_FTSMPS426_MODE_LPM_MASK; + break; + default: + return -EINVAL; + } return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask); } @@ -1256,12 +1388,41 @@ static struct regulator_ops spmi_ult_ldo_ops = { .set_soft_start = spmi_regulator_common_set_soft_start, }; +static struct regulator_ops spmi_ftsmps426_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = spmi_regulator_ftsmps426_set_voltage, + .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel, + .get_voltage_sel = spmi_regulator_ftsmps426_get_voltage, + .map_voltage = spmi_regulator_single_map_voltage, + .list_voltage = spmi_regulator_common_list_voltage, + .set_mode = spmi_regulator_ftsmps426_set_mode, + .get_mode = spmi_regulator_ftsmps426_get_mode, + .set_load = spmi_regulator_common_set_load, + .set_pull_down = spmi_regulator_common_set_pull_down, +}; + +static struct regulator_ops spmi_hfs430_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = spmi_regulator_ftsmps426_set_voltage, + .set_voltage_time_sel = spmi_regulator_set_voltage_time_sel, + .get_voltage_sel = spmi_regulator_ftsmps426_get_voltage, + .map_voltage = spmi_regulator_single_map_voltage, + .list_voltage = spmi_regulator_common_list_voltage, + .set_mode = spmi_regulator_ftsmps426_set_mode, + .get_mode = spmi_regulator_ftsmps426_get_mode, +}; + /* Maximum possible digital major revision value */ #define INF 0xFF static const struct spmi_regulator_mapping supported_regulators[] = { /* type subtype dig_min dig_max ltype ops setpoints hpm_min */ 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), SPMI_VREG(LDO, N600, 0, 0, LDO, ldo, nldo2, 10000), SPMI_VREG(LDO, N1200, 0, 0, LDO, ldo, nldo2, 10000), @@ -1291,6 +1452,7 @@ static const struct spmi_regulator_mapping supported_regulators[] = { SPMI_VREG(BOOST, 5V_BOOST, 0, INF, BOOST, boost, boost, 0), SPMI_VREG(FTS, FTS_CTL, 0, INF, FTSMPS, ftsmps, ftsmps, 100000), SPMI_VREG(FTS, FTS2p5_CTL, 0, INF, FTSMPS, ftsmps, ftsmps2p5, 100000), + SPMI_VREG(FTS, FTS426_CTL, 0, INF, FTSMPS426, ftsmps426, ftsmps426, 100000), SPMI_VREG(BOOST_BYP, BB_2A, 0, INF, BOOST_BYP, boost, boost_byp, 0), SPMI_VREG(ULT_BUCK, ULT_HF_CTL1, 0, INF, ULT_LO_SMPS, ult_lo_smps, ult_lo_smps, 100000), @@ -1428,6 +1590,35 @@ static int spmi_regulator_init_slew_rate(struct spmi_regulator *vreg) return ret; } +static int spmi_regulator_init_slew_rate_ftsmps426(struct spmi_regulator *vreg, + int clock_rate) +{ + int ret; + u8 reg = 0; + int delay, slew_rate; + const struct spmi_voltage_range *range = &vreg->set_points->range[0]; + + ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_STEP_CTRL, ®, 1); + if (ret) { + dev_err(vreg->dev, "spmi read failed, ret=%d\n", ret); + return ret; + } + + delay = reg & SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK; + delay >>= SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT; + + /* slew_rate has units of uV/us */ + slew_rate = clock_rate * range->step_uV; + slew_rate /= 1000 * (SPMI_FTSMPS426_STEP_DELAY << delay); + slew_rate *= SPMI_FTSMPS426_STEP_MARGIN_NUM; + slew_rate /= SPMI_FTSMPS426_STEP_MARGIN_DEN; + + /* Ensure that the slew rate is greater than 0 */ + vreg->slew_rate = max(slew_rate, 1); + + return ret; +} + static int spmi_regulator_init_registers(struct spmi_regulator *vreg, const struct spmi_regulator_init_data *data) { @@ -1567,6 +1758,19 @@ static int spmi_regulator_of_parse(struct device_node *node, ret = spmi_regulator_init_slew_rate(vreg); if (ret) return ret; + break; + case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426: + ret = spmi_regulator_init_slew_rate_ftsmps426(vreg, + SPMI_FTSMPS426_CLOCK_RATE); + if (ret) + return ret; + break; + case SPMI_REGULATOR_LOGICAL_TYPE_HFS430: + ret = spmi_regulator_init_slew_rate_ftsmps426(vreg, + SPMI_HFS430_CLOCK_RATE); + if (ret) + return ret; + break; default: break; } @@ -1723,12 +1927,27 @@ static const struct spmi_regulator_data pmi8994_regulators[] = { { } }; +static const struct spmi_regulator_data pm8005_regulators[] = { + { "s1", 0x1400, "vdd_s1", }, + { "s2", 0x1700, "vdd_s2", }, + { "s3", 0x1a00, "vdd_s3", }, + { "s4", 0x1d00, "vdd_s4", }, + { } +}; + +static const struct spmi_regulator_data pms405_regulators[] = { + { "s3", 0x1a00, "vdd_s3"}, + { } +}; + static const struct of_device_id qcom_spmi_regulator_match[] = { + { .compatible = "qcom,pm8005-regulators", .data = &pm8005_regulators }, { .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators }, { .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators }, { .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators }, { .compatible = "qcom,pm8994-regulators", .data = &pm8994_regulators }, { .compatible = "qcom,pmi8994-regulators", .data = &pmi8994_regulators }, + { .compatible = "qcom,pms405-regulators", .data = &pms405_regulators }, { } }; MODULE_DEVICE_TABLE(of, qcom_spmi_regulator_match); @@ -1736,6 +1955,7 @@ MODULE_DEVICE_TABLE(of, qcom_spmi_regulator_match); static int qcom_spmi_regulator_probe(struct platform_device *pdev) { const struct spmi_regulator_data *reg; + const struct spmi_voltage_range *range; const struct of_device_id *match; struct regulator_config config = { }; struct regulator_dev *rdev; @@ -1825,6 +2045,12 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) } } + if (vreg->set_points && vreg->set_points->count == 1) { + /* since there is only one range */ + range = vreg->set_points->range; + vreg->desc.uV_step = range->step_uV; + } + config.dev = dev; config.driver_data = vreg; config.regmap = regmap; diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 134c62db36c5..054baaadfdfd 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -34,7 +34,7 @@ struct s2mps11_info { enum sec_device_type dev_type; /* - * One bit for each S2MPS13/S2MPS14/S2MPU02 regulator whether + * One bit for each S2MPS11/S2MPS13/S2MPS14/S2MPU02 regulator whether * the suspend mode was enabled. */ DECLARE_BITMAP(suspend_state, S2MPS_REGULATOR_MAX); @@ -70,10 +70,11 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int new_selector) { struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + int rdev_id = rdev_get_id(rdev); unsigned int ramp_delay = 0; int old_volt, new_volt; - switch (rdev_get_id(rdev)) { + switch (rdev_id) { case S2MPS11_BUCK2: ramp_delay = s2mps11->ramp_delay2; break; @@ -111,9 +112,10 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); unsigned int ramp_val, ramp_shift, ramp_reg = S2MPS11_REG_RAMP_BUCK; unsigned int ramp_enable = 1, enable_shift = 0; + int rdev_id = rdev_get_id(rdev); int ret; - switch (rdev_get_id(rdev)) { + switch (rdev_id) { case S2MPS11_BUCK1: if (ramp_delay > s2mps11->ramp_delay16) s2mps11->ramp_delay16 = ramp_delay; @@ -203,9 +205,8 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) goto ramp_disable; /* Ramp delay can be enabled/disabled only for buck[2346] */ - if ((rdev_get_id(rdev) >= S2MPS11_BUCK2 && - rdev_get_id(rdev) <= S2MPS11_BUCK4) || - rdev_get_id(rdev) == S2MPS11_BUCK6) { + if ((rdev_id >= S2MPS11_BUCK2 && rdev_id <= S2MPS11_BUCK4) || + rdev_id == S2MPS11_BUCK6) { ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, 1 << enable_shift, 1 << enable_shift); if (ret) { @@ -224,27 +225,133 @@ ramp_disable: 1 << enable_shift, 0); } +static int s2mps11_regulator_enable(struct regulator_dev *rdev) +{ + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + int rdev_id = rdev_get_id(rdev); + unsigned int val; + + switch (s2mps11->dev_type) { + case S2MPS11X: + if (test_bit(rdev_id, s2mps11->suspend_state)) + val = S2MPS14_ENABLE_SUSPEND; + else + val = rdev->desc->enable_mask; + break; + case S2MPS13X: + case S2MPS14X: + if (test_bit(rdev_id, s2mps11->suspend_state)) + val = S2MPS14_ENABLE_SUSPEND; + else if (s2mps11->ext_control_gpiod[rdev_id]) + val = S2MPS14_ENABLE_EXT_CONTROL; + else + val = rdev->desc->enable_mask; + break; + case S2MPU02: + if (test_bit(rdev_id, s2mps11->suspend_state)) + val = S2MPU02_ENABLE_SUSPEND; + else + val = rdev->desc->enable_mask; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, val); +} + +static int s2mps11_regulator_set_suspend_disable(struct regulator_dev *rdev) +{ + int ret; + unsigned int val, state; + struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + int rdev_id = rdev_get_id(rdev); + + /* Below LDO should be always on or does not support suspend mode. */ + switch (s2mps11->dev_type) { + case S2MPS11X: + switch (rdev_id) { + case S2MPS11_LDO2: + case S2MPS11_LDO36: + case S2MPS11_LDO37: + case S2MPS11_LDO38: + return 0; + default: + state = S2MPS14_ENABLE_SUSPEND; + break; + } + break; + case S2MPS13X: + case S2MPS14X: + switch (rdev_id) { + case S2MPS14_LDO3: + return 0; + default: + state = S2MPS14_ENABLE_SUSPEND; + break; + } + break; + case S2MPU02: + switch (rdev_id) { + case S2MPU02_LDO13: + case S2MPU02_LDO14: + case S2MPU02_LDO15: + case S2MPU02_LDO17: + case S2MPU02_BUCK7: + state = S2MPU02_DISABLE_SUSPEND; + break; + default: + state = S2MPU02_ENABLE_SUSPEND; + break; + } + break; + default: + return -EINVAL; + } + + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); + if (ret < 0) + return ret; + + set_bit(rdev_id, s2mps11->suspend_state); + /* + * Don't enable suspend mode if regulator is already disabled because + * this would effectively for a short time turn on the regulator after + * resuming. + * However we still want to toggle the suspend_state bit for regulator + * in case if it got enabled before suspending the system. + */ + if (!(val & rdev->desc->enable_mask)) + return 0; + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, state); +} + static const struct regulator_ops s2mps11_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, }; static const struct regulator_ops s2mps11_buck_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = s2mps11_regulator_set_voltage_time_sel, .set_ramp_delay = s2mps11_set_ramp_delay, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, }; #define regulator_desc_s2mps11_ldo(num, step) { \ @@ -269,9 +376,10 @@ static const struct regulator_ops s2mps11_buck_ops = { .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = MIN_600_MV, \ + .min_uV = MIN_650_MV, \ .uV_step = STEP_6_25_MV, \ - .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .linear_min_sel = 8, \ + .n_voltages = S2MPS11_BUCK12346_N_VOLTAGES, \ .ramp_delay = S2MPS11_RAMP_DELAY, \ .vsel_reg = S2MPS11_REG_B1CTRL2 + (num - 1) * 2, \ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ @@ -285,9 +393,10 @@ static const struct regulator_ops s2mps11_buck_ops = { .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ - .min_uV = MIN_600_MV, \ + .min_uV = MIN_650_MV, \ .uV_step = STEP_6_25_MV, \ - .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .linear_min_sel = 8, \ + .n_voltages = S2MPS11_BUCK5_N_VOLTAGES, \ .ramp_delay = S2MPS11_RAMP_DELAY, \ .vsel_reg = S2MPS11_REG_B5CTRL2, \ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ @@ -295,7 +404,7 @@ static const struct regulator_ops s2mps11_buck_ops = { .enable_mask = S2MPS11_ENABLE_MASK \ } -#define regulator_desc_s2mps11_buck67810(num, min, step) { \ +#define regulator_desc_s2mps11_buck67810(num, min, step, min_sel, voltages) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ .ops = &s2mps11_buck_ops, \ @@ -303,7 +412,8 @@ static const struct regulator_ops s2mps11_buck_ops = { .owner = THIS_MODULE, \ .min_uV = min, \ .uV_step = step, \ - .n_voltages = S2MPS11_BUCK_N_VOLTAGES, \ + .linear_min_sel = min_sel, \ + .n_voltages = voltages, \ .ramp_delay = S2MPS11_RAMP_DELAY, \ .vsel_reg = S2MPS11_REG_B6CTRL2 + (num - 6) * 2, \ .vsel_mask = S2MPS11_BUCK_VSEL_MASK, \ @@ -371,11 +481,15 @@ static const struct regulator_desc s2mps11_regulators[] = { regulator_desc_s2mps11_buck1_4(3), regulator_desc_s2mps11_buck1_4(4), regulator_desc_s2mps11_buck5, - regulator_desc_s2mps11_buck67810(6, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps11_buck67810(7, MIN_600_MV, STEP_12_5_MV), - regulator_desc_s2mps11_buck67810(8, MIN_600_MV, STEP_12_5_MV), + regulator_desc_s2mps11_buck67810(6, MIN_650_MV, STEP_6_25_MV, 8, + S2MPS11_BUCK12346_N_VOLTAGES), + regulator_desc_s2mps11_buck67810(7, MIN_750_MV, STEP_12_5_MV, 0, + S2MPS11_BUCK7810_N_VOLTAGES), + regulator_desc_s2mps11_buck67810(8, MIN_750_MV, STEP_12_5_MV, 0, + S2MPS11_BUCK7810_N_VOLTAGES), regulator_desc_s2mps11_buck9, - regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV), + regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV, 0, + S2MPS11_BUCK7810_N_VOLTAGES), }; static const struct regulator_ops s2mps14_reg_ops; @@ -500,101 +614,16 @@ static const struct regulator_desc s2mps13_regulators[] = { regulator_desc_s2mps13_buck8_10(10, MIN_500_MV, STEP_6_25_MV, 0x10), }; -static int s2mps14_regulator_enable(struct regulator_dev *rdev) -{ - struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); - unsigned int val; - - switch (s2mps11->dev_type) { - case S2MPS13X: - case S2MPS14X: - if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state)) - val = S2MPS14_ENABLE_SUSPEND; - else if (s2mps11->ext_control_gpiod[rdev_get_id(rdev)]) - val = S2MPS14_ENABLE_EXT_CONTROL; - else - val = rdev->desc->enable_mask; - break; - case S2MPU02: - if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state)) - val = S2MPU02_ENABLE_SUSPEND; - else - val = rdev->desc->enable_mask; - break; - default: - return -EINVAL; - } - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, val); -} - -static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev) -{ - int ret; - unsigned int val, state; - struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); - int rdev_id = rdev_get_id(rdev); - - /* Below LDO should be always on or does not support suspend mode. */ - switch (s2mps11->dev_type) { - case S2MPS13X: - case S2MPS14X: - switch (rdev_id) { - case S2MPS14_LDO3: - return 0; - default: - state = S2MPS14_ENABLE_SUSPEND; - break; - } - break; - case S2MPU02: - switch (rdev_id) { - case S2MPU02_LDO13: - case S2MPU02_LDO14: - case S2MPU02_LDO15: - case S2MPU02_LDO17: - case S2MPU02_BUCK7: - state = S2MPU02_DISABLE_SUSPEND; - break; - default: - state = S2MPU02_ENABLE_SUSPEND; - break; - } - break; - default: - return -EINVAL; - } - - ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); - if (ret < 0) - return ret; - - set_bit(rdev_get_id(rdev), s2mps11->suspend_state); - /* - * Don't enable suspend mode if regulator is already disabled because - * this would effectively for a short time turn on the regulator after - * resuming. - * However we still want to toggle the suspend_state bit for regulator - * in case if it got enabled before suspending the system. - */ - if (!(val & rdev->desc->enable_mask)) - return 0; - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, state); -} - static const struct regulator_ops s2mps14_reg_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = s2mps14_regulator_enable, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_disable = s2mps14_regulator_set_suspend_disable, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, }; #define regulator_desc_s2mps14_ldo(num, min, step) { \ @@ -821,9 +850,12 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, 0, GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, "s2mps11-regulator"); - if (IS_ERR(gpio[reg])) { + if (PTR_ERR(gpio[reg]) == -ENOENT) + gpio[reg] = NULL; + else if (IS_ERR(gpio[reg])) { dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n", reg, rdata[reg].name); + gpio[reg] = NULL; continue; } if (gpio[reg]) @@ -856,8 +888,9 @@ static int s2mps11_pmic_dt_parse(struct platform_device *pdev, static int s2mpu02_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { unsigned int ramp_val, ramp_shift, ramp_reg; + int rdev_id = rdev_get_id(rdev); - switch (rdev_get_id(rdev)) { + switch (rdev_id) { case S2MPU02_BUCK1: ramp_shift = S2MPU02_BUCK1_RAMP_SHIFT; break; @@ -885,24 +918,24 @@ static const struct regulator_ops s2mpu02_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = s2mps14_regulator_enable, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_disable = s2mps14_regulator_set_suspend_disable, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, }; static const struct regulator_ops s2mpu02_buck_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, - .enable = s2mps14_regulator_enable, + .enable = s2mps11_regulator_enable, .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_suspend_disable = s2mps14_regulator_set_suspend_disable, + .set_suspend_disable = s2mps11_regulator_set_suspend_disable, .set_ramp_delay = s2mpu02_set_ramp_delay, }; diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index bb9d1a083299..6ca27e9d5ef7 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -574,7 +574,9 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, 0, GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, "s5m8767"); - if (IS_ERR(rdata->ext_control_gpiod)) + if (PTR_ERR(rdata->ext_control_gpiod) == -ENOENT) + rdata->ext_control_gpiod = NULL; + else if (IS_ERR(rdata->ext_control_gpiod)) return PTR_ERR(rdata->ext_control_gpiod); rdata->id = i; diff --git a/drivers/regulator/slg51000-regulator.c b/drivers/regulator/slg51000-regulator.c new file mode 100644 index 000000000000..04b732991d69 --- /dev/null +++ b/drivers/regulator/slg51000-regulator.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// SLG51000 High PSRR, Multi-Output Regulators +// Copyright (C) 2019 Dialog Semiconductor +// +// Author: Eric Jeong <eric.jeong.opensource@diasemi.com> + +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include "slg51000-regulator.h" + +#define SLG51000_SCTL_EVT 7 +#define SLG51000_MAX_EVT_REGISTER 8 +#define SLG51000_LDOHP_LV_MIN 1200000 +#define SLG51000_LDOHP_HV_MIN 2400000 + +enum slg51000_regulators { + SLG51000_REGULATOR_LDO1 = 0, + SLG51000_REGULATOR_LDO2, + SLG51000_REGULATOR_LDO3, + SLG51000_REGULATOR_LDO4, + SLG51000_REGULATOR_LDO5, + SLG51000_REGULATOR_LDO6, + SLG51000_REGULATOR_LDO7, + SLG51000_MAX_REGULATORS, +}; + +struct slg51000 { + struct device *dev; + struct regmap *regmap; + struct regulator_desc *rdesc[SLG51000_MAX_REGULATORS]; + struct regulator_dev *rdev[SLG51000_MAX_REGULATORS]; + struct gpio_desc *cs_gpiod; + int chip_irq; +}; + +struct slg51000_evt_sta { + unsigned int ereg; + unsigned int sreg; +}; + +static const struct slg51000_evt_sta es_reg[SLG51000_MAX_EVT_REGISTER] = { + {SLG51000_LDO1_EVENT, SLG51000_LDO1_STATUS}, + {SLG51000_LDO2_EVENT, SLG51000_LDO2_STATUS}, + {SLG51000_LDO3_EVENT, SLG51000_LDO3_STATUS}, + {SLG51000_LDO4_EVENT, SLG51000_LDO4_STATUS}, + {SLG51000_LDO5_EVENT, SLG51000_LDO5_STATUS}, + {SLG51000_LDO6_EVENT, SLG51000_LDO6_STATUS}, + {SLG51000_LDO7_EVENT, SLG51000_LDO7_STATUS}, + {SLG51000_SYSCTL_EVENT, SLG51000_SYSCTL_STATUS}, +}; + +static const struct regmap_range slg51000_writeable_ranges[] = { + regmap_reg_range(SLG51000_SYSCTL_MATRIX_CONF_A, + SLG51000_SYSCTL_MATRIX_CONF_A), + regmap_reg_range(SLG51000_LDO1_VSEL, SLG51000_LDO1_VSEL), + regmap_reg_range(SLG51000_LDO1_MINV, SLG51000_LDO1_MAXV), + regmap_reg_range(SLG51000_LDO1_IRQ_MASK, SLG51000_LDO1_IRQ_MASK), + regmap_reg_range(SLG51000_LDO2_VSEL, SLG51000_LDO2_VSEL), + regmap_reg_range(SLG51000_LDO2_MINV, SLG51000_LDO2_MAXV), + regmap_reg_range(SLG51000_LDO2_IRQ_MASK, SLG51000_LDO2_IRQ_MASK), + regmap_reg_range(SLG51000_LDO3_VSEL, SLG51000_LDO3_VSEL), + regmap_reg_range(SLG51000_LDO3_MINV, SLG51000_LDO3_MAXV), + regmap_reg_range(SLG51000_LDO3_IRQ_MASK, SLG51000_LDO3_IRQ_MASK), + regmap_reg_range(SLG51000_LDO4_VSEL, SLG51000_LDO4_VSEL), + regmap_reg_range(SLG51000_LDO4_MINV, SLG51000_LDO4_MAXV), + regmap_reg_range(SLG51000_LDO4_IRQ_MASK, SLG51000_LDO4_IRQ_MASK), + regmap_reg_range(SLG51000_LDO5_VSEL, SLG51000_LDO5_VSEL), + regmap_reg_range(SLG51000_LDO5_MINV, SLG51000_LDO5_MAXV), + regmap_reg_range(SLG51000_LDO5_IRQ_MASK, SLG51000_LDO5_IRQ_MASK), + regmap_reg_range(SLG51000_LDO6_VSEL, SLG51000_LDO6_VSEL), + regmap_reg_range(SLG51000_LDO6_MINV, SLG51000_LDO6_MAXV), + regmap_reg_range(SLG51000_LDO6_IRQ_MASK, SLG51000_LDO6_IRQ_MASK), + regmap_reg_range(SLG51000_LDO7_VSEL, SLG51000_LDO7_VSEL), + regmap_reg_range(SLG51000_LDO7_MINV, SLG51000_LDO7_MAXV), + regmap_reg_range(SLG51000_LDO7_IRQ_MASK, SLG51000_LDO7_IRQ_MASK), + regmap_reg_range(SLG51000_OTP_IRQ_MASK, SLG51000_OTP_IRQ_MASK), +}; + +static const struct regmap_range slg51000_readable_ranges[] = { + regmap_reg_range(SLG51000_SYSCTL_PATN_ID_B0, + SLG51000_SYSCTL_PATN_ID_B2), + regmap_reg_range(SLG51000_SYSCTL_SYS_CONF_A, + SLG51000_SYSCTL_SYS_CONF_A), + regmap_reg_range(SLG51000_SYSCTL_SYS_CONF_D, + SLG51000_SYSCTL_MATRIX_CONF_B), + regmap_reg_range(SLG51000_SYSCTL_REFGEN_CONF_C, + SLG51000_SYSCTL_UVLO_CONF_A), + regmap_reg_range(SLG51000_SYSCTL_FAULT_LOG1, SLG51000_SYSCTL_IRQ_MASK), + regmap_reg_range(SLG51000_IO_GPIO1_CONF, SLG51000_IO_GPIO_STATUS), + regmap_reg_range(SLG51000_LUTARRAY_LUT_VAL_0, + SLG51000_LUTARRAY_LUT_VAL_11), + regmap_reg_range(SLG51000_MUXARRAY_INPUT_SEL_0, + SLG51000_MUXARRAY_INPUT_SEL_63), + regmap_reg_range(SLG51000_PWRSEQ_RESOURCE_EN_0, + SLG51000_PWRSEQ_INPUT_SENSE_CONF_B), + regmap_reg_range(SLG51000_LDO1_VSEL, SLG51000_LDO1_VSEL), + regmap_reg_range(SLG51000_LDO1_MINV, SLG51000_LDO1_MAXV), + regmap_reg_range(SLG51000_LDO1_MISC1, SLG51000_LDO1_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO1_EVENT, SLG51000_LDO1_IRQ_MASK), + regmap_reg_range(SLG51000_LDO2_VSEL, SLG51000_LDO2_VSEL), + regmap_reg_range(SLG51000_LDO2_MINV, SLG51000_LDO2_MAXV), + regmap_reg_range(SLG51000_LDO2_MISC1, SLG51000_LDO2_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO2_EVENT, SLG51000_LDO2_IRQ_MASK), + regmap_reg_range(SLG51000_LDO3_VSEL, SLG51000_LDO3_VSEL), + regmap_reg_range(SLG51000_LDO3_MINV, SLG51000_LDO3_MAXV), + regmap_reg_range(SLG51000_LDO3_CONF1, SLG51000_LDO3_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO3_EVENT, SLG51000_LDO3_IRQ_MASK), + regmap_reg_range(SLG51000_LDO4_VSEL, SLG51000_LDO4_VSEL), + regmap_reg_range(SLG51000_LDO4_MINV, SLG51000_LDO4_MAXV), + regmap_reg_range(SLG51000_LDO4_CONF1, SLG51000_LDO4_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO4_EVENT, SLG51000_LDO4_IRQ_MASK), + regmap_reg_range(SLG51000_LDO5_VSEL, SLG51000_LDO5_VSEL), + regmap_reg_range(SLG51000_LDO5_MINV, SLG51000_LDO5_MAXV), + regmap_reg_range(SLG51000_LDO5_TRIM2, SLG51000_LDO5_TRIM2), + regmap_reg_range(SLG51000_LDO5_CONF1, SLG51000_LDO5_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO5_EVENT, SLG51000_LDO5_IRQ_MASK), + regmap_reg_range(SLG51000_LDO6_VSEL, SLG51000_LDO6_VSEL), + regmap_reg_range(SLG51000_LDO6_MINV, SLG51000_LDO6_MAXV), + regmap_reg_range(SLG51000_LDO6_TRIM2, SLG51000_LDO6_TRIM2), + regmap_reg_range(SLG51000_LDO6_CONF1, SLG51000_LDO6_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO6_EVENT, SLG51000_LDO6_IRQ_MASK), + regmap_reg_range(SLG51000_LDO7_VSEL, SLG51000_LDO7_VSEL), + regmap_reg_range(SLG51000_LDO7_MINV, SLG51000_LDO7_MAXV), + regmap_reg_range(SLG51000_LDO7_CONF1, SLG51000_LDO7_VSEL_ACTUAL), + regmap_reg_range(SLG51000_LDO7_EVENT, SLG51000_LDO7_IRQ_MASK), + regmap_reg_range(SLG51000_OTP_EVENT, SLG51000_OTP_EVENT), + regmap_reg_range(SLG51000_OTP_IRQ_MASK, SLG51000_OTP_IRQ_MASK), + regmap_reg_range(SLG51000_OTP_LOCK_OTP_PROG, SLG51000_OTP_LOCK_CTRL), + regmap_reg_range(SLG51000_LOCK_GLOBAL_LOCK_CTRL1, + SLG51000_LOCK_GLOBAL_LOCK_CTRL1), +}; + +static const struct regmap_range slg51000_volatile_ranges[] = { + regmap_reg_range(SLG51000_SYSCTL_FAULT_LOG1, SLG51000_SYSCTL_STATUS), + regmap_reg_range(SLG51000_IO_GPIO_STATUS, SLG51000_IO_GPIO_STATUS), + regmap_reg_range(SLG51000_LDO1_EVENT, SLG51000_LDO1_STATUS), + regmap_reg_range(SLG51000_LDO2_EVENT, SLG51000_LDO2_STATUS), + regmap_reg_range(SLG51000_LDO3_EVENT, SLG51000_LDO3_STATUS), + regmap_reg_range(SLG51000_LDO4_EVENT, SLG51000_LDO4_STATUS), + regmap_reg_range(SLG51000_LDO5_EVENT, SLG51000_LDO5_STATUS), + regmap_reg_range(SLG51000_LDO6_EVENT, SLG51000_LDO6_STATUS), + regmap_reg_range(SLG51000_LDO7_EVENT, SLG51000_LDO7_STATUS), + regmap_reg_range(SLG51000_OTP_EVENT, SLG51000_OTP_EVENT), +}; + +static const struct regmap_access_table slg51000_writeable_table = { + .yes_ranges = slg51000_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(slg51000_writeable_ranges), +}; + +static const struct regmap_access_table slg51000_readable_table = { + .yes_ranges = slg51000_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(slg51000_readable_ranges), +}; + +static const struct regmap_access_table slg51000_volatile_table = { + .yes_ranges = slg51000_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(slg51000_volatile_ranges), +}; + +static const struct regmap_config slg51000_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0x8000, + .wr_table = &slg51000_writeable_table, + .rd_table = &slg51000_readable_table, + .volatile_table = &slg51000_volatile_table, +}; + +static const struct regulator_ops slg51000_regl_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_ops slg51000_switch_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static int slg51000_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct slg51000 *chip = config->driver_data; + struct gpio_desc *ena_gpiod; + enum gpiod_flags gflags = GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE; + + ena_gpiod = devm_gpiod_get_from_of_node(chip->dev, np, + "enable-gpios", 0, + gflags, "gpio-en-ldo"); + if (ena_gpiod) { + config->ena_gpiod = ena_gpiod; + devm_gpiod_unhinge(chip->dev, config->ena_gpiod); + } + + return 0; +} + +#define SLG51000_REGL_DESC(_id, _name, _s_name, _min, _step) \ + [SLG51000_REGULATOR_##_id] = { \ + .name = #_name, \ + .supply_name = _s_name, \ + .id = SLG51000_REGULATOR_##_id, \ + .of_match = of_match_ptr(#_name), \ + .of_parse_cb = slg51000_of_parse_cb, \ + .ops = &slg51000_regl_ops, \ + .regulators_node = of_match_ptr("regulators"), \ + .n_voltages = 256, \ + .min_uV = _min, \ + .uV_step = _step, \ + .linear_min_sel = 0, \ + .vsel_mask = SLG51000_VSEL_MASK, \ + .vsel_reg = SLG51000_##_id##_VSEL, \ + .enable_reg = SLG51000_SYSCTL_MATRIX_CONF_A, \ + .enable_mask = BIT(SLG51000_REGULATOR_##_id), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +static struct regulator_desc regls_desc[SLG51000_MAX_REGULATORS] = { + SLG51000_REGL_DESC(LDO1, ldo1, NULL, 2400000, 5000), + SLG51000_REGL_DESC(LDO2, ldo2, NULL, 2400000, 5000), + SLG51000_REGL_DESC(LDO3, ldo3, "vin3", 1200000, 10000), + SLG51000_REGL_DESC(LDO4, ldo4, "vin4", 1200000, 10000), + SLG51000_REGL_DESC(LDO5, ldo5, "vin5", 400000, 5000), + SLG51000_REGL_DESC(LDO6, ldo6, "vin6", 400000, 5000), + SLG51000_REGL_DESC(LDO7, ldo7, "vin7", 1200000, 10000), +}; + +static int slg51000_regulator_init(struct slg51000 *chip) +{ + struct regulator_config config = { }; + struct regulator_desc *rdesc; + unsigned int reg, val; + u8 vsel_range[2]; + int id, ret = 0; + const unsigned int min_regs[SLG51000_MAX_REGULATORS] = { + SLG51000_LDO1_MINV, SLG51000_LDO2_MINV, SLG51000_LDO3_MINV, + SLG51000_LDO4_MINV, SLG51000_LDO5_MINV, SLG51000_LDO6_MINV, + SLG51000_LDO7_MINV, + }; + + for (id = 0; id < SLG51000_MAX_REGULATORS; id++) { + chip->rdesc[id] = ®ls_desc[id]; + rdesc = chip->rdesc[id]; + config.regmap = chip->regmap; + config.dev = chip->dev; + config.driver_data = chip; + + ret = regmap_bulk_read(chip->regmap, min_regs[id], + vsel_range, 2); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read the MIN register\n"); + return ret; + } + + switch (id) { + case SLG51000_REGULATOR_LDO1: + case SLG51000_REGULATOR_LDO2: + if (id == SLG51000_REGULATOR_LDO1) + reg = SLG51000_LDO1_MISC1; + else + reg = SLG51000_LDO2_MISC1; + + ret = regmap_read(chip->regmap, reg, &val); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read voltage range of ldo%d\n", + id + 1); + return ret; + } + + rdesc->linear_min_sel = vsel_range[0]; + rdesc->n_voltages = vsel_range[1] + 1; + if (val & SLG51000_SEL_VRANGE_MASK) + rdesc->min_uV = SLG51000_LDOHP_HV_MIN + + (vsel_range[0] + * rdesc->uV_step); + else + rdesc->min_uV = SLG51000_LDOHP_LV_MIN + + (vsel_range[0] + * rdesc->uV_step); + break; + + case SLG51000_REGULATOR_LDO5: + case SLG51000_REGULATOR_LDO6: + if (id == SLG51000_REGULATOR_LDO5) + reg = SLG51000_LDO5_TRIM2; + else + reg = SLG51000_LDO6_TRIM2; + + ret = regmap_read(chip->regmap, reg, &val); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read LDO mode register\n"); + return ret; + } + + if (val & SLG51000_SEL_BYP_MODE_MASK) { + rdesc->ops = &slg51000_switch_ops; + rdesc->n_voltages = 0; + rdesc->min_uV = 0; + rdesc->uV_step = 0; + rdesc->linear_min_sel = 0; + break; + } + /* Fall through - to the check below.*/ + + default: + rdesc->linear_min_sel = vsel_range[0]; + rdesc->n_voltages = vsel_range[1] + 1; + rdesc->min_uV = rdesc->min_uV + + (vsel_range[0] * rdesc->uV_step); + break; + } + + chip->rdev[id] = devm_regulator_register(chip->dev, rdesc, + &config); + if (IS_ERR(chip->rdev[id])) { + ret = PTR_ERR(chip->rdev[id]); + dev_err(chip->dev, + "Failed to register regulator(%s):%d\n", + chip->rdesc[id]->name, ret); + return ret; + } + } + + return 0; +} + +static irqreturn_t slg51000_irq_handler(int irq, void *data) +{ + struct slg51000 *chip = data; + struct regmap *regmap = chip->regmap; + enum { R0 = 0, R1, R2, REG_MAX }; + u8 evt[SLG51000_MAX_EVT_REGISTER][REG_MAX]; + int ret, i, handled = IRQ_NONE; + unsigned int evt_otp, mask_otp; + + /* Read event[R0], status[R1] and mask[R2] register */ + for (i = 0; i < SLG51000_MAX_EVT_REGISTER; i++) { + ret = regmap_bulk_read(regmap, es_reg[i].ereg, evt[i], REG_MAX); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read event registers(%d)\n", ret); + return IRQ_NONE; + } + } + + ret = regmap_read(regmap, SLG51000_OTP_EVENT, &evt_otp); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read otp event registers(%d)\n", ret); + return IRQ_NONE; + } + + ret = regmap_read(regmap, SLG51000_OTP_IRQ_MASK, &mask_otp); + if (ret < 0) { + dev_err(chip->dev, + "Failed to read otp mask register(%d)\n", ret); + return IRQ_NONE; + } + + if ((evt_otp & SLG51000_EVT_CRC_MASK) && + !(mask_otp & SLG51000_IRQ_CRC_MASK)) { + dev_info(chip->dev, + "OTP has been read or OTP crc is not zero\n"); + handled = IRQ_HANDLED; + } + + for (i = 0; i < SLG51000_MAX_REGULATORS; i++) { + if (!(evt[i][R2] & SLG51000_IRQ_ILIM_FLAG_MASK) && + (evt[i][R0] & SLG51000_EVT_ILIM_FLAG_MASK)) { + regulator_lock(chip->rdev[i]); + regulator_notifier_call_chain(chip->rdev[i], + REGULATOR_EVENT_OVER_CURRENT, NULL); + regulator_unlock(chip->rdev[i]); + + if (evt[i][R1] & SLG51000_STA_ILIM_FLAG_MASK) + dev_warn(chip->dev, + "Over-current limit(ldo%d)\n", i + 1); + handled = IRQ_HANDLED; + } + } + + if (!(evt[SLG51000_SCTL_EVT][R2] & SLG51000_IRQ_HIGH_TEMP_WARN_MASK) && + (evt[SLG51000_SCTL_EVT][R0] & SLG51000_EVT_HIGH_TEMP_WARN_MASK)) { + for (i = 0; i < SLG51000_MAX_REGULATORS; i++) { + if (!(evt[i][R1] & SLG51000_STA_ILIM_FLAG_MASK) && + (evt[i][R1] & SLG51000_STA_VOUT_OK_FLAG_MASK)) { + regulator_lock(chip->rdev[i]); + regulator_notifier_call_chain(chip->rdev[i], + REGULATOR_EVENT_OVER_TEMP, NULL); + regulator_unlock(chip->rdev[i]); + } + } + handled = IRQ_HANDLED; + if (evt[SLG51000_SCTL_EVT][R1] & + SLG51000_STA_HIGH_TEMP_WARN_MASK) + dev_warn(chip->dev, "High temperature warning!\n"); + } + + return handled; +} + +static void slg51000_clear_fault_log(struct slg51000 *chip) +{ + unsigned int val = 0; + int ret = 0; + + ret = regmap_read(chip->regmap, SLG51000_SYSCTL_FAULT_LOG1, &val); + if (ret < 0) { + dev_err(chip->dev, "Failed to read Fault log register\n"); + return; + } + + if (val & SLG51000_FLT_OVER_TEMP_MASK) + dev_dbg(chip->dev, "Fault log: FLT_OVER_TEMP\n"); + if (val & SLG51000_FLT_POWER_SEQ_CRASH_REQ_MASK) + dev_dbg(chip->dev, "Fault log: FLT_POWER_SEQ_CRASH_REQ\n"); + if (val & SLG51000_FLT_RST_MASK) + dev_dbg(chip->dev, "Fault log: FLT_RST\n"); + if (val & SLG51000_FLT_POR_MASK) + dev_dbg(chip->dev, "Fault log: FLT_POR\n"); +} + +static int slg51000_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct slg51000 *chip; + struct gpio_desc *cs_gpiod = NULL; + int error, ret; + + chip = devm_kzalloc(dev, sizeof(struct slg51000), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + cs_gpiod = devm_gpiod_get_from_of_node(dev, dev->of_node, + "dlg,cs-gpios", 0, + GPIOD_OUT_HIGH + | GPIOD_FLAGS_BIT_NONEXCLUSIVE, + "slg51000-cs"); + if (cs_gpiod) { + dev_info(dev, "Found chip selector property\n"); + chip->cs_gpiod = cs_gpiod; + } + + i2c_set_clientdata(client, chip); + chip->chip_irq = client->irq; + chip->dev = dev; + chip->regmap = devm_regmap_init_i2c(client, &slg51000_regmap_config); + if (IS_ERR(chip->regmap)) { + error = PTR_ERR(chip->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", + error); + return error; + } + + ret = slg51000_regulator_init(chip); + if (ret < 0) { + dev_err(chip->dev, "Failed to init regulator(%d)\n", ret); + return ret; + } + + slg51000_clear_fault_log(chip); + + if (chip->chip_irq) { + ret = devm_request_threaded_irq(dev, chip->chip_irq, NULL, + slg51000_irq_handler, + (IRQF_TRIGGER_HIGH | + IRQF_ONESHOT), + "slg51000-irq", chip); + if (ret != 0) { + dev_err(dev, "Failed to request IRQ: %d\n", + chip->chip_irq); + return ret; + } + } else { + dev_info(dev, "No IRQ configured\n"); + } + + return ret; +} + +static const struct i2c_device_id slg51000_i2c_id[] = { + {"slg51000", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, slg51000_i2c_id); + +static struct i2c_driver slg51000_regulator_driver = { + .driver = { + .name = "slg51000-regulator", + }, + .probe = slg51000_i2c_probe, + .id_table = slg51000_i2c_id, +}; + +module_i2c_driver(slg51000_regulator_driver); + +MODULE_AUTHOR("Eric Jeong <eric.jeong.opensource@diasemi.com>"); +MODULE_DESCRIPTION("SLG51000 regulator driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/regulator/slg51000-regulator.h b/drivers/regulator/slg51000-regulator.h new file mode 100644 index 000000000000..20feb7f91942 --- /dev/null +++ b/drivers/regulator/slg51000-regulator.h @@ -0,0 +1,505 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * SLG51000 High PSRR, Multi-Output Regulators + * Copyright (C) 2019 Dialog Semiconductor + * + * Author: Eric Jeong <eric.jeong.opensource@diasemi.com> + */ + +#ifndef __SLG51000_REGISTERS_H__ +#define __SLG51000_REGISTERS_H__ + +/* Registers */ + +#define SLG51000_SYSCTL_PATN_ID_B0 0x1105 +#define SLG51000_SYSCTL_PATN_ID_B1 0x1106 +#define SLG51000_SYSCTL_PATN_ID_B2 0x1107 +#define SLG51000_SYSCTL_SYS_CONF_A 0x1109 +#define SLG51000_SYSCTL_SYS_CONF_D 0x110c +#define SLG51000_SYSCTL_MATRIX_CONF_A 0x110d +#define SLG51000_SYSCTL_MATRIX_CONF_B 0x110e +#define SLG51000_SYSCTL_REFGEN_CONF_C 0x1111 +#define SLG51000_SYSCTL_UVLO_CONF_A 0x1112 +#define SLG51000_SYSCTL_FAULT_LOG1 0x1115 +#define SLG51000_SYSCTL_EVENT 0x1116 +#define SLG51000_SYSCTL_STATUS 0x1117 +#define SLG51000_SYSCTL_IRQ_MASK 0x1118 +#define SLG51000_IO_GPIO1_CONF 0x1500 +#define SLG51000_IO_GPIO2_CONF 0x1501 +#define SLG51000_IO_GPIO3_CONF 0x1502 +#define SLG51000_IO_GPIO4_CONF 0x1503 +#define SLG51000_IO_GPIO5_CONF 0x1504 +#define SLG51000_IO_GPIO6_CONF 0x1505 +#define SLG51000_IO_GPIO_STATUS 0x1506 +#define SLG51000_LUTARRAY_LUT_VAL_0 0x1600 +#define SLG51000_LUTARRAY_LUT_VAL_1 0x1601 +#define SLG51000_LUTARRAY_LUT_VAL_2 0x1602 +#define SLG51000_LUTARRAY_LUT_VAL_3 0x1603 +#define SLG51000_LUTARRAY_LUT_VAL_4 0x1604 +#define SLG51000_LUTARRAY_LUT_VAL_5 0x1605 +#define SLG51000_LUTARRAY_LUT_VAL_6 0x1606 +#define SLG51000_LUTARRAY_LUT_VAL_7 0x1607 +#define SLG51000_LUTARRAY_LUT_VAL_8 0x1608 +#define SLG51000_LUTARRAY_LUT_VAL_9 0x1609 +#define SLG51000_LUTARRAY_LUT_VAL_10 0x160a +#define SLG51000_LUTARRAY_LUT_VAL_11 0x160b +#define SLG51000_MUXARRAY_INPUT_SEL_0 0x1700 +#define SLG51000_MUXARRAY_INPUT_SEL_1 0x1701 +#define SLG51000_MUXARRAY_INPUT_SEL_2 0x1702 +#define SLG51000_MUXARRAY_INPUT_SEL_3 0x1703 +#define SLG51000_MUXARRAY_INPUT_SEL_4 0x1704 +#define SLG51000_MUXARRAY_INPUT_SEL_5 0x1705 +#define SLG51000_MUXARRAY_INPUT_SEL_6 0x1706 +#define SLG51000_MUXARRAY_INPUT_SEL_7 0x1707 +#define SLG51000_MUXARRAY_INPUT_SEL_8 0x1708 +#define SLG51000_MUXARRAY_INPUT_SEL_9 0x1709 +#define SLG51000_MUXARRAY_INPUT_SEL_10 0x170a +#define SLG51000_MUXARRAY_INPUT_SEL_11 0x170b +#define SLG51000_MUXARRAY_INPUT_SEL_12 0x170c +#define SLG51000_MUXARRAY_INPUT_SEL_13 0x170d +#define SLG51000_MUXARRAY_INPUT_SEL_14 0x170e +#define SLG51000_MUXARRAY_INPUT_SEL_15 0x170f +#define SLG51000_MUXARRAY_INPUT_SEL_16 0x1710 +#define SLG51000_MUXARRAY_INPUT_SEL_17 0x1711 +#define SLG51000_MUXARRAY_INPUT_SEL_18 0x1712 +#define SLG51000_MUXARRAY_INPUT_SEL_19 0x1713 +#define SLG51000_MUXARRAY_INPUT_SEL_20 0x1714 +#define SLG51000_MUXARRAY_INPUT_SEL_21 0x1715 +#define SLG51000_MUXARRAY_INPUT_SEL_22 0x1716 +#define SLG51000_MUXARRAY_INPUT_SEL_23 0x1717 +#define SLG51000_MUXARRAY_INPUT_SEL_24 0x1718 +#define SLG51000_MUXARRAY_INPUT_SEL_25 0x1719 +#define SLG51000_MUXARRAY_INPUT_SEL_26 0x171a +#define SLG51000_MUXARRAY_INPUT_SEL_27 0x171b +#define SLG51000_MUXARRAY_INPUT_SEL_28 0x171c +#define SLG51000_MUXARRAY_INPUT_SEL_29 0x171d +#define SLG51000_MUXARRAY_INPUT_SEL_30 0x171e +#define SLG51000_MUXARRAY_INPUT_SEL_31 0x171f +#define SLG51000_MUXARRAY_INPUT_SEL_32 0x1720 +#define SLG51000_MUXARRAY_INPUT_SEL_33 0x1721 +#define SLG51000_MUXARRAY_INPUT_SEL_34 0x1722 +#define SLG51000_MUXARRAY_INPUT_SEL_35 0x1723 +#define SLG51000_MUXARRAY_INPUT_SEL_36 0x1724 +#define SLG51000_MUXARRAY_INPUT_SEL_37 0x1725 +#define SLG51000_MUXARRAY_INPUT_SEL_38 0x1726 +#define SLG51000_MUXARRAY_INPUT_SEL_39 0x1727 +#define SLG51000_MUXARRAY_INPUT_SEL_40 0x1728 +#define SLG51000_MUXARRAY_INPUT_SEL_41 0x1729 +#define SLG51000_MUXARRAY_INPUT_SEL_42 0x172a +#define SLG51000_MUXARRAY_INPUT_SEL_43 0x172b +#define SLG51000_MUXARRAY_INPUT_SEL_44 0x172c +#define SLG51000_MUXARRAY_INPUT_SEL_45 0x172d +#define SLG51000_MUXARRAY_INPUT_SEL_46 0x172e +#define SLG51000_MUXARRAY_INPUT_SEL_47 0x172f +#define SLG51000_MUXARRAY_INPUT_SEL_48 0x1730 +#define SLG51000_MUXARRAY_INPUT_SEL_49 0x1731 +#define SLG51000_MUXARRAY_INPUT_SEL_50 0x1732 +#define SLG51000_MUXARRAY_INPUT_SEL_51 0x1733 +#define SLG51000_MUXARRAY_INPUT_SEL_52 0x1734 +#define SLG51000_MUXARRAY_INPUT_SEL_53 0x1735 +#define SLG51000_MUXARRAY_INPUT_SEL_54 0x1736 +#define SLG51000_MUXARRAY_INPUT_SEL_55 0x1737 +#define SLG51000_MUXARRAY_INPUT_SEL_56 0x1738 +#define SLG51000_MUXARRAY_INPUT_SEL_57 0x1739 +#define SLG51000_MUXARRAY_INPUT_SEL_58 0x173a +#define SLG51000_MUXARRAY_INPUT_SEL_59 0x173b +#define SLG51000_MUXARRAY_INPUT_SEL_60 0x173c +#define SLG51000_MUXARRAY_INPUT_SEL_61 0x173d +#define SLG51000_MUXARRAY_INPUT_SEL_62 0x173e +#define SLG51000_MUXARRAY_INPUT_SEL_63 0x173f +#define SLG51000_PWRSEQ_RESOURCE_EN_0 0x1900 +#define SLG51000_PWRSEQ_RESOURCE_EN_1 0x1901 +#define SLG51000_PWRSEQ_RESOURCE_EN_2 0x1902 +#define SLG51000_PWRSEQ_RESOURCE_EN_3 0x1903 +#define SLG51000_PWRSEQ_RESOURCE_EN_4 0x1904 +#define SLG51000_PWRSEQ_RESOURCE_EN_5 0x1905 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP0 0x1906 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN0 0x1907 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP1 0x1908 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN1 0x1909 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP2 0x190a +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN2 0x190b +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP3 0x190c +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN3 0x190d +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP4 0x190e +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN4 0x190f +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_UP5 0x1910 +#define SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN5 0x1911 +#define SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_A 0x1912 +#define SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_B 0x1913 +#define SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_C 0x1914 +#define SLG51000_PWRSEQ_INPUT_SENSE_CONF_A 0x1915 +#define SLG51000_PWRSEQ_INPUT_SENSE_CONF_B 0x1916 +#define SLG51000_LDO1_VSEL 0x2000 +#define SLG51000_LDO1_MINV 0x2060 +#define SLG51000_LDO1_MAXV 0x2061 +#define SLG51000_LDO1_MISC1 0x2064 +#define SLG51000_LDO1_VSEL_ACTUAL 0x2065 +#define SLG51000_LDO1_EVENT 0x20c0 +#define SLG51000_LDO1_STATUS 0x20c1 +#define SLG51000_LDO1_IRQ_MASK 0x20c2 +#define SLG51000_LDO2_VSEL 0x2200 +#define SLG51000_LDO2_MINV 0x2260 +#define SLG51000_LDO2_MAXV 0x2261 +#define SLG51000_LDO2_MISC1 0x2264 +#define SLG51000_LDO2_VSEL_ACTUAL 0x2265 +#define SLG51000_LDO2_EVENT 0x22c0 +#define SLG51000_LDO2_STATUS 0x22c1 +#define SLG51000_LDO2_IRQ_MASK 0x22c2 +#define SLG51000_LDO3_VSEL 0x2300 +#define SLG51000_LDO3_MINV 0x2360 +#define SLG51000_LDO3_MAXV 0x2361 +#define SLG51000_LDO3_CONF1 0x2364 +#define SLG51000_LDO3_CONF2 0x2365 +#define SLG51000_LDO3_VSEL_ACTUAL 0x2366 +#define SLG51000_LDO3_EVENT 0x23c0 +#define SLG51000_LDO3_STATUS 0x23c1 +#define SLG51000_LDO3_IRQ_MASK 0x23c2 +#define SLG51000_LDO4_VSEL 0x2500 +#define SLG51000_LDO4_MINV 0x2560 +#define SLG51000_LDO4_MAXV 0x2561 +#define SLG51000_LDO4_CONF1 0x2564 +#define SLG51000_LDO4_CONF2 0x2565 +#define SLG51000_LDO4_VSEL_ACTUAL 0x2566 +#define SLG51000_LDO4_EVENT 0x25c0 +#define SLG51000_LDO4_STATUS 0x25c1 +#define SLG51000_LDO4_IRQ_MASK 0x25c2 +#define SLG51000_LDO5_VSEL 0x2700 +#define SLG51000_LDO5_MINV 0x2760 +#define SLG51000_LDO5_MAXV 0x2761 +#define SLG51000_LDO5_TRIM2 0x2763 +#define SLG51000_LDO5_CONF1 0x2765 +#define SLG51000_LDO5_CONF2 0x2766 +#define SLG51000_LDO5_VSEL_ACTUAL 0x2767 +#define SLG51000_LDO5_EVENT 0x27c0 +#define SLG51000_LDO5_STATUS 0x27c1 +#define SLG51000_LDO5_IRQ_MASK 0x27c2 +#define SLG51000_LDO6_VSEL 0x2900 +#define SLG51000_LDO6_MINV 0x2960 +#define SLG51000_LDO6_MAXV 0x2961 +#define SLG51000_LDO6_TRIM2 0x2963 +#define SLG51000_LDO6_CONF1 0x2965 +#define SLG51000_LDO6_CONF2 0x2966 +#define SLG51000_LDO6_VSEL_ACTUAL 0x2967 +#define SLG51000_LDO6_EVENT 0x29c0 +#define SLG51000_LDO6_STATUS 0x29c1 +#define SLG51000_LDO6_IRQ_MASK 0x29c2 +#define SLG51000_LDO7_VSEL 0x3100 +#define SLG51000_LDO7_MINV 0x3160 +#define SLG51000_LDO7_MAXV 0x3161 +#define SLG51000_LDO7_CONF1 0x3164 +#define SLG51000_LDO7_CONF2 0x3165 +#define SLG51000_LDO7_VSEL_ACTUAL 0x3166 +#define SLG51000_LDO7_EVENT 0x31c0 +#define SLG51000_LDO7_STATUS 0x31c1 +#define SLG51000_LDO7_IRQ_MASK 0x31c2 +#define SLG51000_OTP_EVENT 0x782b +#define SLG51000_OTP_IRQ_MASK 0x782d +#define SLG51000_OTP_LOCK_OTP_PROG 0x78fe +#define SLG51000_OTP_LOCK_CTRL 0x78ff +#define SLG51000_LOCK_GLOBAL_LOCK_CTRL1 0x8000 + +/* Register Bit Fields */ + +/* SLG51000_SYSCTL_PATTERN_ID_BYTE0 = 0x1105 */ +#define SLG51000_PATTERN_ID_BYTE0_SHIFT 0 +#define SLG51000_PATTERN_ID_BYTE0_MASK (0xff << 0) + +/* SLG51000_SYSCTL_PATTERN_ID_BYTE1 = 0x1106 */ +#define SLG51000_PATTERN_ID_BYTE1_SHIFT 0 +#define SLG51000_PATTERN_ID_BYTE1_MASK (0xff << 0) + +/* SLG51000_SYSCTL_PATTERN_ID_BYTE2 = 0x1107 */ +#define SLG51000_PATTERN_ID_BYTE2_SHIFT 0 +#define SLG51000_PATTERN_ID_BYTE2_MASK (0xff << 0) + +/* SLG51000_SYSCTL_SYS_CONF_A = 0x1109 */ +#define SLG51000_I2C_ADDRESS_SHIFT 0 +#define SLG51000_I2C_ADDRESS_MASK (0x7f << 0) +#define SLG51000_I2C_DISABLE_SHIFT 7 +#define SLG51000_I2C_DISABLE_MASK (0x01 << 7) + +/* SLG51000_SYSCTL_SYS_CONF_D = 0x110c */ +#define SLG51000_CS_T_DEB_SHIFT 6 +#define SLG51000_CS_T_DEB_MASK (0x03 << 6) +#define SLG51000_I2C_CLR_MODE_SHIFT 5 +#define SLG51000_I2C_CLR_MODE_MASK (0x01 << 5) + +/* SLG51000_SYSCTL_MATRIX_CTRL_CONF_A = 0x110d */ +#define SLG51000_RESOURCE_CTRL_SHIFT 0 +#define SLG51000_RESOURCE_CTRL_MASK (0xff << 0) + +/* SLG51000_SYSCTL_MATRIX_CTRL_CONF_B = 0x110e */ +#define SLG51000_MATRIX_EVENT_SENSE_SHIFT 0 +#define SLG51000_MATRIX_EVENT_SENSE_MASK (0x07 << 0) + +/* SLG51000_SYSCTL_REFGEN_CONF_C = 0x1111 */ +#define SLG51000_REFGEN_SEL_TEMP_WARN_DEBOUNCE_SHIFT 2 +#define SLG51000_REFGEN_SEL_TEMP_WARN_DEBOUNCE_MASK (0x03 << 2) +#define SLG51000_REFGEN_SEL_TEMP_WARN_THR_SHIFT 0 +#define SLG51000_REFGEN_SEL_TEMP_WARN_THR_MASK (0x03 << 0) + +/* SLG51000_SYSCTL_UVLO_CONF_A = 0x1112 */ +#define SLG51000_VMON_UVLO_SEL_THR_SHIFT 0 +#define SLG51000_VMON_UVLO_SEL_THR_MASK (0x1f << 0) + +/* SLG51000_SYSCTL_FAULT_LOG1 = 0x1115 */ +#define SLG51000_FLT_POR_SHIFT 5 +#define SLG51000_FLT_POR_MASK (0x01 << 5) +#define SLG51000_FLT_RST_SHIFT 4 +#define SLG51000_FLT_RST_MASK (0x01 << 4) +#define SLG51000_FLT_POWER_SEQ_CRASH_REQ_SHIFT 2 +#define SLG51000_FLT_POWER_SEQ_CRASH_REQ_MASK (0x01 << 2) +#define SLG51000_FLT_OVER_TEMP_SHIFT 1 +#define SLG51000_FLT_OVER_TEMP_MASK (0x01 << 1) + +/* SLG51000_SYSCTL_EVENT = 0x1116 */ +#define SLG51000_EVT_MATRIX_SHIFT 1 +#define SLG51000_EVT_MATRIX_MASK (0x01 << 1) +#define SLG51000_EVT_HIGH_TEMP_WARN_SHIFT 0 +#define SLG51000_EVT_HIGH_TEMP_WARN_MASK (0x01 << 0) + +/* SLG51000_SYSCTL_STATUS = 0x1117 */ +#define SLG51000_STA_MATRIX_SHIFT 1 +#define SLG51000_STA_MATRIX_MASK (0x01 << 1) +#define SLG51000_STA_HIGH_TEMP_WARN_SHIFT 0 +#define SLG51000_STA_HIGH_TEMP_WARN_MASK (0x01 << 0) + +/* SLG51000_SYSCTL_IRQ_MASK = 0x1118 */ +#define SLG51000_IRQ_MATRIX_SHIFT 1 +#define SLG51000_IRQ_MATRIX_MASK (0x01 << 1) +#define SLG51000_IRQ_HIGH_TEMP_WARN_SHIFT 0 +#define SLG51000_IRQ_HIGH_TEMP_WARN_MASK (0x01 << 0) + +/* SLG51000_IO_GPIO1_CONF ~ SLG51000_IO_GPIO5_CONF = + * 0x1500, 0x1501, 0x1502, 0x1503, 0x1504 + */ +#define SLG51000_GPIO_DIR_SHIFT 7 +#define SLG51000_GPIO_DIR_MASK (0x01 << 7) +#define SLG51000_GPIO_SENS_SHIFT 5 +#define SLG51000_GPIO_SENS_MASK (0x03 << 5) +#define SLG51000_GPIO_INVERT_SHIFT 4 +#define SLG51000_GPIO_INVERT_MASK (0x01 << 4) +#define SLG51000_GPIO_BYP_SHIFT 3 +#define SLG51000_GPIO_BYP_MASK (0x01 << 3) +#define SLG51000_GPIO_T_DEB_SHIFT 1 +#define SLG51000_GPIO_T_DEB_MASK (0x03 << 1) +#define SLG51000_GPIO_LEVEL_SHIFT 0 +#define SLG51000_GPIO_LEVEL_MASK (0x01 << 0) + +/* SLG51000_IO_GPIO6_CONF = 0x1505 */ +#define SLG51000_GPIO6_SENS_SHIFT 5 +#define SLG51000_GPIO6_SENS_MASK (0x03 << 5) +#define SLG51000_GPIO6_INVERT_SHIFT 4 +#define SLG51000_GPIO6_INVERT_MASK (0x01 << 4) +#define SLG51000_GPIO6_T_DEB_SHIFT 1 +#define SLG51000_GPIO6_T_DEB_MASK (0x03 << 1) +#define SLG51000_GPIO6_LEVEL_SHIFT 0 +#define SLG51000_GPIO6_LEVEL_MASK (0x01 << 0) + +/* SLG51000_IO_GPIO_STATUS = 0x1506 */ +#define SLG51000_GPIO6_STATUS_SHIFT 5 +#define SLG51000_GPIO6_STATUS_MASK (0x01 << 5) +#define SLG51000_GPIO5_STATUS_SHIFT 4 +#define SLG51000_GPIO5_STATUS_MASK (0x01 << 4) +#define SLG51000_GPIO4_STATUS_SHIFT 3 +#define SLG51000_GPIO4_STATUS_MASK (0x01 << 3) +#define SLG51000_GPIO3_STATUS_SHIFT 2 +#define SLG51000_GPIO3_STATUS_MASK (0x01 << 2) +#define SLG51000_GPIO2_STATUS_SHIFT 1 +#define SLG51000_GPIO2_STATUS_MASK (0x01 << 1) +#define SLG51000_GPIO1_STATUS_SHIFT 0 +#define SLG51000_GPIO1_STATUS_MASK (0x01 << 0) + +/* SLG51000_LUTARRAY_LUT_VAL_0 ~ SLG51000_LUTARRAY_LUT_VAL_11 + * 0x1600, 0x1601, 0x1602, 0x1603, 0x1604, 0x1605, + * 0x1606, 0x1607, 0x1608, 0x1609, 0x160a, 0x160b + */ +#define SLG51000_LUT_VAL_SHIFT 0 +#define SLG51000_LUT_VAL_MASK (0xff << 0) + +/* SLG51000_MUXARRAY_INPUT_SEL_0 ~ SLG51000_MUXARRAY_INPUT_SEL_63 + * 0x1700, 0x1701, 0x1702, 0x1703, 0x1704, 0x1705, + * 0x1706, 0x1707, 0x1708, 0x1709, 0x170a, 0x170b, + * 0x170c, 0x170d, 0x170e, 0x170f, 0x1710, 0x1711, + * 0x1712, 0x1713, 0x1714, 0x1715, 0x1716, 0x1717, + * 0x1718, 0x1719, 0x171a, 0x171b, 0x171c, 0x171d, + * 0x171e, 0x171f, 0x1720, 0x1721, 0x1722, 0x1723, + * 0x1724, 0x1725, 0x1726, 0x1727, 0x1728, 0x1729, + * 0x173a, 0x173b, 0x173c, 0x173d, 0x173e, 0x173f, + */ +#define SLG51000_INPUT_SEL_SHIFT 0 +#define SLG51000_INPUT_SEL_MASK (0x3f << 0) + +/* SLG51000_PWRSEQ_RESOURCE_EN_0 ~ SLG51000_PWRSEQ_RESOURCE_EN_5 + * 0x1900, 0x1901, 0x1902, 0x1903, 0x1904, 0x1905 + */ +#define SLG51000_RESOURCE_EN_DOWN0_SHIFT 4 +#define SLG51000_RESOURCE_EN_DOWN0_MASK (0x07 << 4) +#define SLG51000_RESOURCE_EN_UP0_SHIFT 0 +#define SLG51000_RESOURCE_EN_UP0_MASK (0x07 << 0) + +/* SLG51000_PWRSEQ_SLOT_TIME_MIN_UP0 ~ SLG51000_PWRSEQ_SLOT_TIME_MIN_UP5 + * 0x1906, 0x1908, 0x190a, 0x190c, 0x190e, 0x1910 + */ +#define SLG51000_SLOT_TIME_MIN_UP_SHIFT 0 +#define SLG51000_SLOT_TIME_MIN_UP_MASK (0xff << 0) + +/* SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN0 ~ SLG51000_PWRSEQ_SLOT_TIME_MIN_DOWN5 + * 0x1907, 0x1909, 0x190b, 0x190d, 0x190f, 0x1911 + */ +#define SLG51000_SLOT_TIME_MIN_DOWN_SHIFT 0 +#define SLG51000_SLOT_TIME_MIN_DOWN_MASK (0xff << 0) + +/* SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_A ~ SLG51000_PWRSEQ_SLOT_TIME_MAX_CONF_C + * 0x1912, 0x1913, 0x1914 + */ +#define SLG51000_SLOT_TIME_MAX_DOWN1_SHIFT 6 +#define SLG51000_SLOT_TIME_MAX_DOWN1_MASK (0x03 << 6) +#define SLG51000_SLOT_TIME_MAX_UP1_SHIFT 4 +#define SLG51000_SLOT_TIME_MAX_UP1_MASK (0x03 << 4) +#define SLG51000_SLOT_TIME_MAX_DOWN0_SHIFT 2 +#define SLG51000_SLOT_TIME_MAX_DOWN0_MASK (0x03 << 2) +#define SLG51000_SLOT_TIME_MAX_UP0_SHIFT 0 +#define SLG51000_SLOT_TIME_MAX_UP0_MASK (0x03 << 0) + +/* SLG51000_PWRSEQ_INPUT_SENSE_CONF_A = 0x1915 */ +#define SLG51000_TRIG_UP_SENSE_SHIFT 6 +#define SLG51000_TRIG_UP_SENSE_MASK (0x01 << 6) +#define SLG51000_UP_EN_SENSE5_SHIFT 5 +#define SLG51000_UP_EN_SENSE5_MASK (0x01 << 5) +#define SLG51000_UP_EN_SENSE4_SHIFT 4 +#define SLG51000_UP_EN_SENSE4_MASK (0x01 << 4) +#define SLG51000_UP_EN_SENSE3_SHIFT 3 +#define SLG51000_UP_EN_SENSE3_MASK (0x01 << 3) +#define SLG51000_UP_EN_SENSE2_SHIFT 2 +#define SLG51000_UP_EN_SENSE2_MASK (0x01 << 2) +#define SLG51000_UP_EN_SENSE1_SHIFT 1 +#define SLG51000_UP_EN_SENSE1_MASK (0x01 << 1) +#define SLG51000_UP_EN_SENSE0_SHIFT 0 +#define SLG51000_UP_EN_SENSE0_MASK (0x01 << 0) + +/* SLG51000_PWRSEQ_INPUT_SENSE_CONF_B = 0x1916 */ +#define SLG51000_CRASH_DETECT_SENSE_SHIFT 7 +#define SLG51000_CRASH_DETECT_SENSE_MASK (0x01 << 7) +#define SLG51000_TRIG_DOWN_SENSE_SHIFT 6 +#define SLG51000_TRIG_DOWN_SENSE_MASK (0x01 << 6) +#define SLG51000_DOWN_EN_SENSE5_SHIFT 5 +#define SLG51000_DOWN_EN_SENSE5_MASK (0x01 << 5) +#define SLG51000_DOWN_EN_SENSE4_SHIFT 4 +#define SLG51000_DOWN_EN_SENSE4_MASK (0x01 << 4) +#define SLG51000_DOWN_EN_SENSE3_SHIFT 3 +#define SLG51000_DOWN_EN_SENSE3_MASK (0x01 << 3) +#define SLG51000_DOWN_EN_SENSE2_SHIFT 2 +#define SLG51000_DOWN_EN_SENSE2_MASK (0x01 << 2) +#define SLG51000_DOWN_EN_SENSE1_SHIFT 1 +#define SLG51000_DOWN_EN_SENSE1_MASK (0x01 << 1) +#define SLG51000_DOWN_EN_SENSE0_SHIFT 0 +#define SLG51000_DOWN_EN_SENSE0_MASK (0x01 << 0) + +/* SLG51000_LDO1_VSEL ~ SLG51000_LDO7_VSEL = + * 0x2000, 0x2200, 0x2300, 0x2500, 0x2700, 0x2900, 0x3100 + */ +#define SLG51000_VSEL_SHIFT 0 +#define SLG51000_VSEL_MASK (0xff << 0) + +/* SLG51000_LDO1_MINV ~ SLG51000_LDO7_MINV = + * 0x2060, 0x2260, 0x2360, 0x2560, 0x2760, 0x2960, 0x3160 + */ +#define SLG51000_MINV_SHIFT 0 +#define SLG51000_MINV_MASK (0xff << 0) + +/* SLG51000_LDO1_MAXV ~ SLG51000_LDO7_MAXV = + * 0x2061, 0x2261, 0x2361, 0x2561, 0x2761, 0x2961, 0x3161 + */ +#define SLG51000_MAXV_SHIFT 0 +#define SLG51000_MAXV_MASK (0xff << 0) + +/* SLG51000_LDO1_MISC1 = 0x2064, SLG51000_LDO2_MISC1 = 0x2264 */ +#define SLG51000_SEL_VRANGE_SHIFT 0 +#define SLG51000_SEL_VRANGE_MASK (0x01 << 0) + +/* SLG51000_LDO1_VSEL_ACTUAL ~ SLG51000_LDO7_VSEL_ACTUAL = + * 0x2065, 0x2265, 0x2366, 0x2566, 0x2767, 0x2967, 0x3166 + */ +#define SLG51000_VSEL_ACTUAL_SHIFT 0 +#define SLG51000_VSEL_ACTUAL_MASK (0xff << 0) + +/* SLG51000_LDO1_EVENT ~ SLG51000_LDO7_EVENT = + * 0x20c0, 0x22c0, 0x23c0, 0x25c0, 0x27c0, 0x29c0, 0x31c0 + */ +#define SLG51000_EVT_ILIM_FLAG_SHIFT 0 +#define SLG51000_EVT_ILIM_FLAG_MASK (0x01 << 0) +#define SLG51000_EVT_VOUT_OK_FLAG_SHIFT 1 +#define SLG51000_EVT_VOUT_OK_FLAG_MASK (0x01 << 1) + +/* SLG51000_LDO1_STATUS ~ SLG51000_LDO7_STATUS = + * 0x20c1, 0x22c1, 0x23c1, 0x25c1, 0x27c1, 0x29c1, 0x31c1 + */ +#define SLG51000_STA_ILIM_FLAG_SHIFT 0 +#define SLG51000_STA_ILIM_FLAG_MASK (0x01 << 0) +#define SLG51000_STA_VOUT_OK_FLAG_SHIFT 1 +#define SLG51000_STA_VOUT_OK_FLAG_MASK (0x01 << 1) + +/* SLG51000_LDO1_IRQ_MASK ~ SLG51000_LDO7_IRQ_MASK = + * 0x20c2, 0x22c2, 0x23c2, 0x25c2, 0x27c2, 0x29c2, 0x31c2 + */ +#define SLG51000_IRQ_ILIM_FLAG_SHIFT 0 +#define SLG51000_IRQ_ILIM_FLAG_MASK (0x01 << 0) + +/* SLG51000_LDO3_CONF1 ~ SLG51000_LDO7_CONF1 = + * 0x2364, 0x2564, 0x2765, 0x2965, 0x3164 + */ +#define SLG51000_SEL_START_ILIM_SHIFT 0 +#define SLG51000_SEL_START_ILIM_MASK (0x7f << 0) + +/* SLG51000_LDO3_CONF2 ~ SLG51000_LDO7_CONF2 = + * 0x2365, 0x2565, 0x2766, 0x2966, 0x3165 + */ +#define SLG51000_SEL_FUNC_ILIM_SHIFT 0 +#define SLG51000_SEL_FUNC_ILIM_MASK (0x7f << 0) + +/* SLG51000_LDO5_TRIM2 = 0x2763, SLG51000_LDO6_TRIM2 = 0x2963 */ +#define SLG51000_SEL_BYP_SLEW_RATE_SHIFT 2 +#define SLG51000_SEL_BYP_SLEW_RATE_MASK (0x03 << 2) +#define SLG51000_SEL_BYP_VGATE_SHIFT 1 +#define SLG51000_SEL_BYP_VGATE_MASK (0x01 << 1) +#define SLG51000_SEL_BYP_MODE_SHIFT 0 +#define SLG51000_SEL_BYP_MODE_MASK (0x01 << 0) + +/* SLG51000_OTP_EVENT = 0x782b */ +#define SLG51000_EVT_CRC_SHIFT 0 +#define SLG51000_EVT_CRC_MASK (0x01 << 0) + +/* SLG51000_OTP_IRQ_MASK = 0x782d */ +#define SLG51000_IRQ_CRC_SHIFT 0 +#define SLG51000_IRQ_CRC_MASK (0x01 << 0) + +/* SLG51000_OTP_LOCK_OTP_PROG = 0x78fe */ +#define SLG51000_LOCK_OTP_PROG_SHIFT 0 +#define SLG51000_LOCK_OTP_PROG_MASK (0x01 << 0) + +/* SLG51000_OTP_LOCK_CTRL = 0x78ff */ +#define SLG51000_LOCK_DFT_SHIFT 1 +#define SLG51000_LOCK_DFT_MASK (0x01 << 1) +#define SLG51000_LOCK_RWT_SHIFT 0 +#define SLG51000_LOCK_RWT_MASK (0x01 << 0) + +/* SLG51000_LOCK_GLOBAL_LOCK_CTRL1 = 0x8000 */ +#define SLG51000_LDO7_LOCK_SHIFT 7 +#define SLG51000_LDO7_LOCK_MASK (0x01 << 7) +#define SLG51000_LDO6_LOCK_SHIFT 6 +#define SLG51000_LDO6_LOCK_MASK (0x01 << 6) +#define SLG51000_LDO5_LOCK_SHIFT 5 +#define SLG51000_LDO5_LOCK_MASK (0x01 << 5) +#define SLG51000_LDO4_LOCK_SHIFT 4 +#define SLG51000_LDO4_LOCK_MASK (0x01 << 4) +#define SLG51000_LDO3_LOCK_SHIFT 3 +#define SLG51000_LDO3_LOCK_MASK (0x01 << 3) +#define SLG51000_LDO2_LOCK_SHIFT 2 +#define SLG51000_LDO2_LOCK_MASK (0x01 << 2) +#define SLG51000_LDO1_LOCK_SHIFT 1 +#define SLG51000_LDO1_LOCK_MASK (0x01 << 1) + +#endif /* __SLG51000_REGISTERS_H__ */ + diff --git a/drivers/regulator/stm32-booster.c b/drivers/regulator/stm32-booster.c new file mode 100644 index 000000000000..2a897666c650 --- /dev/null +++ b/drivers/regulator/stm32-booster.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2019 +// Author(s): Fabrice Gasnier <fabrice.gasnier@st.com>. + +#include <linux/mfd/syscon.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/regulator/of_regulator.h> + +/* STM32H7 SYSCFG register */ +#define STM32H7_SYSCFG_PMCR 0x04 +#define STM32H7_SYSCFG_BOOSTE_MASK BIT(8) + +/* STM32MP1 SYSCFG has set and clear registers */ +#define STM32MP1_SYSCFG_PMCSETR 0x04 +#define STM32MP1_SYSCFG_PMCCLRR 0x44 +#define STM32MP1_SYSCFG_EN_BOOSTER_MASK BIT(8) + +static const struct regulator_ops stm32h7_booster_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_desc stm32h7_booster_desc = { + .name = "booster", + .supply_name = "vdda", + .n_voltages = 1, + .type = REGULATOR_VOLTAGE, + .min_uV = 3300000, + .fixed_uV = 3300000, + .ramp_delay = 66000, /* up to 50us to stabilize */ + .ops = &stm32h7_booster_ops, + .enable_reg = STM32H7_SYSCFG_PMCR, + .enable_mask = STM32H7_SYSCFG_BOOSTE_MASK, + .owner = THIS_MODULE, +}; + +static int stm32mp1_booster_enable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, STM32MP1_SYSCFG_PMCSETR, + STM32MP1_SYSCFG_EN_BOOSTER_MASK); +} + +static int stm32mp1_booster_disable(struct regulator_dev *rdev) +{ + return regmap_write(rdev->regmap, STM32MP1_SYSCFG_PMCCLRR, + STM32MP1_SYSCFG_EN_BOOSTER_MASK); +} + +static const struct regulator_ops stm32mp1_booster_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = stm32mp1_booster_enable, + .disable = stm32mp1_booster_disable, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_desc stm32mp1_booster_desc = { + .name = "booster", + .supply_name = "vdda", + .n_voltages = 1, + .type = REGULATOR_VOLTAGE, + .min_uV = 3300000, + .fixed_uV = 3300000, + .ramp_delay = 66000, + .ops = &stm32mp1_booster_ops, + .enable_reg = STM32MP1_SYSCFG_PMCSETR, + .enable_mask = STM32MP1_SYSCFG_EN_BOOSTER_MASK, + .owner = THIS_MODULE, +}; + +static int stm32_booster_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + struct regulator_config config = { }; + const struct regulator_desc *desc; + struct regulator_dev *rdev; + struct regmap *regmap; + int ret; + + regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + desc = (const struct regulator_desc *) + of_match_device(dev->driver->of_match_table, dev)->data; + + config.regmap = regmap; + config.dev = dev; + config.of_node = np; + config.init_data = of_get_regulator_init_data(dev, np, desc); + + rdev = devm_regulator_register(dev, desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "register failed with error %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id stm32_booster_of_match[] = { + { + .compatible = "st,stm32h7-booster", + .data = (void *)&stm32h7_booster_desc + }, { + .compatible = "st,stm32mp1-booster", + .data = (void *)&stm32mp1_booster_desc + }, { + }, +}; +MODULE_DEVICE_TABLE(of, stm32_booster_of_match); + +static struct platform_driver stm32_booster_driver = { + .probe = stm32_booster_probe, + .driver = { + .name = "stm32-booster", + .of_match_table = of_match_ptr(stm32_booster_of_match), + }, +}; +module_platform_driver(stm32_booster_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics STM32 booster regulator driver"); +MODULE_ALIAS("platform:stm32-booster"); diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index ca39b3d55123..10ea4b5a0f55 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -371,11 +371,12 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( "dcdc-ext-control-gpios", 0, gflags, "tps65090"); - if (IS_ERR(rpdata->gpiod)) - return ERR_CAST(rpdata->gpiod); - if (!rpdata->gpiod) + if (PTR_ERR(rpdata->gpiod) == -ENOENT) { dev_err(&pdev->dev, "could not find DCDC external control GPIO\n"); + rpdata->gpiod = NULL; + } else if (IS_ERR(rpdata->gpiod)) + return ERR_CAST(rpdata->gpiod); } if (of_property_read_u32(tps65090_matches[idx].of_node, diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index b422eef97b77..018dbbd96771 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -15,7 +15,7 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/mfd/wm831x/core.h> @@ -50,7 +50,7 @@ struct wm831x_dcdc { int base; struct wm831x *wm831x; struct regulator_dev *regulator; - int dvs_gpio; + struct gpio_desc *dvs_gpiod; int dvs_gpio_state; int on_vsel; int dvs_vsel; @@ -217,7 +217,7 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) return 0; dcdc->dvs_gpio_state = state; - gpio_set_value(dcdc->dvs_gpio, state); + gpiod_set_value(dcdc->dvs_gpiod, state); /* Should wait for DVS state change to be asserted if we have * a GPIO for it, for now assume the device is configured @@ -237,10 +237,10 @@ static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev, int ret; /* If this value is already set then do a GPIO update if we can */ - if (dcdc->dvs_gpio && dcdc->on_vsel == vsel) + if (dcdc->dvs_gpiod && dcdc->on_vsel == vsel) return wm831x_buckv_set_dvs(rdev, 0); - if (dcdc->dvs_gpio && dcdc->dvs_vsel == vsel) + if (dcdc->dvs_gpiod && dcdc->dvs_vsel == vsel) return wm831x_buckv_set_dvs(rdev, 1); /* Always set the ON status to the minimum voltage */ @@ -249,7 +249,7 @@ static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev, return ret; dcdc->on_vsel = vsel; - if (!dcdc->dvs_gpio) + if (!dcdc->dvs_gpiod) return ret; /* Kick the voltage transition now */ @@ -296,7 +296,7 @@ static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); - if (dcdc->dvs_gpio && dcdc->dvs_gpio_state) + if (dcdc->dvs_gpiod && dcdc->dvs_gpio_state) return dcdc->dvs_vsel; else return dcdc->on_vsel; @@ -337,7 +337,7 @@ static void wm831x_buckv_dvs_init(struct platform_device *pdev, int ret; u16 ctrl; - if (!pdata || !pdata->dvs_gpio) + if (!pdata) return; /* gpiolib won't let us read the GPIO status so pick the higher @@ -345,17 +345,14 @@ static void wm831x_buckv_dvs_init(struct platform_device *pdev, */ dcdc->dvs_gpio_state = pdata->dvs_init_state; - ret = devm_gpio_request_one(&pdev->dev, pdata->dvs_gpio, - dcdc->dvs_gpio_state ? GPIOF_INIT_HIGH : 0, - "DCDC DVS"); - if (ret < 0) { - dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", - dcdc->name, ret); + dcdc->dvs_gpiod = devm_gpiod_get(&pdev->dev, "dvs", + dcdc->dvs_gpio_state ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW); + if (IS_ERR(dcdc->dvs_gpiod)) { + dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %ld\n", + dcdc->name, PTR_ERR(dcdc->dvs_gpiod)); return; } - dcdc->dvs_gpio = pdata->dvs_gpio; - switch (pdata->dvs_control_src) { case 1: ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; diff --git a/include/linux/mfd/da9062/registers.h b/include/linux/mfd/da9062/registers.h index fe04b708742b..2906bf6160fb 100644 --- a/include/linux/mfd/da9062/registers.h +++ b/include/linux/mfd/da9062/registers.h @@ -797,6 +797,9 @@ #define DA9062AA_BUCK3_SL_A_SHIFT 7 #define DA9062AA_BUCK3_SL_A_MASK BIT(7) +/* DA9062AA_VLDO[1-4]_A common */ +#define DA9062AA_VLDO_A_MIN_SEL 2 + /* DA9062AA_VLDO1_A = 0x0A9 */ #define DA9062AA_VLDO1_A_SHIFT 0 #define DA9062AA_VLDO1_A_MASK 0x3f diff --git a/include/linux/mfd/da9063/pdata.h b/include/linux/mfd/da9063/pdata.h index 77c566ab96ab..085edbf7601b 100644 --- a/include/linux/mfd/da9063/pdata.h +++ b/include/linux/mfd/da9063/pdata.h @@ -11,55 +11,6 @@ #ifndef __MFD_DA9063_PDATA_H__ #define __MFD_DA9063_PDATA_H__ -#include <linux/regulator/machine.h> - -/* - * Regulator configuration - */ -/* DA9063 and DA9063L regulator IDs */ -enum { - /* BUCKs */ - DA9063_ID_BCORE1, - DA9063_ID_BCORE2, - DA9063_ID_BPRO, - DA9063_ID_BMEM, - DA9063_ID_BIO, - DA9063_ID_BPERI, - - /* BCORE1 and BCORE2 in merged mode */ - DA9063_ID_BCORES_MERGED, - /* BMEM and BIO in merged mode */ - DA9063_ID_BMEM_BIO_MERGED, - /* When two BUCKs are merged, they cannot be reused separately */ - - /* LDOs on both DA9063 and DA9063L */ - DA9063_ID_LDO3, - DA9063_ID_LDO7, - DA9063_ID_LDO8, - DA9063_ID_LDO9, - DA9063_ID_LDO11, - - /* DA9063-only LDOs */ - DA9063_ID_LDO1, - DA9063_ID_LDO2, - DA9063_ID_LDO4, - DA9063_ID_LDO5, - DA9063_ID_LDO6, - DA9063_ID_LDO10, -}; - -/* Regulators platform data */ -struct da9063_regulator_data { - int id; - struct regulator_init_data *initdata; -}; - -struct da9063_regulators_pdata { - unsigned n_regulators; - struct da9063_regulator_data *regulator_data; -}; - - /* * RGB LED configuration */ diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 3ca17eb89aa2..f1631a39acfc 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -20,6 +20,7 @@ #define MIN_850_MV 850000 #define MIN_800_MV 800000 #define MIN_750_MV 750000 +#define MIN_650_MV 650000 #define MIN_600_MV 600000 #define MIN_500_MV 500000 diff --git a/include/linux/mfd/samsung/s2mps11.h b/include/linux/mfd/samsung/s2mps11.h index 6e7668a389a1..4805c90609c4 100644 --- a/include/linux/mfd/samsung/s2mps11.h +++ b/include/linux/mfd/samsung/s2mps11.h @@ -170,7 +170,9 @@ enum s2mps11_regulators { #define S2MPS11_ENABLE_MASK (0x03 << S2MPS11_ENABLE_SHIFT) #define S2MPS11_ENABLE_SHIFT 0x06 #define S2MPS11_LDO_N_VOLTAGES (S2MPS11_LDO_VSEL_MASK + 1) -#define S2MPS11_BUCK_N_VOLTAGES (S2MPS11_BUCK_VSEL_MASK + 1) +#define S2MPS11_BUCK12346_N_VOLTAGES 153 +#define S2MPS11_BUCK5_N_VOLTAGES 216 +#define S2MPS11_BUCK7810_N_VOLTAGES 225 #define S2MPS11_BUCK9_N_VOLTAGES (S2MPS11_BUCK9_VSEL_MASK + 1) #define S2MPS11_RAMP_DELAY 25000 /* uV/us */ @@ -188,4 +190,9 @@ enum s2mps11_regulators { #define S2MPS11_BUCK6_RAMP_EN_SHIFT 0 #define S2MPS11_PMIC_EN_SHIFT 6 +/* + * Bits for "enable suspend" (On/Off controlled by PWREN) + * are the same as in S2MPS14: S2MPS14_ENABLE_SUSPEND + */ + #endif /* __LINUX_MFD_S2MPS11_H */ diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h index 071cdf3e16cf..986986fe4e4e 100644 --- a/include/linux/mfd/wm831x/pdata.h +++ b/include/linux/mfd/wm831x/pdata.h @@ -47,7 +47,6 @@ struct wm831x_battery_pdata { * I2C or SPI buses. */ struct wm831x_buckv_pdata { - int dvs_gpio; /** CPU GPIO to use for DVS switching */ int dvs_control_src; /** Hardware DVS source to use (1 or 2) */ int dvs_init_state; /** DVS state to expect on startup */ int dvs_state_gpio; /** CPU GPIO to use for monitoring status */ diff --git a/include/linux/regulator/coupler.h b/include/linux/regulator/coupler.h new file mode 100644 index 000000000000..0212d6255e4e --- /dev/null +++ b/include/linux/regulator/coupler.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * coupler.h -- SoC Regulator support, coupler API. + * + * Regulator Coupler Interface. + */ + +#ifndef __LINUX_REGULATOR_COUPLER_H_ +#define __LINUX_REGULATOR_COUPLER_H_ + +#include <linux/kernel.h> +#include <linux/suspend.h> + +struct regulator_coupler; +struct regulator_dev; + +/** + * struct regulator_coupler - customized regulator's coupler + * + * Regulator's coupler allows to customize coupling algorithm. + * + * @list: couplers list entry + * @attach_regulator: Callback invoked on creation of a coupled regulator, + * couples are unresolved at this point. The callee should + * check that it could handle the regulator and return 0 on + * success, -errno on failure and 1 if given regulator is + * not suitable for this coupler (case of having multiple + * regulators in a system). Callback shall be implemented. + * @detach_regulator: Callback invoked on destruction of a coupled regulator. + * This callback is optional and could be NULL. + * @balance_voltage: Callback invoked when voltage of a coupled regulator is + * changing. Called with all of the coupled rdev's being held + * under "consumer lock". The callee should perform voltage + * balancing, changing voltage of the coupled regulators as + * needed. It's up to the coupler to verify the voltage + * before changing it in hardware, i.e. coupler should + * check consumer's min/max and etc. This callback is + * optional and could be NULL, in which case a generic + * voltage balancer will be used. + */ +struct regulator_coupler { + struct list_head list; + + int (*attach_regulator)(struct regulator_coupler *coupler, + struct regulator_dev *rdev); + int (*detach_regulator)(struct regulator_coupler *coupler, + struct regulator_dev *rdev); + int (*balance_voltage)(struct regulator_coupler *coupler, + struct regulator_dev *rdev, + suspend_state_t state); +}; + +#ifdef CONFIG_REGULATOR +int regulator_coupler_register(struct regulator_coupler *coupler); +const char *rdev_get_name(struct regulator_dev *rdev); +int regulator_check_consumers(struct regulator_dev *rdev, + int *min_uV, int *max_uV, + suspend_state_t state); +int regulator_check_voltage(struct regulator_dev *rdev, + int *min_uV, int *max_uV); +int regulator_get_voltage_rdev(struct regulator_dev *rdev); +int regulator_set_voltage_rdev(struct regulator_dev *rdev, + int min_uV, int max_uV, + suspend_state_t state); +#else +static inline int regulator_coupler_register(struct regulator_coupler *coupler) +{ + return 0; +} +static inline const char *rdev_get_name(struct regulator_dev *rdev) +{ + return NULL; +} +static inline int regulator_check_consumers(struct regulator_dev *rdev, + int *min_uV, int *max_uV, + suspend_state_t state) +{ + return -EINVAL; +} +static inline int regulator_check_voltage(struct regulator_dev *rdev, + int *min_uV, int *max_uV) +{ + return -EINVAL; +} +static inline int regulator_get_voltage_rdev(struct regulator_dev *rdev) +{ + return -EINVAL; +} +static inline int regulator_set_voltage_rdev(struct regulator_dev *rdev, + int min_uV, int max_uV, + suspend_state_t state) +{ + return -EINVAL; +} +#endif + +#endif diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index d45ab52c91c9..9a911bb5fb61 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -12,8 +12,6 @@ #ifndef __LINUX_REGULATOR_DRIVER_H_ #define __LINUX_REGULATOR_DRIVER_H_ -#define MAX_COUPLED 2 - #include <linux/device.h> #include <linux/notifier.h> #include <linux/regulator/consumer.h> @@ -283,6 +281,11 @@ enum regulator_type { * @vsel_range_mask: Mask for register bitfield used for range selector * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_ * @vsel_mask: Mask for register bitfield used for selector + * @vsel_step: Specify the resolution of selector stepping when setting + * voltage. If 0, then no stepping is done (requested selector is + * set directly), if >0 then the regulator API will ramp the + * voltage up/down gradually each time increasing/decreasing the + * selector by the specified step value. * @csel_reg: Register for current limit selector using regmap set_current_limit * @csel_mask: Mask for register bitfield used for current limit selector * @apply_reg: Register for initiate voltage change on the output when @@ -357,6 +360,7 @@ struct regulator_desc { unsigned int vsel_range_mask; unsigned int vsel_reg; unsigned int vsel_mask; + unsigned int vsel_step; unsigned int csel_reg; unsigned int csel_mask; unsigned int apply_reg; @@ -423,7 +427,8 @@ struct regulator_config { * incremented. */ struct coupling_desc { - struct regulator_dev *coupled_rdevs[MAX_COUPLED]; + struct regulator_dev **coupled_rdevs; + struct regulator_coupler *coupler; int n_resolved; int n_coupled; }; @@ -549,4 +554,5 @@ void regulator_unlock(struct regulator_dev *rdev); */ int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc, unsigned int selector); + #endif diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 5539efa76d26..a84cc8879c3e 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -153,7 +153,7 @@ struct regulation_constraints { int system_load; /* used for coupled regulators */ - int max_spread; + u32 *max_spread; /* used for changing voltage in steps */ int max_uV_step; diff --git a/include/linux/regulator/max8952.h b/include/linux/regulator/max8952.h index ebd99d2e62ad..8712c091abf0 100644 --- a/include/linux/regulator/max8952.h +++ b/include/linux/regulator/max8952.h @@ -105,9 +105,6 @@ enum { #define MAX8952_NUM_DVS_MODE 4 struct max8952_platform_data { - int gpio_vid0; - int gpio_vid1; - u32 default_mode; u32 dvs_mode[MAX8952_NUM_DVS_MODE]; /* MAX8952_DVS_MODEx_XXXXmV */ |