regulator: Updates for v4.20
This has been a very busy release for the core, some fixes, one large new feature and a big bit of refactoring to update the GPIO API: - Support for coupled regulators from Dmitry Osipenko based on a prior attempt by Maciej Purski, allowing us to handle situations where the voltages on two regulators can't be too far apart from each other. - Conversion of the GPIO support in both drivers and the core to use GPIO descriptors rather than numbers, part of the overall project to remove GPIO numbers. - Support for standby mode suspend states from Andrei Stefanescu. - New drivers for Allwinner AXP209, Cirrus Logic Lochnagar and Microchip MPC16502. -----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAlwhKkcTHGJyb29uaWVA a2VybmVsLm9yZwAKCRAk1otyXVSH0DFfB/91/ECmybKTP+RvwUTZ0rrqFFs2C9Vl 76vH242exyJuzv44inWi9gOcXFDn7c9hf7Vl4Jd5UVP53Nzm5I8ZwExQsxax9BsN hltlX01UpRAmHNkMNrnJH6YAntD3EicYGSUDjohkWItIDqpMAjhWpx/yGXTEjBir gvkV51bF3qAYQe0g6MmK3KeVw96QPNjUhoPbsqbpaXaF6fmyOVzMiFrffJGmUAyM J5qRv3OhsZiZy2/zxNLkUI6y4XKDEaFJ3RhSKoUwItGyKQt2saXMoJGyEEWm2b6X coTm0ZQk+EU+b659lDHErTM4YUx7p7tQt3VM09NoMD8B261TdZ0y99Oh =8Rxt -----END PGP SIGNATURE----- Merge tag 'regulator-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator Pull regulator updates from Mark Brown: "This has been a very busy release for the core, some fixes, one large new feature and a big bit of refactoring to update the GPIO API: - Support for coupled regulators from Dmitry Osipenko based on a prior attempt by Maciej Purski, allowing us to handle situations where the voltages on two regulators can't be too far apart from each other. - Conversion of the GPIO support in both drivers and the core to use GPIO descriptors rather than numbers, part of the overall project to remove GPIO numbers. - Support for standby mode suspend states from Andrei Stefanescu. - New drivers for Allwinner AXP209, Cirrus Logic Lochnagar and Microchip MPC16502" * tag 'regulator-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (90 commits) regulator: tps65910: fix a missing check of return value regulator: mcp16502: Select REGMAP_I2C to fix build error regulator: convert to DEFINE_SHOW_ATTRIBUTE regulator: mcp16502: Fix missing n_voltages setting regulator: mcp16502: Use #ifdef CONFIG_PM_SLEEP around mcp16502_suspend/resume_noirq regulator: mcp16502: code cleanup regulator: act8945a-regulator: make symbol act8945a_pm static drivers/regulator: fix a missing check of return value regulator: act8945a-regulator: fix 'defined but not used' compiler warning regulator: axp20x: fix set_ramp_delay for AXP209/dcdc2 regulator: mcp16502: add support for suspend mfd: axp20x: use explicit bit defines mfd: axp20x: Clean up included headers regulator: dts: enable soft-start and ramp delay for the OLinuXino Lime2 dt-bindings: mfd: axp20x: Add software based soft_start for AXP209 LDO3 regulator: axp20x: add software based soft_start for AXP209 LDO3 dt-bindings: mfd: axp20x: add support for regulator-ramp-delay for AXP209 regulator: axp20x: add support for set_ramp_delay for AXP209 mfd: axp20x: name voltage ramping define properly regulator: mcp16502: add regulator driver for MCP16502 ...
This commit is contained in:
commit
79f20778fb
|
@ -32,6 +32,15 @@ Required properties:
|
||||||
- interrupt-controller: The PMIC has its own internal IRQs
|
- interrupt-controller: The PMIC has its own internal IRQs
|
||||||
- #interrupt-cells: Should be set to 1
|
- #interrupt-cells: Should be set to 1
|
||||||
|
|
||||||
|
Supported common regulator properties, see ../regulator/regulator.txt for
|
||||||
|
more information:
|
||||||
|
- regulator-ramp-delay: sets the ramp up delay in uV/us
|
||||||
|
AXP20x/DCDC2: 1600, 800
|
||||||
|
AXP20x/LDO3: 1600, 800
|
||||||
|
- regulator-soft-start: enable the output at the lowest possible voltage and
|
||||||
|
only then set the desired voltage
|
||||||
|
AXP20x/LDO3: software-based implementation
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz
|
- x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz
|
||||||
AXP152/20X: range: 750-1875, Default: 1.5 MHz
|
AXP152/20X: range: 750-1875, Default: 1.5 MHz
|
||||||
|
|
|
@ -15,11 +15,17 @@ Optional input supply properties:
|
||||||
- inl67-supply: The input supply for REG_LDO3 and REG_LDO4
|
- inl67-supply: The input supply for REG_LDO3 and REG_LDO4
|
||||||
|
|
||||||
Any standard regulator properties can be used to configure the single regulator.
|
Any standard regulator properties can be used to configure the single regulator.
|
||||||
|
regulator-initial-mode, regulator-allowed-modes and regulator-mode could be
|
||||||
|
specified using mode values from dt-bindings/regulator/active-semi,8945a-regulator.h
|
||||||
|
file.
|
||||||
|
|
||||||
The valid names for regulators are:
|
The valid names for regulators are:
|
||||||
REG_DCDC1, REG_DCDC2, REG_DCDC3, REG_LDO1, REG_LDO2, REG_LDO3, REG_LDO4.
|
REG_DCDC1, REG_DCDC2, REG_DCDC3, REG_LDO1, REG_LDO2, REG_LDO3, REG_LDO4.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
#include <dt-bindings/regulator/active-semi,8945a-regulator.h>
|
||||||
|
|
||||||
pmic@5b {
|
pmic@5b {
|
||||||
compatible = "active-semi,act8945a";
|
compatible = "active-semi,act8945a";
|
||||||
reg = <0x5b>;
|
reg = <0x5b>;
|
||||||
|
@ -32,6 +38,18 @@ Example:
|
||||||
regulator-min-microvolt = <1350000>;
|
regulator-min-microvolt = <1350000>;
|
||||||
regulator-max-microvolt = <1350000>;
|
regulator-max-microvolt = <1350000>;
|
||||||
regulator-always-on;
|
regulator-always-on;
|
||||||
|
|
||||||
|
regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_FIXED>,
|
||||||
|
<ACT8945A_REGULATOR_MODE_LOWPOWER>;
|
||||||
|
regulator-initial-mode = <ACT8945A_REGULATOR_MODE_FIXED>;
|
||||||
|
|
||||||
|
regulator-state-mem {
|
||||||
|
regulator-on-in-suspend;
|
||||||
|
regulator-suspend-min-microvolt=<1400000>;
|
||||||
|
regulator-suspend-max-microvolt=<1400000>;
|
||||||
|
regulator-changeable-in-suspend;
|
||||||
|
regulator-mode=<ACT8945A_REGULATOR_MODE_LOWPOWER>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
vdd_1v2_reg: REG_DCDC2 {
|
vdd_1v2_reg: REG_DCDC2 {
|
||||||
|
@ -39,6 +57,14 @@ Example:
|
||||||
regulator-min-microvolt = <1100000>;
|
regulator-min-microvolt = <1100000>;
|
||||||
regulator-max-microvolt = <1300000>;
|
regulator-max-microvolt = <1300000>;
|
||||||
regulator-always-on;
|
regulator-always-on;
|
||||||
|
|
||||||
|
regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_FIXED>,
|
||||||
|
<ACT8945A_REGULATOR_MODE_LOWPOWER>;
|
||||||
|
regulator-initial-mode = <ACT8945A_REGULATOR_MODE_FIXED>;
|
||||||
|
|
||||||
|
regulator-state-mem {
|
||||||
|
regulator-off-in-suspend;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
vdd_3v3_reg: REG_DCDC3 {
|
vdd_3v3_reg: REG_DCDC3 {
|
||||||
|
@ -53,6 +79,14 @@ Example:
|
||||||
regulator-min-microvolt = <2500000>;
|
regulator-min-microvolt = <2500000>;
|
||||||
regulator-max-microvolt = <2500000>;
|
regulator-max-microvolt = <2500000>;
|
||||||
regulator-always-on;
|
regulator-always-on;
|
||||||
|
|
||||||
|
regulator-allowed-modes = <ACT8945A_REGULATOR_MODE_NORMAL>,
|
||||||
|
<ACT8945A_REGULATOR_MODE_LOWPOWER>;
|
||||||
|
regulator-initial-mode = <ACT8945A_REGULATOR_MODE_NORMAL>;
|
||||||
|
|
||||||
|
regulator-state-mem {
|
||||||
|
regulator-off-in-suspend;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
vdd_3v3_lp_reg: REG_LDO2 {
|
vdd_3v3_lp_reg: REG_LDO2 {
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
Cirrus Logic Lochnagar Audio Development Board
|
||||||
|
|
||||||
|
Lochnagar is an evaluation and development board for Cirrus Logic
|
||||||
|
Smart CODEC and Amp devices. It allows the connection of most Cirrus
|
||||||
|
Logic devices on mini-cards, as well as allowing connection of
|
||||||
|
various application processor systems to provide a full evaluation
|
||||||
|
platform. Audio system topology, clocking and power can all be
|
||||||
|
controlled through the Lochnagar, allowing the device under test
|
||||||
|
to be used in a variety of possible use cases.
|
||||||
|
|
||||||
|
This binding document describes the binding for the regulator portion
|
||||||
|
of the driver.
|
||||||
|
|
||||||
|
Also see these documents for generic binding information:
|
||||||
|
[1] Regulator: ../regulator/regulator.txt
|
||||||
|
|
||||||
|
This binding must be part of the Lochnagar MFD binding:
|
||||||
|
[2] ../mfd/cirrus,lochnagar.txt
|
||||||
|
|
||||||
|
Optional sub-nodes:
|
||||||
|
|
||||||
|
- VDDCORE : Initialisation data for the VDDCORE regulator, which
|
||||||
|
supplies the CODECs digital core if it has no build regulator for that
|
||||||
|
purpose.
|
||||||
|
Required Properties:
|
||||||
|
- compatible : One of the following strings:
|
||||||
|
"cirrus,lochnagar2-vddcore"
|
||||||
|
- SYSVDD-supply: Primary power supply for the Lochnagar.
|
||||||
|
|
||||||
|
- MICVDD : Initialisation data for the MICVDD regulator, which
|
||||||
|
supplies the CODECs MICVDD.
|
||||||
|
Required Properties:
|
||||||
|
- compatible : One of the following strings:
|
||||||
|
"cirrus,lochnagar2-micvdd"
|
||||||
|
- SYSVDD-supply: Primary power supply for the Lochnagar.
|
||||||
|
|
||||||
|
- MIC1VDD, MIC2VDD : Initialisation data for the MICxVDD supplies.
|
||||||
|
Required Properties:
|
||||||
|
- compatible : One of the following strings:
|
||||||
|
"cirrus,lochnagar2-mic1vdd", "cirrus,lochnagar2-mic2vdd"
|
||||||
|
Optional Properties:
|
||||||
|
- cirrus,micbias-input : A property selecting which of the CODEC
|
||||||
|
minicard micbias outputs should be used, valid values are 1 - 4.
|
||||||
|
- MICBIAS1-supply, MICBIAS2-supply: Regulator supplies for the
|
||||||
|
MICxVDD outputs, supplying the digital microphones, normally
|
||||||
|
supplied from the attached CODEC.
|
||||||
|
|
||||||
|
- VDD1V8 : Recommended fixed regulator for the VDD1V8 regulator, which supplies the
|
||||||
|
CODECs analog and 1.8V digital supplies.
|
||||||
|
Required Properties:
|
||||||
|
- compatible : Should be set to "regulator-fixed"
|
||||||
|
- regulator-min-microvolt : Should be set to 1.8V
|
||||||
|
- regulator-max-microvolt : Should be set to 1.8V
|
||||||
|
- regulator-boot-on
|
||||||
|
- regulator-always-on
|
||||||
|
- vin-supply : Should be set to same supply as SYSVDD
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
lochnagar {
|
||||||
|
lochnagar-micvdd: MICVDD {
|
||||||
|
compatible = "cirrus,lochnagar2-micvdd";
|
||||||
|
|
||||||
|
SYSVDD-supply = <&wallvdd>;
|
||||||
|
|
||||||
|
regulator-min-microvolt = <3300000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
lochnagar-vdd1v8: VDD1V8 {
|
||||||
|
compatible = "regulator-fixed";
|
||||||
|
|
||||||
|
regulator-name = "VDD1V8";
|
||||||
|
regulator-min-microvolt = <1800000>;
|
||||||
|
regulator-max-microvolt = <1800000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
regulator-always-on;
|
||||||
|
|
||||||
|
vin-supply = <&wallvdd>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
MCP16502 PMIC
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: "microchip,mcp16502"
|
||||||
|
- reg: I2C slave address
|
||||||
|
- lpm-gpios: GPIO for LPM pin. Note that this GPIO *must* remain high during
|
||||||
|
suspend-to-ram, keeping the PMIC into HIBERNATE mode.
|
||||||
|
- regulators: A node that houses a sub-node for each regulator within
|
||||||
|
the device. Each sub-node is identified using the node's
|
||||||
|
name. The content of each sub-node is defined by the
|
||||||
|
standard binding for regulators; see regulator.txt.
|
||||||
|
|
||||||
|
Regualtors of MCP16502 PMIC:
|
||||||
|
1) VDD_IO - Buck (1.2 - 3.7 V)
|
||||||
|
2) VDD_DDR - Buck (0.6 - 1.85 V)
|
||||||
|
3) VDD_CORE - Buck (0.6 - 1.85 V)
|
||||||
|
4) VDD_OTHER - BUCK (0.6 - 1.85 V)
|
||||||
|
5) LDO1 - LDO (1.2 - 3.7 V)
|
||||||
|
6) LDO2 - LDO (1.2 - 3.7 V)
|
||||||
|
|
||||||
|
Regulator modes:
|
||||||
|
2 - FPWM: higher precision, higher consumption
|
||||||
|
4 - AutoPFM: lower precision, lower consumption
|
||||||
|
|
||||||
|
Each regulator is defined using the standard binding for regulators.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
mcp16502@5b {
|
||||||
|
compatible = "microchip,mcp16502";
|
||||||
|
reg = <0x5b>;
|
||||||
|
status = "okay";
|
||||||
|
lpm-gpios = <&pioBU 7 GPIO_ACTIVE_HIGH>;
|
||||||
|
|
||||||
|
regulators {
|
||||||
|
VDD_IO {
|
||||||
|
regulator-name = "VDD_IO";
|
||||||
|
regulator-min-microvolt = <1200000>;
|
||||||
|
regulator-max-microvolt = <3700000>;
|
||||||
|
regulator-initial-mode = <2>;
|
||||||
|
regulator-allowed-modes = <2>, <4>;
|
||||||
|
regulator-always-on;
|
||||||
|
|
||||||
|
regulator-state-standby {
|
||||||
|
regulator-on-in-suspend;
|
||||||
|
regulator-mode = <4>;
|
||||||
|
};
|
||||||
|
|
||||||
|
regulator-state-mem {
|
||||||
|
regulator-off-in-suspend;
|
||||||
|
regulator-mode = <4>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
VDD_DDR {
|
||||||
|
regulator-name = "VDD_DDR";
|
||||||
|
regulator-min-microvolt = <600000>;
|
||||||
|
regulator-max-microvolt = <1850000>;
|
||||||
|
regulator-initial-mode = <2>;
|
||||||
|
regulator-allowed-modes = <2>, <4>;
|
||||||
|
regulator-always-on;
|
||||||
|
|
||||||
|
regulator-state-standby {
|
||||||
|
regulator-on-in-suspend;
|
||||||
|
regulator-mode = <4>;
|
||||||
|
};
|
||||||
|
|
||||||
|
regulator-state-mem {
|
||||||
|
regulator-on-in-suspend;
|
||||||
|
regulator-mode = <4>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
VDD_CORE {
|
||||||
|
regulator-name = "VDD_CORE";
|
||||||
|
regulator-min-microvolt = <600000>;
|
||||||
|
regulator-max-microvolt = <1850000>;
|
||||||
|
regulator-initial-mode = <2>;
|
||||||
|
regulator-allowed-modes = <2>, <4>;
|
||||||
|
regulator-always-on;
|
||||||
|
|
||||||
|
regulator-state-standby {
|
||||||
|
regulator-on-in-suspend;
|
||||||
|
regulator-mode = <4>;
|
||||||
|
};
|
||||||
|
|
||||||
|
regulator-state-mem {
|
||||||
|
regulator-off-in-suspend;
|
||||||
|
regulator-mode = <4>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
VDD_OTHER {
|
||||||
|
regulator-name = "VDD_OTHER";
|
||||||
|
regulator-min-microvolt = <600000>;
|
||||||
|
regulator-max-microvolt = <1850000>;
|
||||||
|
regulator-initial-mode = <2>;
|
||||||
|
regulator-allowed-modes = <2>, <4>;
|
||||||
|
regulator-always-on;
|
||||||
|
|
||||||
|
regulator-state-standby {
|
||||||
|
regulator-on-in-suspend;
|
||||||
|
regulator-mode = <4>;
|
||||||
|
};
|
||||||
|
|
||||||
|
regulator-state-mem {
|
||||||
|
regulator-off-in-suspend;
|
||||||
|
regulator-mode = <4>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
LDO1 {
|
||||||
|
regulator-name = "LDO1";
|
||||||
|
regulator-min-microvolt = <1200000>;
|
||||||
|
regulator-max-microvolt = <3700000>;
|
||||||
|
regulator-always-on;
|
||||||
|
|
||||||
|
regulator-state-standby {
|
||||||
|
regulator-on-in-suspend;
|
||||||
|
};
|
||||||
|
|
||||||
|
regulator-state-mem {
|
||||||
|
regulator-off-in-suspend;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
LDO2 {
|
||||||
|
regulator-name = "LDO2";
|
||||||
|
regulator-min-microvolt = <1200000>;
|
||||||
|
regulator-max-microvolt = <3700000>;
|
||||||
|
regulator-always-on;
|
||||||
|
|
||||||
|
regulator-state-standby {
|
||||||
|
regulator-on-in-suspend;
|
||||||
|
};
|
||||||
|
|
||||||
|
regulator-state-mem {
|
||||||
|
regulator-off-in-suspend;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
|
@ -33,13 +33,16 @@ Optional properties:
|
||||||
decreases of any level. This is useful for regulators with exponential
|
decreases of any level. This is useful for regulators with exponential
|
||||||
voltage changes.
|
voltage changes.
|
||||||
- regulator-soft-start: Enable soft start so that voltage ramps slowly
|
- 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
|
- 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,
|
: suspend to memory, the device goes to sleep, but all data stored in memory,
|
||||||
only some external interrupt can wake the device.
|
only some external interrupt can wake the device.
|
||||||
- regulator-state-disk sub-root node for Suspend-to-DISK mode
|
- regulator-state-disk sub-root node for Suspend-to-DISK mode
|
||||||
: suspend to disk, this state operates similarly to Suspend-to-RAM,
|
: suspend to disk, this state operates similarly to Suspend-to-RAM,
|
||||||
but includes a final step of writing memory contents to disk.
|
but includes a final step of writing memory contents to disk.
|
||||||
- regulator-state-[mem/disk] node has following common properties:
|
- regulator-state-[mem/disk/standby] node has following common properties:
|
||||||
- regulator-on-in-suspend: regulator should be on in suspend state.
|
- regulator-on-in-suspend: regulator should be on in suspend state.
|
||||||
- regulator-off-in-suspend: regulator should be off in suspend state.
|
- regulator-off-in-suspend: regulator should be off in suspend state.
|
||||||
- regulator-suspend-min-microvolt: minimum voltage may be set in
|
- regulator-suspend-min-microvolt: minimum voltage may be set in
|
||||||
|
@ -76,8 +79,11 @@ Optional properties:
|
||||||
- regulator-coupled-with: Regulators with which the regulator
|
- regulator-coupled-with: Regulators with which the regulator
|
||||||
is coupled. The linkage is 2-way - all coupled regulators should be linked
|
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.
|
with each other. A regulator should not be coupled with its supplier.
|
||||||
- regulator-coupled-max-spread: Max spread between voltages of coupled regulators
|
- regulator-coupled-max-spread: Array of maximum spread between voltages of
|
||||||
in microvolts.
|
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:
|
Deprecated properties:
|
||||||
- regulator-compatible: If a regulator chip contains multiple
|
- regulator-compatible: If a regulator chip contains multiple
|
||||||
|
|
|
@ -254,6 +254,7 @@ GPIO
|
||||||
devm_gpiod_get_index_optional()
|
devm_gpiod_get_index_optional()
|
||||||
devm_gpiod_get_optional()
|
devm_gpiod_get_optional()
|
||||||
devm_gpiod_put()
|
devm_gpiod_put()
|
||||||
|
devm_gpiod_unhinge()
|
||||||
devm_gpiochip_add_data()
|
devm_gpiochip_add_data()
|
||||||
devm_gpiochip_remove()
|
devm_gpiochip_remove()
|
||||||
devm_gpio_request()
|
devm_gpio_request()
|
||||||
|
|
|
@ -9891,6 +9891,13 @@ M: Ludovic Desroches <ludovic.desroches@microchip.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/mmc/host/atmel-mci.c
|
F: drivers/mmc/host/atmel-mci.c
|
||||||
|
|
||||||
|
MICROCHIP MCP16502 PMIC DRIVER
|
||||||
|
M: Andrei Stefanescu <andrei.stefanescu@microchip.com>
|
||||||
|
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||||
|
S: Maintained
|
||||||
|
F: Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
|
||||||
|
F: drivers/regulator/mcp16502.c
|
||||||
|
|
||||||
MICROCHIP MCP3911 ADC DRIVER
|
MICROCHIP MCP3911 ADC DRIVER
|
||||||
M: Marcus Folkesson <marcus.folkesson@gmail.com>
|
M: Marcus Folkesson <marcus.folkesson@gmail.com>
|
||||||
M: Kent Gustavsson <kent@minoris.se>
|
M: Kent Gustavsson <kent@minoris.se>
|
||||||
|
|
|
@ -245,6 +245,8 @@ ®_ldo3 {
|
||||||
regulator-min-microvolt = <2800000>;
|
regulator-min-microvolt = <2800000>;
|
||||||
regulator-max-microvolt = <2800000>;
|
regulator-max-microvolt = <2800000>;
|
||||||
regulator-name = "vddio-csi0";
|
regulator-name = "vddio-csi0";
|
||||||
|
regulator-soft-start;
|
||||||
|
regulator-ramp-delay = <1600>;
|
||||||
};
|
};
|
||||||
|
|
||||||
®_ldo4 {
|
®_ldo4 {
|
||||||
|
|
|
@ -194,8 +194,8 @@ static struct wm8994_pdata wm8994_pdata = {
|
||||||
0x3, /* IRQ out, active high, CMOS */
|
0x3, /* IRQ out, active high, CMOS */
|
||||||
},
|
},
|
||||||
.ldo = {
|
.ldo = {
|
||||||
{ .enable = S3C64XX_GPN(6), .init_data = &wm8994_ldo1, },
|
{ .init_data = &wm8994_ldo1, },
|
||||||
{ .enable = S3C64XX_GPN(4), .init_data = &wm8994_ldo2, },
|
{ .init_data = &wm8994_ldo2, },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -203,6 +203,18 @@ static const struct i2c_board_info wm1277_devs[] = {
|
||||||
{ I2C_BOARD_INFO("wm8958", 0x1a), /* WM8958 is the superset */
|
{ I2C_BOARD_INFO("wm8958", 0x1a), /* WM8958 is the superset */
|
||||||
.platform_data = &wm8994_pdata,
|
.platform_data = &wm8994_pdata,
|
||||||
.irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
|
.irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
|
||||||
|
.dev_name = "wm8958",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct gpiod_lookup_table wm8994_gpiod_table = {
|
||||||
|
.dev_id = "i2c-wm8958", /* I2C device name */
|
||||||
|
.table = {
|
||||||
|
GPIO_LOOKUP("GPION", 6,
|
||||||
|
"wlf,ldo1ena", GPIO_ACTIVE_HIGH),
|
||||||
|
GPIO_LOOKUP("GPION", 4,
|
||||||
|
"wlf,ldo2ena", GPIO_ACTIVE_HIGH),
|
||||||
|
{ },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -381,6 +393,7 @@ static int wlf_gf_module_probe(struct i2c_client *i2c,
|
||||||
|
|
||||||
gpiod_add_lookup_table(&wm5102_reva_gpiod_table);
|
gpiod_add_lookup_table(&wm5102_reva_gpiod_table);
|
||||||
gpiod_add_lookup_table(&wm5102_gpiod_table);
|
gpiod_add_lookup_table(&wm5102_gpiod_table);
|
||||||
|
gpiod_add_lookup_table(&wm8994_gpiod_table);
|
||||||
|
|
||||||
if (i < ARRAY_SIZE(gf_mods)) {
|
if (i < ARRAY_SIZE(gf_mods)) {
|
||||||
dev_info(&i2c->dev, "%s revision %d\n",
|
dev_info(&i2c->dev, "%s revision %d\n",
|
||||||
|
|
|
@ -98,15 +98,28 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
|
||||||
struct gpio_desc **dr;
|
struct gpio_desc **dr;
|
||||||
struct gpio_desc *desc;
|
struct gpio_desc *desc;
|
||||||
|
|
||||||
|
desc = gpiod_get_index(dev, con_id, idx, flags);
|
||||||
|
if (IS_ERR(desc))
|
||||||
|
return desc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For non-exclusive GPIO descriptors, check if this descriptor is
|
||||||
|
* already under resource management by this device.
|
||||||
|
*/
|
||||||
|
if (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
|
||||||
|
struct devres *dres;
|
||||||
|
|
||||||
|
dres = devres_find(dev, devm_gpiod_release,
|
||||||
|
devm_gpiod_match, &desc);
|
||||||
|
if (dres)
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
|
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!dr)
|
if (!dr) {
|
||||||
|
gpiod_put(desc);
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
desc = gpiod_get_index(dev, con_id, idx, flags);
|
|
||||||
if (IS_ERR(desc)) {
|
|
||||||
devres_free(dr);
|
|
||||||
return desc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*dr = desc;
|
*dr = desc;
|
||||||
|
@ -140,15 +153,28 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
||||||
struct gpio_desc **dr;
|
struct gpio_desc **dr;
|
||||||
struct gpio_desc *desc;
|
struct gpio_desc *desc;
|
||||||
|
|
||||||
|
desc = gpiod_get_from_of_node(node, propname, index, dflags, label);
|
||||||
|
if (IS_ERR(desc))
|
||||||
|
return desc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For non-exclusive GPIO descriptors, check if this descriptor is
|
||||||
|
* already under resource management by this device.
|
||||||
|
*/
|
||||||
|
if (dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
|
||||||
|
struct devres *dres;
|
||||||
|
|
||||||
|
dres = devres_find(dev, devm_gpiod_release,
|
||||||
|
devm_gpiod_match, &desc);
|
||||||
|
if (dres)
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
|
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!dr)
|
if (!dr) {
|
||||||
|
gpiod_put(desc);
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
desc = gpiod_get_from_of_node(node, propname, index, dflags, label);
|
|
||||||
if (IS_ERR(desc)) {
|
|
||||||
devres_free(dr);
|
|
||||||
return desc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*dr = desc;
|
*dr = desc;
|
||||||
|
@ -320,6 +346,36 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(devm_gpiod_put);
|
EXPORT_SYMBOL(devm_gpiod_put);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* devm_gpiod_unhinge - Remove resource management from a gpio descriptor
|
||||||
|
* @dev: GPIO consumer
|
||||||
|
* @desc: GPIO descriptor to remove resource management from
|
||||||
|
*
|
||||||
|
* Remove resource management from a GPIO descriptor. This is needed when
|
||||||
|
* you want to hand over lifecycle management of a descriptor to another
|
||||||
|
* mechanism.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(desc))
|
||||||
|
return;
|
||||||
|
ret = devres_destroy(dev, devm_gpiod_release,
|
||||||
|
devm_gpiod_match, &desc);
|
||||||
|
/*
|
||||||
|
* If the GPIO descriptor is requested as nonexclusive, we
|
||||||
|
* may call this function several times on the same descriptor
|
||||||
|
* so it is OK if devres_destroy() returns -ENOENT.
|
||||||
|
*/
|
||||||
|
if (ret == -ENOENT)
|
||||||
|
return;
|
||||||
|
/* Anything else we should warn about */
|
||||||
|
WARN_ON(ret);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(devm_gpiod_unhinge);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* devm_gpiod_put_array - Resource-managed gpiod_put_array()
|
* devm_gpiod_put_array - Resource-managed gpiod_put_array()
|
||||||
* @dev: GPIO consumer
|
* @dev: GPIO consumer
|
||||||
|
|
|
@ -4205,6 +4205,8 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
||||||
transitory = flags & OF_GPIO_TRANSITORY;
|
transitory = flags & OF_GPIO_TRANSITORY;
|
||||||
|
|
||||||
ret = gpiod_request(desc, label);
|
ret = gpiod_request(desc, label);
|
||||||
|
if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
|
||||||
|
return desc;
|
||||||
if (ret)
|
if (ret)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
|
|
@ -201,12 +201,6 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
||||||
struct gpio_array *array_info,
|
struct gpio_array *array_info,
|
||||||
unsigned long *value_bitmap);
|
unsigned long *value_bitmap);
|
||||||
|
|
||||||
/* This is just passed between gpiolib and devres */
|
|
||||||
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
|
||||||
const char *propname, int index,
|
|
||||||
enum gpiod_flags dflags,
|
|
||||||
const char *label);
|
|
||||||
|
|
||||||
extern struct spinlock gpio_lock;
|
extern struct spinlock gpio_lock;
|
||||||
extern struct list_head gpio_devices;
|
extern struct list_head gpio_devices;
|
||||||
|
|
||||||
|
|
|
@ -16,20 +16,21 @@
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/err.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/err.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/mfd/axp20x.h>
|
||||||
|
#include <linux/mfd/core.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/mfd/axp20x.h>
|
|
||||||
#include <linux/mfd/core.h>
|
|
||||||
#include <linux/of_device.h>
|
|
||||||
#include <linux/acpi.h>
|
|
||||||
|
|
||||||
#define AXP20X_OFF 0x80
|
#define AXP20X_OFF BIT(7)
|
||||||
|
|
||||||
#define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE 0
|
#define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE 0
|
||||||
#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4)
|
#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4)
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <linux/mfd/core.h>
|
#include <linux/mfd/core.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_gpio.h>
|
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
@ -306,14 +305,6 @@ static int wm8994_set_pdata_from_of(struct wm8994 *wm8994)
|
||||||
|
|
||||||
pdata->csnaddr_pd = of_property_read_bool(np, "wlf,csnaddr-pd");
|
pdata->csnaddr_pd = of_property_read_bool(np, "wlf,csnaddr-pd");
|
||||||
|
|
||||||
pdata->ldo[0].enable = of_get_named_gpio(np, "wlf,ldo1ena", 0);
|
|
||||||
if (pdata->ldo[0].enable < 0)
|
|
||||||
pdata->ldo[0].enable = 0;
|
|
||||||
|
|
||||||
pdata->ldo[1].enable = of_get_named_gpio(np, "wlf,ldo2ena", 0);
|
|
||||||
if (pdata->ldo[1].enable < 0)
|
|
||||||
pdata->ldo[1].enable = 0;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -328,7 +328,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
for_each_child_of_node(nproot, np) {
|
for_each_child_of_node(nproot, np) {
|
||||||
if (!of_node_cmp(np->name, info->desc.name)) {
|
if (of_node_name_eq(np, info->desc.name)) {
|
||||||
config->init_data =
|
config->init_data =
|
||||||
of_get_regulator_init_data(&pdev->dev, np,
|
of_get_regulator_init_data(&pdev->dev, np,
|
||||||
&info->desc);
|
&info->desc);
|
||||||
|
|
|
@ -567,6 +567,16 @@ config REGULATOR_MC13892
|
||||||
Say y here to support the regulators found on the Freescale MC13892
|
Say y here to support the regulators found on the Freescale MC13892
|
||||||
PMIC.
|
PMIC.
|
||||||
|
|
||||||
|
config REGULATOR_MCP16502
|
||||||
|
tristate "Microchip MCP16502 PMIC"
|
||||||
|
depends on I2C && OF
|
||||||
|
select REGMAP_I2C
|
||||||
|
help
|
||||||
|
Say y here to support the MCP16502 PMIC. This driver supports
|
||||||
|
basic operations (get/set voltage, get/set operating mode)
|
||||||
|
through the regulator interface. In addition it enables
|
||||||
|
suspend-to-ram/standby transition.
|
||||||
|
|
||||||
config REGULATOR_MT6311
|
config REGULATOR_MT6311
|
||||||
tristate "MediaTek MT6311 PMIC"
|
tristate "MediaTek MT6311 PMIC"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
|
|
|
@ -74,6 +74,7 @@ obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
|
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
|
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
|
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
|
||||||
|
obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o
|
||||||
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
|
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
|
obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
|
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
|
||||||
|
|
|
@ -15,31 +15,41 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/driver.h>
|
#include <linux/regulator/driver.h>
|
||||||
#include <linux/regulator/machine.h>
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <dt-bindings/regulator/active-semi,8945a-regulator.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ACT8945A Global Register Map.
|
* ACT8945A Global Register Map.
|
||||||
*/
|
*/
|
||||||
#define ACT8945A_SYS_MODE 0x00
|
#define ACT8945A_SYS_MODE 0x00
|
||||||
#define ACT8945A_SYS_CTRL 0x01
|
#define ACT8945A_SYS_CTRL 0x01
|
||||||
|
#define ACT8945A_SYS_UNLK_REGS 0x0b
|
||||||
#define ACT8945A_DCDC1_VSET1 0x20
|
#define ACT8945A_DCDC1_VSET1 0x20
|
||||||
#define ACT8945A_DCDC1_VSET2 0x21
|
#define ACT8945A_DCDC1_VSET2 0x21
|
||||||
#define ACT8945A_DCDC1_CTRL 0x22
|
#define ACT8945A_DCDC1_CTRL 0x22
|
||||||
|
#define ACT8945A_DCDC1_SUS 0x24
|
||||||
#define ACT8945A_DCDC2_VSET1 0x30
|
#define ACT8945A_DCDC2_VSET1 0x30
|
||||||
#define ACT8945A_DCDC2_VSET2 0x31
|
#define ACT8945A_DCDC2_VSET2 0x31
|
||||||
#define ACT8945A_DCDC2_CTRL 0x32
|
#define ACT8945A_DCDC2_CTRL 0x32
|
||||||
|
#define ACT8945A_DCDC2_SUS 0x34
|
||||||
#define ACT8945A_DCDC3_VSET1 0x40
|
#define ACT8945A_DCDC3_VSET1 0x40
|
||||||
#define ACT8945A_DCDC3_VSET2 0x41
|
#define ACT8945A_DCDC3_VSET2 0x41
|
||||||
#define ACT8945A_DCDC3_CTRL 0x42
|
#define ACT8945A_DCDC3_CTRL 0x42
|
||||||
|
#define ACT8945A_DCDC3_SUS 0x44
|
||||||
#define ACT8945A_LDO1_VSET 0x50
|
#define ACT8945A_LDO1_VSET 0x50
|
||||||
#define ACT8945A_LDO1_CTRL 0x51
|
#define ACT8945A_LDO1_CTRL 0x51
|
||||||
|
#define ACT8945A_LDO1_SUS 0x52
|
||||||
#define ACT8945A_LDO2_VSET 0x54
|
#define ACT8945A_LDO2_VSET 0x54
|
||||||
#define ACT8945A_LDO2_CTRL 0x55
|
#define ACT8945A_LDO2_CTRL 0x55
|
||||||
|
#define ACT8945A_LDO2_SUS 0x56
|
||||||
#define ACT8945A_LDO3_VSET 0x60
|
#define ACT8945A_LDO3_VSET 0x60
|
||||||
#define ACT8945A_LDO3_CTRL 0x61
|
#define ACT8945A_LDO3_CTRL 0x61
|
||||||
|
#define ACT8945A_LDO3_SUS 0x62
|
||||||
#define ACT8945A_LDO4_VSET 0x64
|
#define ACT8945A_LDO4_VSET 0x64
|
||||||
#define ACT8945A_LDO4_CTRL 0x65
|
#define ACT8945A_LDO4_CTRL 0x65
|
||||||
|
#define ACT8945A_LDO4_SUS 0x66
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Field Definitions.
|
* Field Definitions.
|
||||||
|
@ -60,7 +70,12 @@ enum {
|
||||||
ACT8945A_ID_LDO2,
|
ACT8945A_ID_LDO2,
|
||||||
ACT8945A_ID_LDO3,
|
ACT8945A_ID_LDO3,
|
||||||
ACT8945A_ID_LDO4,
|
ACT8945A_ID_LDO4,
|
||||||
ACT8945A_REG_NUM,
|
ACT8945A_ID_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act8945a_pmic {
|
||||||
|
struct regmap *regmap;
|
||||||
|
u32 op_mode[ACT8945A_ID_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct regulator_linear_range act8945a_voltage_ranges[] = {
|
static const struct regulator_linear_range act8945a_voltage_ranges[] = {
|
||||||
|
@ -69,6 +84,143 @@ static const struct regulator_linear_range act8945a_voltage_ranges[] = {
|
||||||
REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
|
REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int act8945a_set_suspend_state(struct regulator_dev *rdev, bool enable)
|
||||||
|
{
|
||||||
|
struct regmap *regmap = rdev->regmap;
|
||||||
|
int id = rdev->desc->id, reg, val;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case ACT8945A_ID_DCDC1:
|
||||||
|
reg = ACT8945A_DCDC1_SUS;
|
||||||
|
val = 0xa8;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_DCDC2:
|
||||||
|
reg = ACT8945A_DCDC2_SUS;
|
||||||
|
val = 0xa8;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_DCDC3:
|
||||||
|
reg = ACT8945A_DCDC3_SUS;
|
||||||
|
val = 0xa8;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_LDO1:
|
||||||
|
reg = ACT8945A_LDO1_SUS;
|
||||||
|
val = 0xe8;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_LDO2:
|
||||||
|
reg = ACT8945A_LDO2_SUS;
|
||||||
|
val = 0xe8;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_LDO3:
|
||||||
|
reg = ACT8945A_LDO3_SUS;
|
||||||
|
val = 0xe8;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_LDO4:
|
||||||
|
reg = ACT8945A_LDO4_SUS;
|
||||||
|
val = 0xe8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
val |= BIT(4);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ask the PMIC to enable/disable this output when entering hibernate
|
||||||
|
* mode.
|
||||||
|
*/
|
||||||
|
return regmap_write(regmap, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int act8945a_set_suspend_enable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
return act8945a_set_suspend_state(rdev, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int act8945a_set_suspend_disable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
return act8945a_set_suspend_state(rdev, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int act8945a_of_map_mode(unsigned int mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case ACT8945A_REGULATOR_MODE_FIXED:
|
||||||
|
case ACT8945A_REGULATOR_MODE_NORMAL:
|
||||||
|
return REGULATOR_MODE_NORMAL;
|
||||||
|
case ACT8945A_REGULATOR_MODE_LOWPOWER:
|
||||||
|
return REGULATOR_MODE_STANDBY;
|
||||||
|
default:
|
||||||
|
return REGULATOR_MODE_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode)
|
||||||
|
{
|
||||||
|
struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev);
|
||||||
|
struct regmap *regmap = rdev->regmap;
|
||||||
|
int id = rdev->desc->id;
|
||||||
|
int reg, ret, val = 0;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case ACT8945A_ID_DCDC1:
|
||||||
|
reg = ACT8945A_DCDC1_CTRL;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_DCDC2:
|
||||||
|
reg = ACT8945A_DCDC2_CTRL;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_DCDC3:
|
||||||
|
reg = ACT8945A_DCDC3_CTRL;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_LDO1:
|
||||||
|
reg = ACT8945A_LDO1_SUS;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_LDO2:
|
||||||
|
reg = ACT8945A_LDO2_SUS;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_LDO3:
|
||||||
|
reg = ACT8945A_LDO3_SUS;
|
||||||
|
break;
|
||||||
|
case ACT8945A_ID_LDO4:
|
||||||
|
reg = ACT8945A_LDO4_SUS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case REGULATOR_MODE_STANDBY:
|
||||||
|
if (rdev->desc->id > ACT8945A_ID_DCDC3)
|
||||||
|
val = BIT(5);
|
||||||
|
break;
|
||||||
|
case REGULATOR_MODE_NORMAL:
|
||||||
|
if (rdev->desc->id <= ACT8945A_ID_DCDC3)
|
||||||
|
val = BIT(5);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_update_bits(regmap, reg, BIT(5), val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
act8945a->op_mode[id] = mode;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int act8945a_get_mode(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev);
|
||||||
|
int id = rdev->desc->id;
|
||||||
|
|
||||||
|
if (id < ACT8945A_ID_DCDC1 || id >= ACT8945A_ID_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return act8945a->op_mode[id];
|
||||||
|
}
|
||||||
|
|
||||||
static const struct regulator_ops act8945a_ops = {
|
static const struct regulator_ops act8945a_ops = {
|
||||||
.list_voltage = regulator_list_voltage_linear_range,
|
.list_voltage = regulator_list_voltage_linear_range,
|
||||||
.map_voltage = regulator_map_voltage_linear_range,
|
.map_voltage = regulator_map_voltage_linear_range,
|
||||||
|
@ -76,7 +228,11 @@ static const struct regulator_ops act8945a_ops = {
|
||||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
.enable = regulator_enable_regmap,
|
.enable = regulator_enable_regmap,
|
||||||
.disable = regulator_disable_regmap,
|
.disable = regulator_disable_regmap,
|
||||||
|
.set_mode = act8945a_set_mode,
|
||||||
|
.get_mode = act8945a_get_mode,
|
||||||
.is_enabled = regulator_is_enabled_regmap,
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.set_suspend_enable = act8945a_set_suspend_enable,
|
||||||
|
.set_suspend_disable = act8945a_set_suspend_disable,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ACT89xx_REG(_name, _family, _id, _vsel_reg, _supply) \
|
#define ACT89xx_REG(_name, _family, _id, _vsel_reg, _supply) \
|
||||||
|
@ -84,6 +240,7 @@ static const struct regulator_ops act8945a_ops = {
|
||||||
.name = _name, \
|
.name = _name, \
|
||||||
.supply_name = _supply, \
|
.supply_name = _supply, \
|
||||||
.of_match = of_match_ptr("REG_"#_id), \
|
.of_match = of_match_ptr("REG_"#_id), \
|
||||||
|
.of_map_mode = act8945a_of_map_mode, \
|
||||||
.regulators_node = of_match_ptr("regulators"), \
|
.regulators_node = of_match_ptr("regulators"), \
|
||||||
.id = _family##_ID_##_id, \
|
.id = _family##_ID_##_id, \
|
||||||
.type = REGULATOR_VOLTAGE, \
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
@ -122,10 +279,22 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct regulator_config config = { };
|
struct regulator_config config = { };
|
||||||
const struct regulator_desc *regulators;
|
const struct regulator_desc *regulators;
|
||||||
|
struct act8945a_pmic *act8945a;
|
||||||
struct regulator_dev *rdev;
|
struct regulator_dev *rdev;
|
||||||
int i, num_regulators;
|
int i, num_regulators;
|
||||||
bool voltage_select;
|
bool voltage_select;
|
||||||
|
|
||||||
|
act8945a = devm_kzalloc(&pdev->dev, sizeof(*act8945a), GFP_KERNEL);
|
||||||
|
if (!act8945a)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
act8945a->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||||
|
if (!act8945a->regmap) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"could not retrieve regmap from parent device\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
voltage_select = of_property_read_bool(pdev->dev.parent->of_node,
|
voltage_select = of_property_read_bool(pdev->dev.parent->of_node,
|
||||||
"active-semi,vsel-high");
|
"active-semi,vsel-high");
|
||||||
|
|
||||||
|
@ -139,8 +308,10 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
config.dev = &pdev->dev;
|
config.dev = &pdev->dev;
|
||||||
config.dev->of_node = pdev->dev.parent->of_node;
|
config.dev->of_node = pdev->dev.parent->of_node;
|
||||||
|
config.driver_data = act8945a;
|
||||||
for (i = 0; i < num_regulators; i++) {
|
for (i = 0; i < num_regulators; i++) {
|
||||||
rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config);
|
rdev = devm_regulator_register(&pdev->dev, ®ulators[i],
|
||||||
|
&config);
|
||||||
if (IS_ERR(rdev)) {
|
if (IS_ERR(rdev)) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"failed to register %s regulator\n",
|
"failed to register %s regulator\n",
|
||||||
|
@ -149,14 +320,42 @@ static int act8945a_pmic_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
platform_set_drvdata(pdev, act8945a);
|
||||||
|
|
||||||
|
/* Unlock expert registers. */
|
||||||
|
return regmap_write(act8945a->regmap, ACT8945A_SYS_UNLK_REGS, 0xef);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused act8945a_suspend(struct device *pdev)
|
||||||
|
{
|
||||||
|
struct act8945a_pmic *act8945a = dev_get_drvdata(pdev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ask the PMIC to enter the suspend mode on the next PWRHLD
|
||||||
|
* transition.
|
||||||
|
*/
|
||||||
|
return regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x42);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(act8945a_pm, act8945a_suspend, NULL);
|
||||||
|
|
||||||
|
static void act8945a_pmic_shutdown(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct act8945a_pmic *act8945a = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ask the PMIC to shutdown everything on the next PWRHLD transition.
|
||||||
|
*/
|
||||||
|
regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver act8945a_pmic_driver = {
|
static struct platform_driver act8945a_pmic_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "act8945a-regulator",
|
.name = "act8945a-regulator",
|
||||||
|
.pm = &act8945a_pm,
|
||||||
},
|
},
|
||||||
.probe = act8945a_pmic_probe,
|
.probe = act8945a_pmic_probe,
|
||||||
|
.shutdown = act8945a_pmic_shutdown,
|
||||||
};
|
};
|
||||||
module_platform_driver(act8945a_pmic_driver);
|
module_platform_driver(act8945a_pmic_driver);
|
||||||
|
|
||||||
|
|
|
@ -283,9 +283,6 @@ static int arizona_ldo1_common_init(struct platform_device *pdev,
|
||||||
of_node_put(config.of_node);
|
of_node_put(config.of_node);
|
||||||
|
|
||||||
if (IS_ERR(ldo1->regulator)) {
|
if (IS_ERR(ldo1->regulator)) {
|
||||||
if (config.ena_gpiod)
|
|
||||||
gpiod_put(config.ena_gpiod);
|
|
||||||
|
|
||||||
ret = PTR_ERR(ldo1->regulator);
|
ret = PTR_ERR(ldo1->regulator);
|
||||||
dev_err(&pdev->dev, "Failed to register LDO1 supply: %d\n",
|
dev_err(&pdev->dev, "Failed to register LDO1 supply: %d\n",
|
||||||
ret);
|
ret);
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* AS3711 PMIC regulator driver, using DCDC Step Down and LDO supplies
|
* AS3711 PMIC regulator driver, using DCDC Step Down and LDO supplies
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Renesas Electronics Corporation
|
* Copyright (C) 2012 Renesas Electronics Corporation
|
||||||
* Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
|
* Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the version 2 of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,6 +9,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/mfd/rohm-bd718x7.h>
|
#include <linux/mfd/rohm-bd718x7.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/driver.h>
|
#include <linux/regulator/driver.h>
|
||||||
#include <linux/regulator/machine.h>
|
#include <linux/regulator/machine.h>
|
||||||
|
@ -130,6 +131,7 @@ static struct regulator_ops bd718xx_buck_regulator_nolinear_ops = {
|
||||||
.disable = regulator_disable_regmap,
|
.disable = regulator_disable_regmap,
|
||||||
.is_enabled = regulator_is_enabled_regmap,
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
.list_voltage = regulator_list_voltage_table,
|
.list_voltage = regulator_list_voltage_table,
|
||||||
|
.map_voltage = regulator_map_voltage_ascend,
|
||||||
.set_voltage_sel = bd718xx_set_voltage_sel_restricted,
|
.set_voltage_sel = bd718xx_set_voltage_sel_restricted,
|
||||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||||
|
@ -1007,7 +1009,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bd718xx_pmic_inits {
|
struct bd718xx_pmic_inits {
|
||||||
const struct bd718xx_regulator_data (*r_datas)[];
|
const struct bd718xx_regulator_data *r_datas;
|
||||||
unsigned int r_amount;
|
unsigned int r_amount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1017,11 +1019,11 @@ static int bd718xx_probe(struct platform_device *pdev)
|
||||||
struct regulator_config config = { 0 };
|
struct regulator_config config = { 0 };
|
||||||
struct bd718xx_pmic_inits pmic_regulators[] = {
|
struct bd718xx_pmic_inits pmic_regulators[] = {
|
||||||
[BD718XX_TYPE_BD71837] = {
|
[BD718XX_TYPE_BD71837] = {
|
||||||
.r_datas = &bd71837_regulators,
|
.r_datas = bd71837_regulators,
|
||||||
.r_amount = ARRAY_SIZE(bd71837_regulators),
|
.r_amount = ARRAY_SIZE(bd71837_regulators),
|
||||||
},
|
},
|
||||||
[BD718XX_TYPE_BD71847] = {
|
[BD718XX_TYPE_BD71847] = {
|
||||||
.r_datas = &bd71847_regulators,
|
.r_datas = bd71847_regulators,
|
||||||
.r_amount = ARRAY_SIZE(bd71847_regulators),
|
.r_amount = ARRAY_SIZE(bd71847_regulators),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1053,13 +1055,36 @@ static int bd718xx_probe(struct platform_device *pdev)
|
||||||
BD718XX_REG_REGLOCK);
|
BD718XX_REG_REGLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* At poweroff transition PMIC HW disables EN bit for regulators but
|
||||||
|
* leaves SEL bit untouched. So if state transition from POWEROFF
|
||||||
|
* is done to SNVS - then all power rails controlled by SW (having
|
||||||
|
* SEL bit set) stay disabled as EN is cleared. This may result boot
|
||||||
|
* failure if any crucial systems are powered by these rails.
|
||||||
|
*
|
||||||
|
* Change the next stage from poweroff to be READY instead of SNVS
|
||||||
|
* for all reset types because OTP loading at READY will clear SEL
|
||||||
|
* bit allowing HW defaults for power rails to be used
|
||||||
|
*/
|
||||||
|
err = regmap_update_bits(mfd->regmap, BD718XX_REG_TRANS_COND1,
|
||||||
|
BD718XX_ON_REQ_POWEROFF_MASK |
|
||||||
|
BD718XX_SWRESET_POWEROFF_MASK |
|
||||||
|
BD718XX_WDOG_POWEROFF_MASK |
|
||||||
|
BD718XX_KEY_L_POWEROFF_MASK,
|
||||||
|
BD718XX_POWOFF_TO_RDY);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "Failed to change reset target\n");
|
||||||
|
goto err;
|
||||||
|
} else {
|
||||||
|
dev_dbg(&pdev->dev, "Changed all resets from SVNS to READY\n");
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) {
|
for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) {
|
||||||
|
|
||||||
const struct regulator_desc *desc;
|
const struct regulator_desc *desc;
|
||||||
struct regulator_dev *rdev;
|
struct regulator_dev *rdev;
|
||||||
const struct bd718xx_regulator_data *r;
|
const struct bd718xx_regulator_data *r;
|
||||||
|
|
||||||
r = &(*pmic_regulators[mfd->chip_type].r_datas)[i];
|
r = &pmic_regulators[mfd->chip_type].r_datas[i];
|
||||||
desc = &r->desc;
|
desc = &r->desc;
|
||||||
|
|
||||||
config.dev = pdev->dev.parent;
|
config.dev = pdev->dev.parent;
|
||||||
|
|
|
@ -1,17 +1,9 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* ROHM BD9571MWV-M regulator driver
|
* ROHM BD9571MWV-M regulator driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
|
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
|
||||||
* kind, whether expressed or implied; without even the implied warranty
|
|
||||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License version 2 for more details.
|
|
||||||
*
|
|
||||||
* Based on the TPS65086 driver
|
* Based on the TPS65086 driver
|
||||||
*
|
*
|
||||||
* NOTE: VD09 is missing
|
* NOTE: VD09 is missing
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -435,7 +435,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
for_each_child_of_node(nproot, np) {
|
for_each_child_of_node(nproot, np) {
|
||||||
if (!of_node_cmp(np->name,
|
if (of_node_name_eq(np,
|
||||||
regulator->info->reg_desc.name)) {
|
regulator->info->reg_desc.name)) {
|
||||||
config.init_data = of_get_regulator_init_data(
|
config.init_data = of_get_regulator_init_data(
|
||||||
&pdev->dev, np,
|
&pdev->dev, np,
|
||||||
|
|
|
@ -131,7 +131,7 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto error_i2c;
|
goto error_i2c;
|
||||||
|
|
||||||
mutex_lock(&chip->rdev->mutex);
|
regulator_lock(chip->rdev);
|
||||||
|
|
||||||
if (val & DA9210_E_OVCURR) {
|
if (val & DA9210_E_OVCURR) {
|
||||||
regulator_notifier_call_chain(chip->rdev,
|
regulator_notifier_call_chain(chip->rdev,
|
||||||
|
@ -157,7 +157,7 @@ static irqreturn_t da9210_irq_handler(int irq, void *data)
|
||||||
handled |= DA9210_E_VMAX;
|
handled |= DA9210_E_VMAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&chip->rdev->mutex);
|
regulator_unlock(chip->rdev);
|
||||||
|
|
||||||
if (handled) {
|
if (handled) {
|
||||||
/* Clear handled events */
|
/* Clear handled events */
|
||||||
|
|
|
@ -389,6 +389,12 @@ static int da9211_regulator_init(struct da9211 *chip)
|
||||||
else
|
else
|
||||||
config.ena_gpiod = NULL;
|
config.ena_gpiod = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hand the GPIO descriptor management over to the regulator
|
||||||
|
* core, remove it from GPIO devres management.
|
||||||
|
*/
|
||||||
|
if (config.ena_gpiod)
|
||||||
|
devm_gpiod_unhinge(chip->dev, config.ena_gpiod);
|
||||||
chip->rdev[i] = devm_regulator_register(chip->dev,
|
chip->rdev[i] = devm_regulator_register(chip->dev,
|
||||||
&da9211_regulators[i], &config);
|
&da9211_regulators[i], &config);
|
||||||
if (IS_ERR(chip->rdev[i])) {
|
if (IS_ERR(chip->rdev[i])) {
|
||||||
|
|
|
@ -75,7 +75,7 @@ static struct ux500_regulator_debug {
|
||||||
u8 *state_after_suspend;
|
u8 *state_after_suspend;
|
||||||
} rdebug;
|
} rdebug;
|
||||||
|
|
||||||
static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
|
static int ux500_regulator_power_state_cnt_show(struct seq_file *s, void *p)
|
||||||
{
|
{
|
||||||
/* print power state count */
|
/* print power state count */
|
||||||
seq_printf(s, "ux500-regulator power state count: %i\n",
|
seq_printf(s, "ux500-regulator power state count: %i\n",
|
||||||
|
@ -83,23 +83,9 @@ static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
DEFINE_SHOW_ATTRIBUTE(ux500_regulator_power_state_cnt);
|
||||||
|
|
||||||
static int ux500_regulator_power_state_cnt_open(struct inode *inode,
|
static int ux500_regulator_status_show(struct seq_file *s, void *p)
|
||||||
struct file *file)
|
|
||||||
{
|
|
||||||
return single_open(file, ux500_regulator_power_state_cnt_print,
|
|
||||||
inode->i_private);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct file_operations ux500_regulator_power_state_cnt_fops = {
|
|
||||||
.open = ux500_regulator_power_state_cnt_open,
|
|
||||||
.read = seq_read,
|
|
||||||
.llseek = seq_lseek,
|
|
||||||
.release = single_release,
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int ux500_regulator_status_print(struct seq_file *s, void *p)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -122,20 +108,7 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
DEFINE_SHOW_ATTRIBUTE(ux500_regulator_status);
|
||||||
static int ux500_regulator_status_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
return single_open(file, ux500_regulator_status_print,
|
|
||||||
inode->i_private);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct file_operations ux500_regulator_status_fops = {
|
|
||||||
.open = ux500_regulator_status_open,
|
|
||||||
.read = seq_read,
|
|
||||||
.llseek = seq_lseek,
|
|
||||||
.release = single_release,
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
};
|
|
||||||
|
|
||||||
int __attribute__((weak)) dbx500_regulator_testcase(
|
int __attribute__((weak)) dbx500_regulator_testcase(
|
||||||
struct dbx500_regulator_info *regulator_info,
|
struct dbx500_regulator_info *regulator_info,
|
||||||
|
|
|
@ -183,7 +183,11 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
|
||||||
*/
|
*/
|
||||||
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
|
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
|
||||||
|
|
||||||
cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags);
|
/*
|
||||||
|
* Do not use devm* here: the regulator core takes over the
|
||||||
|
* lifecycle management of the GPIO descriptor.
|
||||||
|
*/
|
||||||
|
cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags);
|
||||||
if (IS_ERR(cfg.ena_gpiod))
|
if (IS_ERR(cfg.ena_gpiod))
|
||||||
return PTR_ERR(cfg.ena_gpiod);
|
return PTR_ERR(cfg.ena_gpiod);
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@ struct regulator {
|
||||||
unsigned int always_on:1;
|
unsigned int always_on:1;
|
||||||
unsigned int bypass:1;
|
unsigned int bypass:1;
|
||||||
int uA_load;
|
int uA_load;
|
||||||
|
unsigned int enable_count;
|
||||||
|
unsigned int deferred_disables;
|
||||||
struct regulator_voltage voltage[REGULATOR_STATES_NUM];
|
struct regulator_voltage voltage[REGULATOR_STATES_NUM];
|
||||||
const char *supply_name;
|
const char *supply_name;
|
||||||
struct device_attribute dev_attr;
|
struct device_attribute dev_attr;
|
||||||
|
|
|
@ -224,13 +224,15 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev,
|
||||||
/*
|
/*
|
||||||
* Check LCM_EN1/2_GPIO is configured.
|
* Check LCM_EN1/2_GPIO is configured.
|
||||||
* Those pins are used for enabling VPOS/VNEG LDOs.
|
* Those pins are used for enabling VPOS/VNEG LDOs.
|
||||||
|
* Do not use devm* here: the regulator core takes over the
|
||||||
|
* lifecycle management of the GPIO descriptor.
|
||||||
*/
|
*/
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case LM3632_LDO_POS:
|
case LM3632_LDO_POS:
|
||||||
return devm_gpiod_get_index_optional(dev, "enable", 0,
|
return gpiod_get_index_optional(dev, "enable", 0,
|
||||||
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
|
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
|
||||||
case LM3632_LDO_NEG:
|
case LM3632_LDO_NEG:
|
||||||
return devm_gpiod_get_index_optional(dev, "enable", 1,
|
return gpiod_get_index_optional(dev, "enable", 1,
|
||||||
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
|
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -263,6 +265,8 @@ static int lm363x_regulator_probe(struct platform_device *pdev)
|
||||||
LM3632_EXT_EN_MASK,
|
LM3632_EXT_EN_MASK,
|
||||||
LM3632_EXT_EN_MASK);
|
LM3632_EXT_EN_MASK);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
if (gpiod)
|
||||||
|
gpiod_put(gpiod);
|
||||||
dev_err(dev, "External pin err: %d\n", ret);
|
dev_err(dev, "External pin err: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/driver.h>
|
#include <linux/regulator/driver.h>
|
||||||
|
@ -20,6 +21,8 @@
|
||||||
#include <linux/regulator/of_regulator.h>
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
|
||||||
#include <linux/mfd/lochnagar.h>
|
#include <linux/mfd/lochnagar.h>
|
||||||
|
#include <linux/mfd/lochnagar1_regs.h>
|
||||||
|
#include <linux/mfd/lochnagar2_regs.h>
|
||||||
|
|
||||||
static const struct regulator_ops lochnagar_micvdd_ops = {
|
static const struct regulator_ops lochnagar_micvdd_ops = {
|
||||||
.enable = regulator_enable_regmap,
|
.enable = regulator_enable_regmap,
|
||||||
|
@ -212,28 +215,52 @@ static const struct regulator_desc lochnagar_regulators[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id lochnagar_of_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "cirrus,lochnagar2-micvdd",
|
||||||
|
.data = &lochnagar_regulators[LOCHNAGAR_MICVDD],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "cirrus,lochnagar2-mic1vdd",
|
||||||
|
.data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "cirrus,lochnagar2-mic2vdd",
|
||||||
|
.data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "cirrus,lochnagar2-vddcore",
|
||||||
|
.data = &lochnagar_regulators[LOCHNAGAR_VDDCORE],
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
static int lochnagar_regulator_probe(struct platform_device *pdev)
|
static int lochnagar_regulator_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
|
struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
|
||||||
struct regulator_config config = { };
|
struct regulator_config config = { };
|
||||||
|
const struct of_device_id *of_id;
|
||||||
|
const struct regulator_desc *desc;
|
||||||
struct regulator_dev *rdev;
|
struct regulator_dev *rdev;
|
||||||
int ret, i;
|
int ret;
|
||||||
|
|
||||||
config.dev = lochnagar->dev;
|
config.dev = dev;
|
||||||
config.regmap = lochnagar->regmap;
|
config.regmap = lochnagar->regmap;
|
||||||
config.driver_data = lochnagar;
|
config.driver_data = lochnagar;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) {
|
of_id = of_match_device(lochnagar_of_match, dev);
|
||||||
const struct regulator_desc *desc = &lochnagar_regulators[i];
|
if (!of_id)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
rdev = devm_regulator_register(dev, desc, &config);
|
desc = of_id->data;
|
||||||
if (IS_ERR(rdev)) {
|
|
||||||
ret = PTR_ERR(rdev);
|
rdev = devm_regulator_register(dev, desc, &config);
|
||||||
dev_err(dev, "Failed to register %s regulator: %d\n",
|
if (IS_ERR(rdev)) {
|
||||||
desc->name, ret);
|
ret = PTR_ERR(rdev);
|
||||||
return ret;
|
dev_err(dev, "Failed to register %s regulator: %d\n",
|
||||||
}
|
desc->name, ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -242,6 +269,7 @@ static int lochnagar_regulator_probe(struct platform_device *pdev)
|
||||||
static struct platform_driver lochnagar_regulator_driver = {
|
static struct platform_driver lochnagar_regulator_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "lochnagar-regulator",
|
.name = "lochnagar-regulator",
|
||||||
|
.of_match_table = of_match_ptr(lochnagar_of_match),
|
||||||
},
|
},
|
||||||
|
|
||||||
.probe = lochnagar_regulator_probe,
|
.probe = lochnagar_regulator_probe,
|
||||||
|
|
|
@ -501,8 +501,12 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: check default mode for GPIO here: high or low? */
|
/*
|
||||||
ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev,
|
* Do not use devm* here: the regulator core takes over the
|
||||||
|
* lifecycle management of the GPIO descriptor.
|
||||||
|
* FIXME: check default mode for GPIO here: high or low?
|
||||||
|
*/
|
||||||
|
ldo->ena_gpiod = gpiod_get_index_optional(&pdev->dev,
|
||||||
"enable",
|
"enable",
|
||||||
enable_id,
|
enable_id,
|
||||||
GPIOD_OUT_HIGH |
|
GPIOD_OUT_HIGH |
|
||||||
|
|
|
@ -11,8 +11,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/bug.h>
|
#include <linux/bug.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/of_gpio.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/driver.h>
|
#include <linux/regulator/driver.h>
|
||||||
|
@ -76,6 +75,7 @@ enum max77686_ramp_rate {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct max77686_data {
|
struct max77686_data {
|
||||||
|
struct device *dev;
|
||||||
DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS);
|
DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS);
|
||||||
|
|
||||||
/* Array indexed by regulator id */
|
/* Array indexed by regulator id */
|
||||||
|
@ -250,26 +250,34 @@ static int max77686_of_parse_cb(struct device_node *np,
|
||||||
struct regulator_config *config)
|
struct regulator_config *config)
|
||||||
{
|
{
|
||||||
struct max77686_data *max77686 = config->driver_data;
|
struct max77686_data *max77686 = config->driver_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
switch (desc->id) {
|
switch (desc->id) {
|
||||||
case MAX77686_BUCK8:
|
case MAX77686_BUCK8:
|
||||||
case MAX77686_BUCK9:
|
case MAX77686_BUCK9:
|
||||||
case MAX77686_LDO20 ... MAX77686_LDO22:
|
case MAX77686_LDO20 ... MAX77686_LDO22:
|
||||||
config->ena_gpio = of_get_named_gpio(np,
|
config->ena_gpiod = gpiod_get_from_of_node(np,
|
||||||
"maxim,ena-gpios", 0);
|
"maxim,ena",
|
||||||
config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
|
0,
|
||||||
config->ena_gpio_initialized = true;
|
GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
|
||||||
|
"max77686-regulator");
|
||||||
|
if (IS_ERR(config->ena_gpiod))
|
||||||
|
config->ena_gpiod = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_is_valid(config->ena_gpio)) {
|
if (config->ena_gpiod) {
|
||||||
set_bit(desc->id, max77686->gpio_enabled);
|
set_bit(desc->id, max77686->gpio_enabled);
|
||||||
|
|
||||||
return regmap_update_bits(config->regmap, desc->enable_reg,
|
ret = regmap_update_bits(config->regmap, desc->enable_reg,
|
||||||
desc->enable_mask,
|
desc->enable_mask,
|
||||||
MAX77686_GPIO_CONTROL);
|
MAX77686_GPIO_CONTROL);
|
||||||
|
if (ret) {
|
||||||
|
gpiod_put(config->ena_gpiod);
|
||||||
|
config->ena_gpiod = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -507,6 +515,7 @@ static int max77686_pmic_probe(struct platform_device *pdev)
|
||||||
if (!max77686)
|
if (!max77686)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
max77686->dev = &pdev->dev;
|
||||||
config.dev = iodev->dev;
|
config.dev = iodev->dev;
|
||||||
config.regmap = iodev->regmap;
|
config.regmap = iodev->regmap;
|
||||||
config.driver_data = max77686;
|
config.driver_data = max77686;
|
||||||
|
|
|
@ -231,9 +231,13 @@ static int max8952_pmic_probe(struct i2c_client *client,
|
||||||
else
|
else
|
||||||
gflags = GPIOD_OUT_LOW;
|
gflags = GPIOD_OUT_LOW;
|
||||||
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
|
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
|
||||||
gpiod = devm_gpiod_get_optional(&client->dev,
|
/*
|
||||||
"max8952,en",
|
* Do not use devm* here: the regulator core takes over the
|
||||||
gflags);
|
* lifecycle management of the GPIO descriptor.
|
||||||
|
*/
|
||||||
|
gpiod = gpiod_get_optional(&client->dev,
|
||||||
|
"max8952,en",
|
||||||
|
gflags);
|
||||||
if (IS_ERR(gpiod))
|
if (IS_ERR(gpiod))
|
||||||
return PTR_ERR(gpiod);
|
return PTR_ERR(gpiod);
|
||||||
if (gpiod)
|
if (gpiod)
|
||||||
|
|
|
@ -808,7 +808,13 @@ static int max8973_probe(struct i2c_client *client,
|
||||||
config.of_node = client->dev.of_node;
|
config.of_node = client->dev.of_node;
|
||||||
config.regmap = max->regmap;
|
config.regmap = max->regmap;
|
||||||
|
|
||||||
/* Register the regulators */
|
/*
|
||||||
|
* Register the regulators
|
||||||
|
* Turn the GPIO descriptor over to the regulator core for
|
||||||
|
* lifecycle management if we pass an ena_gpiod.
|
||||||
|
*/
|
||||||
|
if (config.ena_gpiod)
|
||||||
|
devm_gpiod_unhinge(&client->dev, config.ena_gpiod);
|
||||||
rdev = devm_regulator_register(&client->dev, &max->desc, &config);
|
rdev = devm_regulator_register(&client->dev, &max->desc, &config);
|
||||||
if (IS_ERR(rdev)) {
|
if (IS_ERR(rdev)) {
|
||||||
ret = PTR_ERR(rdev);
|
ret = PTR_ERR(rdev);
|
||||||
|
|
|
@ -925,7 +925,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
|
||||||
pdata->regulators = rdata;
|
pdata->regulators = rdata;
|
||||||
for_each_child_of_node(regulators_np, reg_np) {
|
for_each_child_of_node(regulators_np, reg_np) {
|
||||||
for (i = 0; i < ARRAY_SIZE(regulators); i++)
|
for (i = 0; i < ARRAY_SIZE(regulators); i++)
|
||||||
if (!of_node_cmp(reg_np->name, regulators[i].name))
|
if (of_node_name_eq(reg_np, regulators[i].name))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == ARRAY_SIZE(regulators)) {
|
if (i == ARRAY_SIZE(regulators)) {
|
||||||
|
|
|
@ -186,7 +186,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
|
||||||
for (i = 0; i < num_regulators; i++) {
|
for (i = 0; i < num_regulators; i++) {
|
||||||
if (!regulators[i].desc.name)
|
if (!regulators[i].desc.name)
|
||||||
continue;
|
continue;
|
||||||
if (!of_node_cmp(child->name,
|
if (of_node_name_eq(child,
|
||||||
regulators[i].desc.name)) {
|
regulators[i].desc.name)) {
|
||||||
p->id = i;
|
p->id = i;
|
||||||
p->init_data = of_get_regulator_init_data(
|
p->init_data = of_get_regulator_init_data(
|
||||||
|
|
|
@ -0,0 +1,552 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
//
|
||||||
|
// MCP16502 PMIC driver
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries
|
||||||
|
//
|
||||||
|
// Author: Andrei Stefanescu <andrei.stefanescu@microchip.com>
|
||||||
|
//
|
||||||
|
// Inspired from tps65086-regulator.c
|
||||||
|
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
|
||||||
|
#define VDD_LOW_SEL 0x0D
|
||||||
|
#define VDD_HIGH_SEL 0x3F
|
||||||
|
|
||||||
|
#define MCP16502_FLT BIT(7)
|
||||||
|
#define MCP16502_ENS BIT(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The PMIC has four sets of registers corresponding to four power modes:
|
||||||
|
* Performance, Active, Low-power, Hibernate.
|
||||||
|
*
|
||||||
|
* Registers:
|
||||||
|
* Each regulator has a register for each power mode. To access a register
|
||||||
|
* for a specific regulator and mode BASE_* and OFFSET_* need to be added.
|
||||||
|
*
|
||||||
|
* Operating modes:
|
||||||
|
* In order for the PMIC to transition to operating modes it has to be
|
||||||
|
* controlled via GPIO lines called LPM and HPM.
|
||||||
|
*
|
||||||
|
* The registers are fully configurable such that you can put all regulators in
|
||||||
|
* a low-power state while the PMIC is in Active mode. They are supposed to be
|
||||||
|
* configured at startup and then simply transition to/from a global low-power
|
||||||
|
* state by setting the GPIO lpm pin high/low.
|
||||||
|
*
|
||||||
|
* This driver keeps the PMIC in Active mode, Low-power state is set for the
|
||||||
|
* regulators by enabling/disabling operating mode (FPWM or Auto PFM).
|
||||||
|
*
|
||||||
|
* The PMIC's Low-power and Hibernate modes are used during standby/suspend.
|
||||||
|
* To enter standby/suspend the PMIC will go to Low-power mode. From there, it
|
||||||
|
* will transition to Hibernate when the PWRHLD line is set to low by the MPU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is useful for iterating over all regulators and accessing their
|
||||||
|
* registers in a generic way or accessing a regulator device by its id.
|
||||||
|
*/
|
||||||
|
#define MCP16502_BASE(i) (((i) + 1) << 4)
|
||||||
|
#define MCP16502_STAT_BASE(i) ((i) + 5)
|
||||||
|
|
||||||
|
#define MCP16502_OFFSET_MODE_A 0
|
||||||
|
#define MCP16502_OFFSET_MODE_LPM 1
|
||||||
|
#define MCP16502_OFFSET_MODE_HIB 2
|
||||||
|
|
||||||
|
#define MCP16502_OPMODE_ACTIVE REGULATOR_MODE_NORMAL
|
||||||
|
#define MCP16502_OPMODE_LPM REGULATOR_MODE_IDLE
|
||||||
|
#define MCP16502_OPMODE_HIB REGULATOR_MODE_STANDBY
|
||||||
|
|
||||||
|
#define MCP16502_MODE_AUTO_PFM 0
|
||||||
|
#define MCP16502_MODE_FPWM BIT(6)
|
||||||
|
|
||||||
|
#define MCP16502_VSEL 0x3F
|
||||||
|
#define MCP16502_EN BIT(7)
|
||||||
|
#define MCP16502_MODE BIT(6)
|
||||||
|
|
||||||
|
#define MCP16502_MIN_REG 0x0
|
||||||
|
#define MCP16502_MAX_REG 0x65
|
||||||
|
|
||||||
|
static unsigned int mcp16502_of_map_mode(unsigned int mode)
|
||||||
|
{
|
||||||
|
if (mode == REGULATOR_MODE_NORMAL || mode == REGULATOR_MODE_IDLE)
|
||||||
|
return mode;
|
||||||
|
|
||||||
|
return REGULATOR_MODE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MCP16502_REGULATOR(_name, _id, _ranges, _ops) \
|
||||||
|
[_id] = { \
|
||||||
|
.name = _name, \
|
||||||
|
.regulators_node = of_match_ptr("regulators"), \
|
||||||
|
.id = _id, \
|
||||||
|
.ops = &(_ops), \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.n_voltages = MCP16502_VSEL + 1, \
|
||||||
|
.linear_ranges = _ranges, \
|
||||||
|
.n_linear_ranges = ARRAY_SIZE(_ranges), \
|
||||||
|
.of_match = of_match_ptr(_name), \
|
||||||
|
.of_map_mode = mcp16502_of_map_mode, \
|
||||||
|
.vsel_reg = (((_id) + 1) << 4), \
|
||||||
|
.vsel_mask = MCP16502_VSEL, \
|
||||||
|
.enable_reg = (((_id) + 1) << 4), \
|
||||||
|
.enable_mask = MCP16502_EN, \
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BUCK1 = 0,
|
||||||
|
BUCK2,
|
||||||
|
BUCK3,
|
||||||
|
BUCK4,
|
||||||
|
LDO1,
|
||||||
|
LDO2,
|
||||||
|
NUM_REGULATORS
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct mcp16502 - PMIC representation
|
||||||
|
* @rdev: the regulators belonging to this chip
|
||||||
|
* @rmap: regmap to be used for I2C communication
|
||||||
|
* @lpm: LPM GPIO descriptor
|
||||||
|
*/
|
||||||
|
struct mcp16502 {
|
||||||
|
struct regulator_dev *rdev[NUM_REGULATORS];
|
||||||
|
struct regmap *rmap;
|
||||||
|
struct gpio_desc *lpm;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp16502_gpio_set_mode() - set the GPIO corresponding value
|
||||||
|
*
|
||||||
|
* Used to prepare transitioning into hibernate or resuming from it.
|
||||||
|
*/
|
||||||
|
static void mcp16502_gpio_set_mode(struct mcp16502 *mcp, int mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case MCP16502_OPMODE_ACTIVE:
|
||||||
|
gpiod_set_value(mcp->lpm, 0);
|
||||||
|
break;
|
||||||
|
case MCP16502_OPMODE_LPM:
|
||||||
|
case MCP16502_OPMODE_HIB:
|
||||||
|
gpiod_set_value(mcp->lpm, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("%s: %d invalid\n", __func__, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp16502_get_reg() - get the PMIC's configuration register for opmode
|
||||||
|
*
|
||||||
|
* @rdev: the regulator whose register we are searching
|
||||||
|
* @opmode: the PMIC's operating mode ACTIVE, Low-power, Hibernate
|
||||||
|
*/
|
||||||
|
static int mcp16502_get_reg(struct regulator_dev *rdev, int opmode)
|
||||||
|
{
|
||||||
|
int reg = MCP16502_BASE(rdev_get_id(rdev));
|
||||||
|
|
||||||
|
switch (opmode) {
|
||||||
|
case MCP16502_OPMODE_ACTIVE:
|
||||||
|
return reg + MCP16502_OFFSET_MODE_A;
|
||||||
|
case MCP16502_OPMODE_LPM:
|
||||||
|
return reg + MCP16502_OFFSET_MODE_LPM;
|
||||||
|
case MCP16502_OPMODE_HIB:
|
||||||
|
return reg + MCP16502_OFFSET_MODE_HIB;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp16502_get_mode() - return the current operating mode of a regulator
|
||||||
|
*
|
||||||
|
* Note: all functions that are not part of entering/exiting standby/suspend
|
||||||
|
* use the Active mode registers.
|
||||||
|
*
|
||||||
|
* Note: this is different from the PMIC's operatig mode, it is the
|
||||||
|
* MODE bit from the regulator's register.
|
||||||
|
*/
|
||||||
|
static unsigned int mcp16502_get_mode(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
unsigned int val;
|
||||||
|
int ret, reg;
|
||||||
|
struct mcp16502 *mcp = rdev_get_drvdata(rdev);
|
||||||
|
|
||||||
|
reg = mcp16502_get_reg(rdev, MCP16502_OPMODE_ACTIVE);
|
||||||
|
if (reg < 0)
|
||||||
|
return reg;
|
||||||
|
|
||||||
|
ret = regmap_read(mcp->rmap, reg, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
switch (val & MCP16502_MODE) {
|
||||||
|
case MCP16502_MODE_FPWM:
|
||||||
|
return REGULATOR_MODE_NORMAL;
|
||||||
|
case MCP16502_MODE_AUTO_PFM:
|
||||||
|
return REGULATOR_MODE_IDLE;
|
||||||
|
default:
|
||||||
|
return REGULATOR_MODE_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _mcp16502_set_mode() - helper for set_mode and set_suspend_mode
|
||||||
|
*
|
||||||
|
* @rdev: the regulator for which we are setting the mode
|
||||||
|
* @mode: the regulator's mode (the one from MODE bit)
|
||||||
|
* @opmode: the PMIC's operating mode: Active/Low-power/Hibernate
|
||||||
|
*/
|
||||||
|
static int _mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode,
|
||||||
|
unsigned int op_mode)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
int reg;
|
||||||
|
struct mcp16502 *mcp = rdev_get_drvdata(rdev);
|
||||||
|
|
||||||
|
reg = mcp16502_get_reg(rdev, op_mode);
|
||||||
|
if (reg < 0)
|
||||||
|
return reg;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case REGULATOR_MODE_NORMAL:
|
||||||
|
val = MCP16502_MODE_FPWM;
|
||||||
|
break;
|
||||||
|
case REGULATOR_MODE_IDLE:
|
||||||
|
val = MCP16502_MODE_AUTO_PFM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = regmap_update_bits(mcp->rmap, reg, MCP16502_MODE, val);
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp16502_set_mode() - regulator_ops set_mode
|
||||||
|
*/
|
||||||
|
static int mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode)
|
||||||
|
{
|
||||||
|
return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_ACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp16502_get_status() - regulator_ops get_status
|
||||||
|
*/
|
||||||
|
static int mcp16502_get_status(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned int val;
|
||||||
|
struct mcp16502 *mcp = rdev_get_drvdata(rdev);
|
||||||
|
|
||||||
|
ret = regmap_read(mcp->rmap, MCP16502_STAT_BASE(rdev_get_id(rdev)),
|
||||||
|
&val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (val & MCP16502_FLT)
|
||||||
|
return REGULATOR_STATUS_ERROR;
|
||||||
|
else if (val & MCP16502_ENS)
|
||||||
|
return REGULATOR_STATUS_ON;
|
||||||
|
else if (!(val & MCP16502_ENS))
|
||||||
|
return REGULATOR_STATUS_OFF;
|
||||||
|
|
||||||
|
return REGULATOR_STATUS_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUSPEND
|
||||||
|
/*
|
||||||
|
* mcp16502_suspend_get_target_reg() - get the reg of the target suspend PMIC
|
||||||
|
* mode
|
||||||
|
*/
|
||||||
|
static int mcp16502_suspend_get_target_reg(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
switch (pm_suspend_target_state) {
|
||||||
|
case PM_SUSPEND_STANDBY:
|
||||||
|
return mcp16502_get_reg(rdev, MCP16502_OPMODE_LPM);
|
||||||
|
case PM_SUSPEND_ON:
|
||||||
|
case PM_SUSPEND_MEM:
|
||||||
|
return mcp16502_get_reg(rdev, MCP16502_OPMODE_HIB);
|
||||||
|
default:
|
||||||
|
dev_err(&rdev->dev, "invalid suspend target: %d\n",
|
||||||
|
pm_suspend_target_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp16502_set_suspend_voltage() - regulator_ops set_suspend_voltage
|
||||||
|
*/
|
||||||
|
static int mcp16502_set_suspend_voltage(struct regulator_dev *rdev, int uV)
|
||||||
|
{
|
||||||
|
struct mcp16502 *mcp = rdev_get_drvdata(rdev);
|
||||||
|
int sel = regulator_map_voltage_linear_range(rdev, uV, uV);
|
||||||
|
int reg = mcp16502_suspend_get_target_reg(rdev);
|
||||||
|
|
||||||
|
if (sel < 0)
|
||||||
|
return sel;
|
||||||
|
|
||||||
|
if (reg < 0)
|
||||||
|
return reg;
|
||||||
|
|
||||||
|
return regmap_update_bits(mcp->rmap, reg, MCP16502_VSEL, sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp16502_set_suspend_mode() - regulator_ops set_suspend_mode
|
||||||
|
*/
|
||||||
|
static int mcp16502_set_suspend_mode(struct regulator_dev *rdev,
|
||||||
|
unsigned int mode)
|
||||||
|
{
|
||||||
|
switch (pm_suspend_target_state) {
|
||||||
|
case PM_SUSPEND_STANDBY:
|
||||||
|
return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_LPM);
|
||||||
|
case PM_SUSPEND_ON:
|
||||||
|
case PM_SUSPEND_MEM:
|
||||||
|
return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_HIB);
|
||||||
|
default:
|
||||||
|
dev_err(&rdev->dev, "invalid suspend target: %d\n",
|
||||||
|
pm_suspend_target_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp16502_set_suspend_enable() - regulator_ops set_suspend_enable
|
||||||
|
*/
|
||||||
|
static int mcp16502_set_suspend_enable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct mcp16502 *mcp = rdev_get_drvdata(rdev);
|
||||||
|
int reg = mcp16502_suspend_get_target_reg(rdev);
|
||||||
|
|
||||||
|
if (reg < 0)
|
||||||
|
return reg;
|
||||||
|
|
||||||
|
return regmap_update_bits(mcp->rmap, reg, MCP16502_EN, MCP16502_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mcp16502_set_suspend_disable() - regulator_ops set_suspend_disable
|
||||||
|
*/
|
||||||
|
static int mcp16502_set_suspend_disable(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct mcp16502 *mcp = rdev_get_drvdata(rdev);
|
||||||
|
int reg = mcp16502_suspend_get_target_reg(rdev);
|
||||||
|
|
||||||
|
if (reg < 0)
|
||||||
|
return reg;
|
||||||
|
|
||||||
|
return regmap_update_bits(mcp->rmap, reg, MCP16502_EN, 0);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SUSPEND */
|
||||||
|
|
||||||
|
static const struct regulator_ops mcp16502_buck_ops = {
|
||||||
|
.list_voltage = regulator_list_voltage_linear_range,
|
||||||
|
.map_voltage = regulator_map_voltage_linear_range,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.get_status = mcp16502_get_status,
|
||||||
|
|
||||||
|
.set_mode = mcp16502_set_mode,
|
||||||
|
.get_mode = mcp16502_get_mode,
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUSPEND
|
||||||
|
.set_suspend_voltage = mcp16502_set_suspend_voltage,
|
||||||
|
.set_suspend_mode = mcp16502_set_suspend_mode,
|
||||||
|
.set_suspend_enable = mcp16502_set_suspend_enable,
|
||||||
|
.set_suspend_disable = mcp16502_set_suspend_disable,
|
||||||
|
#endif /* CONFIG_SUSPEND */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LDOs cannot change operating modes.
|
||||||
|
*/
|
||||||
|
static const struct regulator_ops mcp16502_ldo_ops = {
|
||||||
|
.list_voltage = regulator_list_voltage_linear_range,
|
||||||
|
.map_voltage = regulator_map_voltage_linear_range,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.get_status = mcp16502_get_status,
|
||||||
|
|
||||||
|
#ifdef CONFIG_SUSPEND
|
||||||
|
.set_suspend_voltage = mcp16502_set_suspend_voltage,
|
||||||
|
.set_suspend_enable = mcp16502_set_suspend_enable,
|
||||||
|
.set_suspend_disable = mcp16502_set_suspend_disable,
|
||||||
|
#endif /* CONFIG_SUSPEND */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id mcp16502_ids[] = {
|
||||||
|
{ .compatible = "microchip,mcp16502", },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, mcp16502_ids);
|
||||||
|
|
||||||
|
static const struct regulator_linear_range b1l12_ranges[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE(1200000, VDD_LOW_SEL, VDD_HIGH_SEL, 50000),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_linear_range b234_ranges[] = {
|
||||||
|
REGULATOR_LINEAR_RANGE(600000, VDD_LOW_SEL, VDD_HIGH_SEL, 25000),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regulator_desc mcp16502_desc[] = {
|
||||||
|
/* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops) */
|
||||||
|
MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops),
|
||||||
|
MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops),
|
||||||
|
MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops),
|
||||||
|
MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops),
|
||||||
|
MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops),
|
||||||
|
MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops)
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regmap_range mcp16502_ranges[] = {
|
||||||
|
regmap_reg_range(MCP16502_MIN_REG, MCP16502_MAX_REG)
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regmap_access_table mcp16502_yes_reg_table = {
|
||||||
|
.yes_ranges = mcp16502_ranges,
|
||||||
|
.n_yes_ranges = ARRAY_SIZE(mcp16502_ranges),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regmap_config mcp16502_regmap_config = {
|
||||||
|
.reg_bits = 8,
|
||||||
|
.val_bits = 8,
|
||||||
|
.max_register = MCP16502_MAX_REG,
|
||||||
|
.cache_type = REGCACHE_NONE,
|
||||||
|
.rd_table = &mcp16502_yes_reg_table,
|
||||||
|
.wr_table = &mcp16502_yes_reg_table,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set_up_regulators() - initialize all regulators
|
||||||
|
*/
|
||||||
|
static int setup_regulators(struct mcp16502 *mcp, struct device *dev,
|
||||||
|
struct regulator_config config)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_REGULATORS; i++) {
|
||||||
|
mcp->rdev[i] = devm_regulator_register(dev,
|
||||||
|
&mcp16502_desc[i],
|
||||||
|
&config);
|
||||||
|
if (IS_ERR(mcp->rdev[i])) {
|
||||||
|
dev_err(dev,
|
||||||
|
"failed to register %s regulator %ld\n",
|
||||||
|
mcp16502_desc[i].name, PTR_ERR(mcp->rdev[i]));
|
||||||
|
return PTR_ERR(mcp->rdev[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mcp16502_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct regulator_config config = { };
|
||||||
|
struct device *dev;
|
||||||
|
struct mcp16502 *mcp;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
dev = &client->dev;
|
||||||
|
config.dev = dev;
|
||||||
|
|
||||||
|
mcp = devm_kzalloc(dev, sizeof(*mcp), GFP_KERNEL);
|
||||||
|
if (!mcp)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mcp->rmap = devm_regmap_init_i2c(client, &mcp16502_regmap_config);
|
||||||
|
if (IS_ERR(mcp->rmap)) {
|
||||||
|
ret = PTR_ERR(mcp->rmap);
|
||||||
|
dev_err(dev, "regmap init failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, mcp);
|
||||||
|
config.regmap = mcp->rmap;
|
||||||
|
config.driver_data = mcp;
|
||||||
|
|
||||||
|
mcp->lpm = devm_gpiod_get(dev, "lpm", GPIOD_OUT_LOW);
|
||||||
|
if (IS_ERR(mcp->lpm)) {
|
||||||
|
dev_err(dev, "failed to get lpm pin: %ld\n", PTR_ERR(mcp->lpm));
|
||||||
|
return PTR_ERR(mcp->lpm);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = setup_regulators(mcp, dev, config);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_ACTIVE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int mcp16502_suspend_noirq(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct mcp16502 *mcp = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_LPM);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mcp16502_resume_noirq(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct mcp16502 *mcp = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_ACTIVE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static const struct dev_pm_ops mcp16502_pm_ops = {
|
||||||
|
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mcp16502_suspend_noirq,
|
||||||
|
mcp16502_resume_noirq)
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
static const struct i2c_device_id mcp16502_i2c_id[] = {
|
||||||
|
{ "mcp16502", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, mcp16502_i2c_id);
|
||||||
|
|
||||||
|
static struct i2c_driver mcp16502_drv = {
|
||||||
|
.probe = mcp16502_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "mcp16502-regulator",
|
||||||
|
.of_match_table = of_match_ptr(mcp16502_ids),
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.pm = &mcp16502_pm_ops,
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
.id_table = mcp16502_i2c_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_i2c_driver(mcp16502_drv);
|
||||||
|
|
||||||
|
MODULE_VERSION("1.0");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_DESCRIPTION("MCP16502 PMIC driver");
|
||||||
|
MODULE_AUTHOR("Andrei Stefanescu andrei.stefanescu@microchip.com");
|
|
@ -20,6 +20,7 @@
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
|
static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
|
||||||
|
[PM_SUSPEND_STANDBY] = "regulator-state-standby",
|
||||||
[PM_SUSPEND_MEM] = "regulator-state-mem",
|
[PM_SUSPEND_MEM] = "regulator-state-mem",
|
||||||
[PM_SUSPEND_MAX] = "regulator-state-disk",
|
[PM_SUSPEND_MAX] = "regulator-state-disk",
|
||||||
};
|
};
|
||||||
|
@ -170,6 +171,10 @@ static void of_get_regulation_constraints(struct device_node *np,
|
||||||
&pval))
|
&pval))
|
||||||
constraints->max_spread = pval;
|
constraints->max_spread = pval;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "regulator-max-step-microvolt",
|
||||||
|
&pval))
|
||||||
|
constraints->max_uV_step = pval;
|
||||||
|
|
||||||
constraints->over_current_protection = of_property_read_bool(np,
|
constraints->over_current_protection = of_property_read_bool(np,
|
||||||
"regulator-over-current-protection");
|
"regulator-over-current-protection");
|
||||||
|
|
||||||
|
@ -181,9 +186,11 @@ static void of_get_regulation_constraints(struct device_node *np,
|
||||||
case PM_SUSPEND_MAX:
|
case PM_SUSPEND_MAX:
|
||||||
suspend_state = &constraints->state_disk;
|
suspend_state = &constraints->state_disk;
|
||||||
break;
|
break;
|
||||||
|
case PM_SUSPEND_STANDBY:
|
||||||
|
suspend_state = &constraints->state_standby;
|
||||||
|
break;
|
||||||
case PM_SUSPEND_ON:
|
case PM_SUSPEND_ON:
|
||||||
case PM_SUSPEND_TO_IDLE:
|
case PM_SUSPEND_TO_IDLE:
|
||||||
case PM_SUSPEND_STANDBY:
|
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -364,24 +371,25 @@ int of_regulator_match(struct device *dev, struct device_node *node,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_regulator_match);
|
EXPORT_SYMBOL_GPL(of_regulator_match);
|
||||||
|
|
||||||
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
|
struct device_node *regulator_of_get_init_node(struct device *dev,
|
||||||
const struct regulator_desc *desc,
|
const struct regulator_desc *desc)
|
||||||
struct regulator_config *config,
|
|
||||||
struct device_node **node)
|
|
||||||
{
|
{
|
||||||
struct device_node *search, *child;
|
struct device_node *search, *child;
|
||||||
struct regulator_init_data *init_data = NULL;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
if (!dev->of_node || !desc->of_match)
|
if (!dev->of_node || !desc->of_match)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (desc->regulators_node)
|
if (desc->regulators_node) {
|
||||||
search = of_get_child_by_name(dev->of_node,
|
search = of_get_child_by_name(dev->of_node,
|
||||||
desc->regulators_node);
|
desc->regulators_node);
|
||||||
else
|
} else {
|
||||||
search = of_node_get(dev->of_node);
|
search = of_node_get(dev->of_node);
|
||||||
|
|
||||||
|
if (!strcmp(desc->of_match, search->name))
|
||||||
|
return search;
|
||||||
|
}
|
||||||
|
|
||||||
if (!search) {
|
if (!search) {
|
||||||
dev_dbg(dev, "Failed to find regulator container node '%s'\n",
|
dev_dbg(dev, "Failed to find regulator container node '%s'\n",
|
||||||
desc->regulators_node);
|
desc->regulators_node);
|
||||||
|
@ -393,35 +401,48 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
|
||||||
if (!name)
|
if (!name)
|
||||||
name = child->name;
|
name = child->name;
|
||||||
|
|
||||||
if (strcmp(desc->of_match, name))
|
if (!strcmp(desc->of_match, name))
|
||||||
continue;
|
return of_node_get(child);
|
||||||
|
|
||||||
init_data = of_get_regulator_init_data(dev, child, desc);
|
|
||||||
if (!init_data) {
|
|
||||||
dev_err(dev,
|
|
||||||
"failed to parse DT for regulator %pOFn\n",
|
|
||||||
child);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desc->of_parse_cb) {
|
|
||||||
if (desc->of_parse_cb(child, desc, config)) {
|
|
||||||
dev_err(dev,
|
|
||||||
"driver callback failed to parse DT for regulator %pOFn\n",
|
|
||||||
child);
|
|
||||||
init_data = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
of_node_get(child);
|
|
||||||
*node = child;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
of_node_put(search);
|
of_node_put(search);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
|
||||||
|
const struct regulator_desc *desc,
|
||||||
|
struct regulator_config *config,
|
||||||
|
struct device_node **node)
|
||||||
|
{
|
||||||
|
struct device_node *child;
|
||||||
|
struct regulator_init_data *init_data = NULL;
|
||||||
|
|
||||||
|
child = regulator_of_get_init_node(dev, desc);
|
||||||
|
if (!child)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
init_data = of_get_regulator_init_data(dev, child, desc);
|
||||||
|
if (!init_data) {
|
||||||
|
dev_err(dev, "failed to parse DT for regulator %pOFn\n", child);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc->of_parse_cb && desc->of_parse_cb(child, desc, config)) {
|
||||||
|
dev_err(dev,
|
||||||
|
"driver callback failed to parse DT for regulator %pOFn\n",
|
||||||
|
child);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
*node = child;
|
||||||
|
|
||||||
return init_data;
|
return init_data;
|
||||||
|
|
||||||
|
error:
|
||||||
|
of_node_put(child);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int of_node_match(struct device *dev, const void *data)
|
static int of_node_match(struct device *dev, const void *data)
|
||||||
|
|
|
@ -443,13 +443,16 @@ static int palmas_ldo_write(struct palmas *palmas, unsigned int reg,
|
||||||
static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
|
static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
|
||||||
{
|
{
|
||||||
int id = rdev_get_id(dev);
|
int id = rdev_get_id(dev);
|
||||||
|
int ret;
|
||||||
struct palmas_pmic *pmic = rdev_get_drvdata(dev);
|
struct palmas_pmic *pmic = rdev_get_drvdata(dev);
|
||||||
struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata;
|
struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata;
|
||||||
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
|
struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id];
|
||||||
unsigned int reg;
|
unsigned int reg;
|
||||||
bool rail_enable = true;
|
bool rail_enable = true;
|
||||||
|
|
||||||
palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, ®);
|
ret = palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, ®);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
|
reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
|
||||||
|
|
||||||
|
|
|
@ -370,6 +370,7 @@ static struct pfuze_regulator pfuze100_regulators[] = {
|
||||||
PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
|
PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
|
||||||
PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
|
PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
|
||||||
PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
|
PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
|
||||||
|
PFUZE100_COIN_REG(PFUZE100, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin),
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pfuze_regulator pfuze200_regulators[] = {
|
static struct pfuze_regulator pfuze200_regulators[] = {
|
||||||
|
@ -436,6 +437,7 @@ static struct of_regulator_match pfuze100_matches[] = {
|
||||||
{ .name = "vgen4", },
|
{ .name = "vgen4", },
|
||||||
{ .name = "vgen5", },
|
{ .name = "vgen5", },
|
||||||
{ .name = "vgen6", },
|
{ .name = "vgen6", },
|
||||||
|
{ .name = "coin", },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* PFUZE200 */
|
/* PFUZE200 */
|
||||||
|
|
|
@ -410,7 +410,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
|
||||||
vreg->dev = dev;
|
vreg->dev = dev;
|
||||||
|
|
||||||
for (rpmh_data = pmic_rpmh_data; rpmh_data->name; rpmh_data++)
|
for (rpmh_data = pmic_rpmh_data; rpmh_data->name; rpmh_data++)
|
||||||
if (!strcmp(rpmh_data->name, node->name))
|
if (of_node_name_eq(node, rpmh_data->name))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!rpmh_data->name) {
|
if (!rpmh_data->name) {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include <linux/bug.h>
|
#include <linux/bug.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
@ -14,7 +14,6 @@
|
||||||
#include <linux/regulator/driver.h>
|
#include <linux/regulator/driver.h>
|
||||||
#include <linux/regulator/machine.h>
|
#include <linux/regulator/machine.h>
|
||||||
#include <linux/regulator/of_regulator.h>
|
#include <linux/regulator/of_regulator.h>
|
||||||
#include <linux/of_gpio.h>
|
|
||||||
#include <linux/mfd/samsung/core.h>
|
#include <linux/mfd/samsung/core.h>
|
||||||
#include <linux/mfd/samsung/s2mps11.h>
|
#include <linux/mfd/samsung/s2mps11.h>
|
||||||
#include <linux/mfd/samsung/s2mps13.h>
|
#include <linux/mfd/samsung/s2mps13.h>
|
||||||
|
@ -44,7 +43,7 @@ struct s2mps11_info {
|
||||||
* Array (size: number of regulators) with GPIO-s for external
|
* Array (size: number of regulators) with GPIO-s for external
|
||||||
* sleep control.
|
* sleep control.
|
||||||
*/
|
*/
|
||||||
int *ext_control_gpio;
|
struct gpio_desc **ext_control_gpiod;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int get_ramp_delay(int ramp_delay)
|
static int get_ramp_delay(int ramp_delay)
|
||||||
|
@ -511,7 +510,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev)
|
||||||
case S2MPS14X:
|
case S2MPS14X:
|
||||||
if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
|
if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state))
|
||||||
val = S2MPS14_ENABLE_SUSPEND;
|
val = S2MPS14_ENABLE_SUSPEND;
|
||||||
else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)]))
|
else if (s2mps11->ext_control_gpiod[rdev_get_id(rdev)])
|
||||||
val = S2MPS14_ENABLE_EXT_CONTROL;
|
val = S2MPS14_ENABLE_EXT_CONTROL;
|
||||||
else
|
else
|
||||||
val = rdev->desc->enable_mask;
|
val = rdev->desc->enable_mask;
|
||||||
|
@ -805,7 +804,7 @@ static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11,
|
||||||
static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
|
static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
|
||||||
struct of_regulator_match *rdata, struct s2mps11_info *s2mps11)
|
struct of_regulator_match *rdata, struct s2mps11_info *s2mps11)
|
||||||
{
|
{
|
||||||
int *gpio = s2mps11->ext_control_gpio;
|
struct gpio_desc **gpio = s2mps11->ext_control_gpiod;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11,
|
unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11,
|
||||||
S2MPS14_LDO12 };
|
S2MPS14_LDO12 };
|
||||||
|
@ -816,11 +815,20 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
|
||||||
if (!rdata[reg].init_data || !rdata[reg].of_node)
|
if (!rdata[reg].init_data || !rdata[reg].of_node)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
gpio[reg] = of_get_named_gpio(rdata[reg].of_node,
|
gpio[reg] = devm_gpiod_get_from_of_node(&pdev->dev,
|
||||||
"samsung,ext-control-gpios", 0);
|
rdata[reg].of_node,
|
||||||
if (gpio_is_valid(gpio[reg]))
|
"samsung,ext-control-gpios",
|
||||||
dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n",
|
0,
|
||||||
gpio[reg], reg, rdata[reg].name);
|
GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
|
||||||
|
"s2mps11-regulator");
|
||||||
|
if (IS_ERR(gpio[reg])) {
|
||||||
|
dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n",
|
||||||
|
reg, rdata[reg].name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (gpio[reg])
|
||||||
|
dev_dbg(&pdev->dev, "Using GPIO for ext-control over %d/%s\n",
|
||||||
|
reg, rdata[reg].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1126,17 +1134,10 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s2mps11->ext_control_gpio = devm_kmalloc_array(&pdev->dev,
|
s2mps11->ext_control_gpiod = devm_kcalloc(&pdev->dev, rdev_num,
|
||||||
rdev_num, sizeof(*s2mps11->ext_control_gpio),
|
sizeof(*s2mps11->ext_control_gpiod), GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
if (!s2mps11->ext_control_gpiod)
|
||||||
if (!s2mps11->ext_control_gpio)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
/*
|
|
||||||
* 0 is a valid GPIO so initialize all GPIO-s to negative value
|
|
||||||
* to indicate that external control won't be used for this regulator.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < rdev_num; i++)
|
|
||||||
s2mps11->ext_control_gpio[i] = -EINVAL;
|
|
||||||
|
|
||||||
if (!iodev->dev->of_node) {
|
if (!iodev->dev->of_node) {
|
||||||
if (iodev->pdata) {
|
if (iodev->pdata) {
|
||||||
|
@ -1166,8 +1167,6 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
|
||||||
config.dev = &pdev->dev;
|
config.dev = &pdev->dev;
|
||||||
config.regmap = iodev->regmap_pmic;
|
config.regmap = iodev->regmap_pmic;
|
||||||
config.driver_data = s2mps11;
|
config.driver_data = s2mps11;
|
||||||
config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
|
|
||||||
config.ena_gpio_initialized = true;
|
|
||||||
for (i = 0; i < rdev_num; i++) {
|
for (i = 0; i < rdev_num; i++) {
|
||||||
struct regulator_dev *regulator;
|
struct regulator_dev *regulator;
|
||||||
|
|
||||||
|
@ -1178,8 +1177,13 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
|
||||||
config.init_data = rdata[i].init_data;
|
config.init_data = rdata[i].init_data;
|
||||||
config.of_node = rdata[i].of_node;
|
config.of_node = rdata[i].of_node;
|
||||||
}
|
}
|
||||||
config.ena_gpio = s2mps11->ext_control_gpio[i];
|
config.ena_gpiod = s2mps11->ext_control_gpiod[i];
|
||||||
|
/*
|
||||||
|
* Hand the GPIO descriptor management over to the regulator
|
||||||
|
* core, remove it from devres management.
|
||||||
|
*/
|
||||||
|
if (config.ena_gpiod)
|
||||||
|
devm_gpiod_unhinge(&pdev->dev, config.ena_gpiod);
|
||||||
regulator = devm_regulator_register(&pdev->dev,
|
regulator = devm_regulator_register(&pdev->dev,
|
||||||
®ulators[i], &config);
|
®ulators[i], &config);
|
||||||
if (IS_ERR(regulator)) {
|
if (IS_ERR(regulator)) {
|
||||||
|
@ -1189,7 +1193,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_is_valid(s2mps11->ext_control_gpio[i])) {
|
if (s2mps11->ext_control_gpiod[i]) {
|
||||||
ret = s2mps14_pmic_enable_ext_control(s2mps11,
|
ret = s2mps14_pmic_enable_ext_control(s2mps11,
|
||||||
regulator);
|
regulator);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
|
@ -561,7 +561,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
|
||||||
pdata->opmode = rmode;
|
pdata->opmode = rmode;
|
||||||
for_each_child_of_node(regulators_np, reg_np) {
|
for_each_child_of_node(regulators_np, reg_np) {
|
||||||
for (i = 0; i < ARRAY_SIZE(regulators); i++)
|
for (i = 0; i < ARRAY_SIZE(regulators); i++)
|
||||||
if (!of_node_cmp(reg_np->name, regulators[i].name))
|
if (of_node_name_eq(reg_np, regulators[i].name))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == ARRAY_SIZE(regulators)) {
|
if (i == ARRAY_SIZE(regulators)) {
|
||||||
|
@ -956,10 +956,17 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
|
||||||
config.regmap = iodev->regmap_pmic;
|
config.regmap = iodev->regmap_pmic;
|
||||||
config.of_node = pdata->regulators[i].reg_node;
|
config.of_node = pdata->regulators[i].reg_node;
|
||||||
config.ena_gpiod = NULL;
|
config.ena_gpiod = NULL;
|
||||||
if (pdata->regulators[i].ext_control_gpiod)
|
if (pdata->regulators[i].ext_control_gpiod) {
|
||||||
|
/* Assigns config.ena_gpiod */
|
||||||
s5m8767_regulator_config_ext_control(s5m8767,
|
s5m8767_regulator_config_ext_control(s5m8767,
|
||||||
&pdata->regulators[i], &config);
|
&pdata->regulators[i], &config);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hand the GPIO descriptor management over to the
|
||||||
|
* regulator core, remove it from devres management.
|
||||||
|
*/
|
||||||
|
devm_gpiod_unhinge(s5m8767->dev, config.ena_gpiod);
|
||||||
|
}
|
||||||
rdev = devm_regulator_register(&pdev->dev, ®ulators[id],
|
rdev = devm_regulator_register(&pdev->dev, ®ulators[id],
|
||||||
&config);
|
&config);
|
||||||
if (IS_ERR(rdev)) {
|
if (IS_ERR(rdev)) {
|
||||||
|
|
|
@ -489,14 +489,14 @@ static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct regulator_dev *rdev = (struct regulator_dev *)data;
|
struct regulator_dev *rdev = (struct regulator_dev *)data;
|
||||||
|
|
||||||
mutex_lock(&rdev->mutex);
|
regulator_lock(rdev);
|
||||||
|
|
||||||
/* Send an overcurrent notification */
|
/* Send an overcurrent notification */
|
||||||
regulator_notifier_call_chain(rdev,
|
regulator_notifier_call_chain(rdev,
|
||||||
REGULATOR_EVENT_OVER_CURRENT,
|
REGULATOR_EVENT_OVER_CURRENT,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
mutex_unlock(&rdev->mutex);
|
regulator_unlock(rdev);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -480,6 +480,12 @@ static int tps65090_regulator_probe(struct platform_device *pdev)
|
||||||
else
|
else
|
||||||
config.of_node = NULL;
|
config.of_node = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hand the GPIO descriptor management over to the regulator
|
||||||
|
* core, remove it from devres management.
|
||||||
|
*/
|
||||||
|
if (config.ena_gpiod)
|
||||||
|
devm_gpiod_unhinge(&pdev->dev, config.ena_gpiod);
|
||||||
rdev = devm_regulator_register(&pdev->dev, ri->desc, &config);
|
rdev = devm_regulator_register(&pdev->dev, ri->desc, &config);
|
||||||
if (IS_ERR(rdev)) {
|
if (IS_ERR(rdev)) {
|
||||||
dev_err(&pdev->dev, "failed to register regulator %s\n",
|
dev_err(&pdev->dev, "failed to register regulator %s\n",
|
||||||
|
|
|
@ -1102,8 +1102,10 @@ static int tps65910_probe(struct platform_device *pdev)
|
||||||
platform_set_drvdata(pdev, pmic);
|
platform_set_drvdata(pdev, pmic);
|
||||||
|
|
||||||
/* Give control of all register to control port */
|
/* Give control of all register to control port */
|
||||||
tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL,
|
err = tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL,
|
||||||
DEVCTRL_SR_CTL_I2C_SEL_MASK);
|
DEVCTRL_SR_CTL_I2C_SEL_MASK);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
switch (tps65910_chip_id(tps65910)) {
|
switch (tps65910_chip_id(tps65910)) {
|
||||||
case TPS65910:
|
case TPS65910:
|
||||||
|
|
|
@ -1153,7 +1153,7 @@ static irqreturn_t pmic_uv_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct regulator_dev *rdev = (struct regulator_dev *)data;
|
struct regulator_dev *rdev = (struct regulator_dev *)data;
|
||||||
|
|
||||||
mutex_lock(&rdev->mutex);
|
regulator_lock(rdev);
|
||||||
if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
|
if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
|
||||||
regulator_notifier_call_chain(rdev,
|
regulator_notifier_call_chain(rdev,
|
||||||
REGULATOR_EVENT_REGULATION_OUT,
|
REGULATOR_EVENT_REGULATION_OUT,
|
||||||
|
@ -1162,7 +1162,7 @@ static irqreturn_t pmic_uv_handler(int irq, void *data)
|
||||||
regulator_notifier_call_chain(rdev,
|
regulator_notifier_call_chain(rdev,
|
||||||
REGULATOR_EVENT_UNDER_VOLTAGE,
|
REGULATOR_EVENT_UNDER_VOLTAGE,
|
||||||
NULL);
|
NULL);
|
||||||
mutex_unlock(&rdev->mutex);
|
regulator_unlock(rdev);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/driver.h>
|
#include <linux/regulator/driver.h>
|
||||||
#include <linux/regulator/machine.h>
|
#include <linux/regulator/machine.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include <linux/mfd/wm8994/core.h>
|
#include <linux/mfd/wm8994/core.h>
|
||||||
|
@ -129,6 +129,7 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
|
||||||
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
|
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
|
||||||
struct regulator_config config = { };
|
struct regulator_config config = { };
|
||||||
struct wm8994_ldo *ldo;
|
struct wm8994_ldo *ldo;
|
||||||
|
struct gpio_desc *gpiod;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
|
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
|
||||||
|
@ -145,12 +146,18 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
|
||||||
config.driver_data = ldo;
|
config.driver_data = ldo;
|
||||||
config.regmap = wm8994->regmap;
|
config.regmap = wm8994->regmap;
|
||||||
config.init_data = &ldo->init_data;
|
config.init_data = &ldo->init_data;
|
||||||
if (pdata) {
|
|
||||||
config.ena_gpio = pdata->ldo[id].enable;
|
/*
|
||||||
} else if (wm8994->dev->of_node) {
|
* Look up LDO enable GPIO from the parent device node, we don't
|
||||||
config.ena_gpio = wm8994->pdata.ldo[id].enable;
|
* use devm because the regulator core will free the GPIO
|
||||||
config.ena_gpio_initialized = true;
|
*/
|
||||||
}
|
gpiod = gpiod_get_optional(pdev->dev.parent,
|
||||||
|
id ? "wlf,ldo2ena" : "wlf,ldo1ena",
|
||||||
|
GPIOD_OUT_LOW |
|
||||||
|
GPIOD_FLAGS_BIT_NONEXCLUSIVE);
|
||||||
|
if (IS_ERR(gpiod))
|
||||||
|
return PTR_ERR(gpiod);
|
||||||
|
config.ena_gpiod = gpiod;
|
||||||
|
|
||||||
/* Use default constraints if none set up */
|
/* Use default constraints if none set up */
|
||||||
if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) {
|
if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) {
|
||||||
|
@ -159,12 +166,17 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ldo->init_data = wm8994_ldo_default[id];
|
ldo->init_data = wm8994_ldo_default[id];
|
||||||
ldo->init_data.consumer_supplies = &ldo->supply;
|
ldo->init_data.consumer_supplies = &ldo->supply;
|
||||||
if (!config.ena_gpio)
|
if (!gpiod)
|
||||||
ldo->init_data.constraints.valid_ops_mask = 0;
|
ldo->init_data.constraints.valid_ops_mask = 0;
|
||||||
} else {
|
} else {
|
||||||
ldo->init_data = *pdata->ldo[id].init_data;
|
ldo->init_data = *pdata->ldo[id].init_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At this point the GPIO descriptor is handled over to the
|
||||||
|
* regulator core and we need not worry about it on the
|
||||||
|
* error path.
|
||||||
|
*/
|
||||||
ldo->regulator = devm_regulator_register(&pdev->dev,
|
ldo->regulator = devm_regulator_register(&pdev->dev,
|
||||||
&wm8994_ldo_desc[id],
|
&wm8994_ldo_desc[id],
|
||||||
&config);
|
&config);
|
||||||
|
@ -172,15 +184,12 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
|
||||||
ret = PTR_ERR(ldo->regulator);
|
ret = PTR_ERR(ldo->regulator);
|
||||||
dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
|
dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
|
||||||
id + 1, ret);
|
id + 1, ret);
|
||||||
goto err;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, ldo);
|
platform_set_drvdata(pdev, ldo);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver wm8994_ldo_driver = {
|
static struct platform_driver wm8994_ldo_driver = {
|
||||||
|
|
|
@ -90,6 +90,9 @@
|
||||||
#define PIO_DATAOUT_1B 0x0020
|
#define PIO_DATAOUT_1B 0x0020
|
||||||
#define PIO_DATAOUT_4B 0x0024
|
#define PIO_DATAOUT_4B 0x0024
|
||||||
|
|
||||||
|
#define RD_FIFO_CFG 0x0028
|
||||||
|
#define CONTINUOUS_MODE BIT(0)
|
||||||
|
|
||||||
#define RD_FIFO_STATUS 0x002c
|
#define RD_FIFO_STATUS 0x002c
|
||||||
#define FIFO_EMPTY BIT(11)
|
#define FIFO_EMPTY BIT(11)
|
||||||
#define WR_CNTS_MSK 0x7f0
|
#define WR_CNTS_MSK 0x7f0
|
||||||
|
@ -99,9 +102,6 @@
|
||||||
#define RDY_16BYTE BIT(1)
|
#define RDY_16BYTE BIT(1)
|
||||||
#define FIFO_RDY BIT(0)
|
#define FIFO_RDY BIT(0)
|
||||||
|
|
||||||
#define RD_FIFO_CFG 0x0028
|
|
||||||
#define CONTINUOUS_MODE BIT(0)
|
|
||||||
|
|
||||||
#define RD_FIFO_RESET 0x0030
|
#define RD_FIFO_RESET 0x0030
|
||||||
#define RESET_FIFO BIT(0)
|
#define RESET_FIFO BIT(0)
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ struct qcom_qspi {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct clk_bulk_data clks[QSPI_NUM_CLKS];
|
struct clk_bulk_data clks[QSPI_NUM_CLKS];
|
||||||
struct qspi_xfer xfer;
|
struct qspi_xfer xfer;
|
||||||
/* Lock to protect data accessed by IRQs */
|
/* Lock to protect xfer and IRQ accessed registers */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Microchip Technology, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Device Tree binding constants for the ACT8945A PMIC regulators
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DT_BINDINGS_REGULATOR_ACT8945A_H
|
||||||
|
#define _DT_BINDINGS_REGULATOR_ACT8945A_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These constants should be used to specify regulator modes in device tree for
|
||||||
|
* ACT8945A regulators as follows:
|
||||||
|
* ACT8945A_REGULATOR_MODE_FIXED: It is specific to DCDC regulators and it
|
||||||
|
* specifies the usage of fixed-frequency
|
||||||
|
* PWM.
|
||||||
|
*
|
||||||
|
* ACT8945A_REGULATOR_MODE_NORMAL: It is specific to LDO regulators and it
|
||||||
|
* specifies the usage of normal mode.
|
||||||
|
*
|
||||||
|
* ACT8945A_REGULATOR_MODE_LOWPOWER: For DCDC and LDO regulators; it specify
|
||||||
|
* the usage of proprietary power-saving
|
||||||
|
* mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ACT8945A_REGULATOR_MODE_FIXED 1
|
||||||
|
#define ACT8945A_REGULATOR_MODE_NORMAL 2
|
||||||
|
#define ACT8945A_REGULATOR_MODE_LOWPOWER 3
|
||||||
|
|
||||||
|
#endif
|
|
@ -104,6 +104,7 @@ struct gpio_descs *__must_check
|
||||||
devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
|
devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
|
||||||
enum gpiod_flags flags);
|
enum gpiod_flags flags);
|
||||||
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
|
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
|
||||||
|
void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc);
|
||||||
void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);
|
void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);
|
||||||
|
|
||||||
int gpiod_get_direction(struct gpio_desc *desc);
|
int gpiod_get_direction(struct gpio_desc *desc);
|
||||||
|
@ -172,6 +173,10 @@ int desc_to_gpio(const struct gpio_desc *desc);
|
||||||
struct device_node;
|
struct device_node;
|
||||||
struct fwnode_handle;
|
struct fwnode_handle;
|
||||||
|
|
||||||
|
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
||||||
|
const char *propname, int index,
|
||||||
|
enum gpiod_flags dflags,
|
||||||
|
const char *label);
|
||||||
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
||||||
struct device_node *node,
|
struct device_node *node,
|
||||||
const char *propname, int index,
|
const char *propname, int index,
|
||||||
|
@ -245,6 +250,15 @@ static inline void gpiod_put(struct gpio_desc *desc)
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void devm_gpiod_unhinge(struct device *dev,
|
||||||
|
struct gpio_desc *desc)
|
||||||
|
{
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
|
/* GPIO can never have been requested */
|
||||||
|
WARN_ON(1);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void gpiod_put_array(struct gpio_descs *descs)
|
static inline void gpiod_put_array(struct gpio_descs *descs)
|
||||||
{
|
{
|
||||||
might_sleep();
|
might_sleep();
|
||||||
|
@ -517,6 +531,15 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
|
||||||
struct device_node;
|
struct device_node;
|
||||||
struct fwnode_handle;
|
struct fwnode_handle;
|
||||||
|
|
||||||
|
static inline
|
||||||
|
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
||||||
|
const char *propname, int index,
|
||||||
|
enum gpiod_flags dflags,
|
||||||
|
const char *label)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
|
||||||
struct device_node *node,
|
struct device_node *node,
|
||||||
|
|
|
@ -35,7 +35,7 @@ enum axp20x_variants {
|
||||||
#define AXP152_ALDO_OP_MODE 0x13
|
#define AXP152_ALDO_OP_MODE 0x13
|
||||||
#define AXP152_LDO0_CTRL 0x15
|
#define AXP152_LDO0_CTRL 0x15
|
||||||
#define AXP152_DCDC2_V_OUT 0x23
|
#define AXP152_DCDC2_V_OUT 0x23
|
||||||
#define AXP152_DCDC2_V_SCAL 0x25
|
#define AXP152_DCDC2_V_RAMP 0x25
|
||||||
#define AXP152_DCDC1_V_OUT 0x26
|
#define AXP152_DCDC1_V_OUT 0x26
|
||||||
#define AXP152_DCDC3_V_OUT 0x27
|
#define AXP152_DCDC3_V_OUT 0x27
|
||||||
#define AXP152_ALDO12_V_OUT 0x28
|
#define AXP152_ALDO12_V_OUT 0x28
|
||||||
|
@ -53,7 +53,7 @@ enum axp20x_variants {
|
||||||
#define AXP20X_USB_OTG_STATUS 0x02
|
#define AXP20X_USB_OTG_STATUS 0x02
|
||||||
#define AXP20X_PWR_OUT_CTRL 0x12
|
#define AXP20X_PWR_OUT_CTRL 0x12
|
||||||
#define AXP20X_DCDC2_V_OUT 0x23
|
#define AXP20X_DCDC2_V_OUT 0x23
|
||||||
#define AXP20X_DCDC2_LDO3_V_SCAL 0x25
|
#define AXP20X_DCDC2_LDO3_V_RAMP 0x25
|
||||||
#define AXP20X_DCDC3_V_OUT 0x27
|
#define AXP20X_DCDC3_V_OUT 0x27
|
||||||
#define AXP20X_LDO24_V_OUT 0x28
|
#define AXP20X_LDO24_V_OUT 0x28
|
||||||
#define AXP20X_LDO3_V_OUT 0x29
|
#define AXP20X_LDO3_V_OUT 0x29
|
||||||
|
|
|
@ -20,9 +20,6 @@
|
||||||
#define WM8994_NUM_AIF 3
|
#define WM8994_NUM_AIF 3
|
||||||
|
|
||||||
struct wm8994_ldo_pdata {
|
struct wm8994_ldo_pdata {
|
||||||
/** GPIOs to enable regulator, 0 or less if not available */
|
|
||||||
int enable;
|
|
||||||
|
|
||||||
const struct regulator_init_data *init_data;
|
const struct regulator_init_data *init_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -508,7 +508,7 @@ static inline int regulator_get_error_flags(struct regulator *regulator,
|
||||||
|
|
||||||
static inline int regulator_set_load(struct regulator *regulator, int load_uA)
|
static inline int regulator_set_load(struct regulator *regulator, int load_uA)
|
||||||
{
|
{
|
||||||
return REGULATOR_MODE_NORMAL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int regulator_allow_bypass(struct regulator *regulator,
|
static inline int regulator_allow_bypass(struct regulator *regulator,
|
||||||
|
|
|
@ -15,11 +15,12 @@
|
||||||
#ifndef __LINUX_REGULATOR_DRIVER_H_
|
#ifndef __LINUX_REGULATOR_DRIVER_H_
|
||||||
#define __LINUX_REGULATOR_DRIVER_H_
|
#define __LINUX_REGULATOR_DRIVER_H_
|
||||||
|
|
||||||
#define MAX_COUPLED 4
|
#define MAX_COUPLED 2
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/ww_mutex.h>
|
||||||
|
|
||||||
struct gpio_desc;
|
struct gpio_desc;
|
||||||
struct regmap;
|
struct regmap;
|
||||||
|
@ -462,7 +463,7 @@ struct regulator_dev {
|
||||||
struct coupling_desc coupling_desc;
|
struct coupling_desc coupling_desc;
|
||||||
|
|
||||||
struct blocking_notifier_head notifier;
|
struct blocking_notifier_head notifier;
|
||||||
struct mutex mutex; /* consumer lock */
|
struct ww_mutex mutex; /* consumer lock */
|
||||||
struct task_struct *mutex_owner;
|
struct task_struct *mutex_owner;
|
||||||
int ref_cnt;
|
int ref_cnt;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
@ -473,7 +474,6 @@ struct regulator_dev {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
|
|
||||||
struct delayed_work disable_work;
|
struct delayed_work disable_work;
|
||||||
int deferred_disables;
|
|
||||||
|
|
||||||
void *reg_data; /* regulator_dev data */
|
void *reg_data; /* regulator_dev data */
|
||||||
|
|
||||||
|
@ -545,4 +545,7 @@ int regulator_set_active_discharge_regmap(struct regulator_dev *rdev,
|
||||||
bool enable);
|
bool enable);
|
||||||
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
|
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
|
||||||
|
|
||||||
|
void regulator_lock(struct regulator_dev *rdev);
|
||||||
|
void regulator_unlock(struct regulator_dev *rdev);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -158,6 +158,9 @@ struct regulation_constraints {
|
||||||
/* used for coupled regulators */
|
/* used for coupled regulators */
|
||||||
int max_spread;
|
int max_spread;
|
||||||
|
|
||||||
|
/* used for changing voltage in steps */
|
||||||
|
int max_uV_step;
|
||||||
|
|
||||||
/* valid regulator operating modes for this machine */
|
/* valid regulator operating modes for this machine */
|
||||||
unsigned int valid_modes_mask;
|
unsigned int valid_modes_mask;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,8 @@
|
||||||
#define PFUZE100_VGEN4 12
|
#define PFUZE100_VGEN4 12
|
||||||
#define PFUZE100_VGEN5 13
|
#define PFUZE100_VGEN5 13
|
||||||
#define PFUZE100_VGEN6 14
|
#define PFUZE100_VGEN6 14
|
||||||
#define PFUZE100_MAX_REGULATOR 15
|
#define PFUZE100_COIN 15
|
||||||
|
#define PFUZE100_MAX_REGULATOR 16
|
||||||
|
|
||||||
#define PFUZE200_SW1AB 0
|
#define PFUZE200_SW1AB 0
|
||||||
#define PFUZE200_SW2 1
|
#define PFUZE200_SW2 1
|
||||||
|
|
Loading…
Reference in New Issue