Commit 416e05e5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'regulator-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator

Pull regulator updates from Mark Brown:
 "This has been a fairly quiet release for the regulator API, a few new
  drivers and a small API update:

   - Support for specifying an initial load as part of requesting
     regulators through the bulk API

   - Support for Maxim MAX597x, Qualcomm PM8074, PM8909 and Realtek
     RT5120 devices"

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