mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 00:21:59 +00:00
regulator: Updates for v4.7
A few core enhancements to deal with some of the slightly more complicated edge cases that have started cropping up in systems, both new ones and old ones that people started worrying about upstream, but otherwise a quiet release for the regulator API: - When applying constraints at system image if we have a voltage range specified and the regulator is currently configured outside the bounds of that range bring the regulator to the nearest end of the range. - When regulators are in non-regulating bypass modes make sure that we always use the voltage from the parent regulator. - Support for LP873x, PV88080, PM8894 and FAN53555 chips. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJXObxVAAoJECTWi3JdVIfQzWkH/jg4ZysKMMdT6yUHxwIjaKGd //dIzTMGZ4N8zFFURuDGf7J+a20w/2xi7MVflELVV8pkRarRi0yV2G2hmGY9pjI3 2RIFtl14Gq5fXMnwF53+GrKdhyS4cu+B9woQVFRaOPnw0kesPacoA7P8Hh+V2+8X J23US9X1dh/Xl8b/tdu3EAYAc/OujYl0nY6uRjijohW80uxHTBb06ky7kbPEuJsc P/3Wa6lEGOJLIQsvyPiJKtH1a5Hoe7HMvHs8sloPc9Hmw+KE1mlWBQqmAV14bvDb YYiXSaZ+lw/bIL3AxIDQLOi07bNTBbE5afVtJjHYyWSaOxclwx6woiMJ/cmibug= =Uhx5 -----END PGP SIGNATURE----- Merge tag 'regulator-v4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator Pull regulator updates from Mark Brown: "A few core enhancements to deal with some of the slightly more complicated edge cases that have started cropping up in systems, both new ones and old ones that people started worrying about upstream, but otherwise a quiet release for the regulator API: - When applying constraints at system image if we have a voltage range specified and the regulator is currently configured outside the bounds of that range bring the regulator to the nearest end of the range. - When regulators are in non-regulating bypass modes make sure that we always use the voltage from the parent regulator. - Support for LP873x, PV88080, PM8894 and FAN53555 chips" * tag 'regulator-v4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (71 commits) regulator: rk808: Migrate to regulator core's simplified DT parsing code regulator: lp873x: Add support for lp873x PMIC regulators regulator: tps65917/palmas: Simplify multiple dereference of match->of_node regulator: tps65917/palmas: Handle possible memory allocation failure regulator: tps65917/palmas: Simplify multiple dereference of pdata->reg_init[idx] regulator: tps65917/palmas: Simplify multiple dereference of ddata->palmas_matches[idx] regulator: pwm: Use pwm_get_args() where appropriate pwm: Introduce the pwm_args concept regulator: max77686: Configure enable time to properly handle regulator enable regulator: rk808: Add rk808_reg_ops_ranges for LDO3 regulator: core: Add early supply resolution for regulators regulator: axp20x: Fix axp22x ldo_io voltage ranges regulator: tps65917/palmas: Add bypass "On" value regulator: rk808: remove unused rk808_reg_ops_ranges regulator: refactor valid_ops_mask checking code regulator: rk808: remove linear range definitions with a single range regulator: max77620: Add support for device specific ramp rate setting regulator: max77620: Add details of device specific ramp rate setting regulator: helpers: Ensure bypass register field matches ON value regulator: core: Move registration of regulator device ...
This commit is contained in:
commit
d9dce51c9b
@ -32,6 +32,13 @@ Optional properties:
|
||||
|
||||
Enhanced transient response (ETR) will affect the configuration of CKADV.
|
||||
|
||||
-junction-warn-millicelsius: u32, junction warning temperature threshold
|
||||
in millicelsius. If die temperature crosses this level then
|
||||
device generates the warning interrupts.
|
||||
|
||||
Please note that thermal functionality is only supported on MAX77621. The
|
||||
supported threshold warning temperature for MAX77621 are 120 degC and 140 degC.
|
||||
|
||||
Example:
|
||||
|
||||
max8973@1b {
|
||||
|
49
Documentation/devicetree/bindings/regulator/pv88080.txt
Normal file
49
Documentation/devicetree/bindings/regulator/pv88080.txt
Normal file
@ -0,0 +1,49 @@
|
||||
* Powerventure Semiconductor PV88080 Voltage Regulator
|
||||
|
||||
Required properties:
|
||||
- compatible: "pvs,pv88080".
|
||||
- reg: I2C slave address, usually 0x49.
|
||||
- interrupts: the interrupt outputs of the controller
|
||||
- regulators: A node that houses a sub-node for each regulator within the
|
||||
device. Each sub-node is identified using the node's name, with valid
|
||||
values listed below. The content of each sub-node is defined by the
|
||||
standard binding for regulators; see regulator.txt.
|
||||
BUCK1, BUCK2, and BUCK3.
|
||||
|
||||
Optional properties:
|
||||
- Any optional property defined in regulator.txt
|
||||
|
||||
Example
|
||||
|
||||
pmic: pv88080@49 {
|
||||
compatible = "pvs,pv88080";
|
||||
reg = <0x49>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <24 24>;
|
||||
|
||||
regulators {
|
||||
BUCK1 {
|
||||
regulator-name = "buck1";
|
||||
regulator-min-microvolt = < 600000>;
|
||||
regulator-max-microvolt = <1393750>;
|
||||
regulator-min-microamp = < 220000>;
|
||||
regulator-max-microamp = <7040000>;
|
||||
};
|
||||
|
||||
BUCK2 {
|
||||
regulator-name = "buck2";
|
||||
regulator-min-microvolt = < 600000>;
|
||||
regulator-max-microvolt = <1393750>;
|
||||
regulator-min-microamp = <1496000>;
|
||||
regulator-max-microamp = <4189000>;
|
||||
};
|
||||
|
||||
BUCK3 {
|
||||
regulator-name = "buck3";
|
||||
regulator-min-microvolt = <1400000>;
|
||||
regulator-max-microvolt = <2193750>;
|
||||
regulator-min-microamp = <1496000>;
|
||||
regulator-max-microamp = <4189000>;
|
||||
};
|
||||
};
|
||||
};
|
@ -7,6 +7,7 @@ Qualcomm SPMI Regulators
|
||||
"qcom,pm8841-regulators"
|
||||
"qcom,pm8916-regulators"
|
||||
"qcom,pm8941-regulators"
|
||||
"qcom,pm8994-regulators"
|
||||
|
||||
- interrupts:
|
||||
Usage: optional
|
||||
@ -68,6 +69,37 @@ Qualcomm SPMI Regulators
|
||||
Definition: Reference to regulator supplying the input pin, as
|
||||
described in the data sheet.
|
||||
|
||||
- vdd_s1-supply:
|
||||
- vdd_s2-supply:
|
||||
- vdd_s3-supply:
|
||||
- vdd_s4-supply:
|
||||
- vdd_s5-supply:
|
||||
- vdd_s6-supply:
|
||||
- vdd_s7-supply:
|
||||
- vdd_s8-supply:
|
||||
- vdd_s9-supply:
|
||||
- vdd_s10-supply:
|
||||
- vdd_s11-supply:
|
||||
- vdd_s12-supply:
|
||||
- vdd_l1-supply:
|
||||
- vdd_l2_l26_l28-supply:
|
||||
- vdd_l3_l11-supply:
|
||||
- vdd_l4_l27_l31-supply:
|
||||
- vdd_l5_l7-supply:
|
||||
- vdd_l6_l12_l32-supply:
|
||||
- vdd_l8_l16_l30-supply:
|
||||
- vdd_l9_l10_l18_l22-supply:
|
||||
- vdd_l13_l19_l23_l24-supply:
|
||||
- vdd_l14_l15-supply:
|
||||
- vdd_l17_l29-supply:
|
||||
- vdd_l20_l21-supply:
|
||||
- vdd_l25-supply:
|
||||
- vdd_lvs_1_2-supply:
|
||||
Usage: optional (pm8994 only)
|
||||
Value type: <phandle>
|
||||
Definition: Reference to regulator supplying the input pin, as
|
||||
described in the data sheet.
|
||||
|
||||
|
||||
The regulator node houses sub-nodes for each regulator within the device. Each
|
||||
sub-node is identified using the node's name, with valid values listed for each
|
||||
@ -85,6 +117,11 @@ pm8941:
|
||||
l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3,
|
||||
mvs1, mvs2
|
||||
|
||||
pm8994:
|
||||
s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5,
|
||||
l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
|
||||
l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, lvs1, lvs2
|
||||
|
||||
The content of each sub-node is defined by the standard binding for regulators -
|
||||
see regulator.txt - with additional custom properties described below:
|
||||
|
||||
|
@ -94,6 +94,28 @@ Following are additional properties:
|
||||
This is applicable if suspend state
|
||||
FPS source is selected as FPS0, FPS1 or
|
||||
FPS2.
|
||||
- maxim,ramp-rate-setting: integer, ramp rate(uV/us) setting to be
|
||||
configured to the device.
|
||||
The platform may have different ramp
|
||||
rate than advertised ramp rate if it has
|
||||
design variation from Maxim's
|
||||
recommended. On this case, platform
|
||||
specific ramp rate is used for ramp time
|
||||
calculation and this property is used
|
||||
for device register configurations.
|
||||
The measured ramp rate of platform is
|
||||
provided by the regulator-ramp-delay
|
||||
as described in <devicetree/bindings/
|
||||
regulator/regulator.txt>.
|
||||
Maxim Max77620 supports following ramp
|
||||
delay:
|
||||
SD: 13.75mV/us, 27.5mV/us, 55mV/us
|
||||
LDOs: 5mV/us, 100mV/us
|
||||
|
||||
Note: If the measured ramp delay is same as advertised ramp delay then it is not
|
||||
required to provide the ramp delay with property "maxim,ramp-rate-setting". The
|
||||
ramp rate can be provided by the regulator-ramp-delay which will be used for
|
||||
ramp time calculation for voltage change as well as for device configuration.
|
||||
|
||||
Example:
|
||||
--------
|
||||
|
@ -14,8 +14,8 @@ Required Properties:
|
||||
- "setup-address" - contains setup register address of ABB module (ti,abb-v3)
|
||||
- "int-address" - contains address of interrupt register for ABB module
|
||||
(also see Optional properties)
|
||||
- #address-cell: should be 0
|
||||
- #size-cell: should be 0
|
||||
- #address-cells: should be 0
|
||||
- #size-cells: should be 0
|
||||
- clocks: should point to the clock node used by ABB module
|
||||
- ti,settling-time: Settling time in uSecs from SoC documentation for ABB module
|
||||
to settle down(target time for SR2_WTCNT_VALUE).
|
||||
@ -69,7 +69,7 @@ Example #1: Simplest configuration (no efuse data, hard coded ABB table):
|
||||
abb_x: regulator-abb-x {
|
||||
compatible = "ti,abb-v1";
|
||||
regulator-name = "abb_x";
|
||||
#address-cell = <0>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x483072f0 0x8>, <0x48306818 0x4>;
|
||||
reg-names = "base-address", "int-address";
|
||||
@ -89,7 +89,7 @@ Example #2: Efuse bits contain ABB mode setting (no LDO override capability)
|
||||
abb_y: regulator-abb-y {
|
||||
compatible = "ti,abb-v2";
|
||||
regulator-name = "abb_y";
|
||||
#address-cell = <0>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x4a307bd0 0x8>, <0x4a306014 0x4>, <0x4A002268 0x8>;
|
||||
reg-names = "base-address", "int-address", "efuse-address";
|
||||
@ -110,7 +110,7 @@ Example #3: Efuse bits contain ABB mode setting and LDO override capability
|
||||
abb_z: regulator-abb-z {
|
||||
compatible = "ti,abb-v2";
|
||||
regulator-name = "abb_z";
|
||||
#address-cell = <0>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x4ae07ce4 0x8>, <0x4ae06010 0x4>,
|
||||
<0x4a002194 0x8>, <0x4ae0C314 0x4>;
|
||||
|
@ -57,6 +57,12 @@ For twl4030 regulators/LDOs
|
||||
|
||||
Optional properties:
|
||||
- Any optional property defined in bindings/regulator/regulator.txt
|
||||
For twl4030 regulators/LDOs:
|
||||
- regulator-initial-mode:
|
||||
- 0x08 - Sleep mode, the nominal output voltage is maintained with low power
|
||||
consumption with low load current capability.
|
||||
- 0x0e - Active mode, the regulator can deliver its nominal output voltage
|
||||
with full-load current capability.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -7020,9 +7020,9 @@ M: Chanwoo Choi <cw00.choi@samsung.com>
|
||||
M: Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/*/max14577.c
|
||||
F: drivers/*/max14577*.c
|
||||
F: drivers/*/max77686*.c
|
||||
F: drivers/*/max77693.c
|
||||
F: drivers/*/max77693*.c
|
||||
F: drivers/extcon/extcon-max14577.c
|
||||
F: drivers/extcon/extcon-max77693.c
|
||||
F: drivers/rtc/rtc-max77686.c
|
||||
@ -12011,7 +12011,9 @@ L: linux-kernel@vger.kernel.org
|
||||
W: http://www.slimlogic.co.uk/?p=48
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/regulator/
|
||||
F: drivers/regulator/
|
||||
F: include/dt-bindings/regulator/
|
||||
F: include/linux/regulator/
|
||||
|
||||
VRF
|
||||
|
@ -128,6 +128,13 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
|
||||
set_bit(PWMF_REQUESTED, &pwm->flags);
|
||||
pwm->label = label;
|
||||
|
||||
/*
|
||||
* FIXME: This should be removed once all PWM users properly make use
|
||||
* of struct pwm_args to initialize the PWM device. As long as this is
|
||||
* here, the PWM state and hardware state can get out of sync.
|
||||
*/
|
||||
pwm_apply_args(pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -146,12 +153,12 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
pwm_set_period(pwm, args->args[1]);
|
||||
pwm->args.period = args->args[1];
|
||||
|
||||
if (args->args[2] & PWM_POLARITY_INVERTED)
|
||||
pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
|
||||
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
||||
else
|
||||
pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
|
||||
pwm->args.polarity = PWM_POLARITY_NORMAL;
|
||||
|
||||
return pwm;
|
||||
}
|
||||
@ -172,7 +179,7 @@ of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
pwm_set_period(pwm, args->args[1]);
|
||||
pwm->args.period = args->args[1];
|
||||
|
||||
return pwm;
|
||||
}
|
||||
@ -747,13 +754,13 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
|
||||
if (!chip)
|
||||
goto out;
|
||||
|
||||
pwm->args.period = chosen->period;
|
||||
pwm->args.polarity = chosen->polarity;
|
||||
|
||||
pwm = pwm_request_from_chip(chip, chosen->index, con_id ?: dev_id);
|
||||
if (IS_ERR(pwm))
|
||||
goto out;
|
||||
|
||||
pwm_set_period(pwm, chosen->period);
|
||||
pwm_set_polarity(pwm, chosen->polarity);
|
||||
|
||||
out:
|
||||
mutex_unlock(&pwm_lookup_lock);
|
||||
return pwm;
|
||||
|
@ -60,7 +60,7 @@ static int clps711x_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
return -EINVAL;
|
||||
|
||||
/* Store constant period value */
|
||||
pwm_set_period(pwm, DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq));
|
||||
pwm->args.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
|
||||
if (IS_ERR(pwm))
|
||||
return pwm;
|
||||
|
||||
pwm_set_period(pwm, args->args[0]);
|
||||
pwm->args.period = args->args[0];
|
||||
|
||||
return pwm;
|
||||
}
|
||||
|
@ -321,6 +321,15 @@ config REGULATOR_LP872X
|
||||
help
|
||||
This driver supports LP8720/LP8725 PMIC
|
||||
|
||||
config REGULATOR_LP873X
|
||||
tristate "TI LP873X Power regulators"
|
||||
depends on MFD_LP873X && OF
|
||||
help
|
||||
This driver supports LP873X voltage regulator chips. LP873X
|
||||
provides two step-down converters and two general-purpose LDO
|
||||
voltage regulators. It supports software based voltage control
|
||||
for different voltage domains
|
||||
|
||||
config REGULATOR_LP8755
|
||||
tristate "TI LP8755 High Performance PMU driver"
|
||||
depends on I2C
|
||||
@ -409,6 +418,7 @@ config REGULATOR_MAX8952
|
||||
config REGULATOR_MAX8973
|
||||
tristate "Maxim MAX8973 voltage regulator "
|
||||
depends on I2C
|
||||
depends on THERMAL && THERMAL_OF
|
||||
select REGMAP_I2C
|
||||
help
|
||||
The MAXIM MAX8973 high-efficiency. three phase, DC-DC step-down
|
||||
@ -548,6 +558,13 @@ config REGULATOR_PV88060
|
||||
Say y here to support the voltage regulators and convertors
|
||||
PV88060
|
||||
|
||||
config REGULATOR_PV88080
|
||||
tristate "Powerventure Semiconductor PV88080 regulator"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say y here to support the buck convertors on PV88080
|
||||
|
||||
config REGULATOR_PV88090
|
||||
tristate "Powerventure Semiconductor PV88090 regulator"
|
||||
depends on I2C
|
||||
|
@ -42,11 +42,12 @@ obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
|
||||
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
|
||||
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
|
||||
obj-$(CONFIG_REGULATOR_LP873X) += lp873x-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
|
||||
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
|
||||
obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
|
||||
obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
|
||||
obj-$(CONFIG_REGULATOR_MAX14577) += max14577.o
|
||||
obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
|
||||
obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
|
||||
@ -55,10 +56,10 @@ obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8997) += max8997-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
|
||||
obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
|
||||
obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
|
||||
@ -71,6 +72,7 @@ obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PV88080) += pv88080-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PV88090) += pv88090-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
|
||||
|
@ -139,6 +139,74 @@ struct act8865 {
|
||||
int off_mask;
|
||||
};
|
||||
|
||||
static const struct regmap_range act8600_reg_ranges[] = {
|
||||
regmap_reg_range(0x00, 0x01),
|
||||
regmap_reg_range(0x10, 0x10),
|
||||
regmap_reg_range(0x12, 0x12),
|
||||
regmap_reg_range(0x20, 0x20),
|
||||
regmap_reg_range(0x22, 0x22),
|
||||
regmap_reg_range(0x30, 0x30),
|
||||
regmap_reg_range(0x32, 0x32),
|
||||
regmap_reg_range(0x40, 0x41),
|
||||
regmap_reg_range(0x50, 0x51),
|
||||
regmap_reg_range(0x60, 0x61),
|
||||
regmap_reg_range(0x70, 0x71),
|
||||
regmap_reg_range(0x80, 0x81),
|
||||
regmap_reg_range(0x91, 0x91),
|
||||
regmap_reg_range(0xA1, 0xA1),
|
||||
regmap_reg_range(0xA8, 0xAA),
|
||||
regmap_reg_range(0xB0, 0xB0),
|
||||
regmap_reg_range(0xB2, 0xB2),
|
||||
regmap_reg_range(0xC1, 0xC1),
|
||||
};
|
||||
|
||||
static const struct regmap_range act8600_reg_ro_ranges[] = {
|
||||
regmap_reg_range(0xAA, 0xAA),
|
||||
regmap_reg_range(0xC1, 0xC1),
|
||||
};
|
||||
|
||||
static const struct regmap_range act8600_reg_volatile_ranges[] = {
|
||||
regmap_reg_range(0x00, 0x01),
|
||||
regmap_reg_range(0x12, 0x12),
|
||||
regmap_reg_range(0x22, 0x22),
|
||||
regmap_reg_range(0x32, 0x32),
|
||||
regmap_reg_range(0x41, 0x41),
|
||||
regmap_reg_range(0x51, 0x51),
|
||||
regmap_reg_range(0x61, 0x61),
|
||||
regmap_reg_range(0x71, 0x71),
|
||||
regmap_reg_range(0x81, 0x81),
|
||||
regmap_reg_range(0xA8, 0xA8),
|
||||
regmap_reg_range(0xAA, 0xAA),
|
||||
regmap_reg_range(0xB0, 0xB0),
|
||||
regmap_reg_range(0xC1, 0xC1),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table act8600_write_ranges_table = {
|
||||
.yes_ranges = act8600_reg_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(act8600_reg_ranges),
|
||||
.no_ranges = act8600_reg_ro_ranges,
|
||||
.n_no_ranges = ARRAY_SIZE(act8600_reg_ro_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table act8600_read_ranges_table = {
|
||||
.yes_ranges = act8600_reg_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(act8600_reg_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table act8600_volatile_ranges_table = {
|
||||
.yes_ranges = act8600_reg_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(act8600_reg_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config act8600_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0xFF,
|
||||
.wr_table = &act8600_write_ranges_table,
|
||||
.rd_table = &act8600_read_ranges_table,
|
||||
.volatile_table = &act8600_volatile_ranges_table,
|
||||
};
|
||||
|
||||
static const struct regmap_config act8865_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
@ -319,7 +387,6 @@ static struct of_regulator_match act8600_matches[] = {
|
||||
};
|
||||
|
||||
static int act8865_pdata_from_dt(struct device *dev,
|
||||
struct device_node **of_node,
|
||||
struct act8865_platform_data *pdata,
|
||||
unsigned long type)
|
||||
{
|
||||
@ -370,7 +437,7 @@ static int act8865_pdata_from_dt(struct device *dev,
|
||||
regulator->id = i;
|
||||
regulator->name = matches[i].name;
|
||||
regulator->init_data = matches[i].init_data;
|
||||
of_node[i] = matches[i].of_node;
|
||||
regulator->of_node = matches[i].of_node;
|
||||
regulator++;
|
||||
}
|
||||
|
||||
@ -378,7 +445,6 @@ static int act8865_pdata_from_dt(struct device *dev,
|
||||
}
|
||||
#else
|
||||
static inline int act8865_pdata_from_dt(struct device *dev,
|
||||
struct device_node **of_node,
|
||||
struct act8865_platform_data *pdata,
|
||||
unsigned long type)
|
||||
{
|
||||
@ -386,8 +452,8 @@ static inline int act8865_pdata_from_dt(struct device *dev,
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct regulator_init_data
|
||||
*act8865_get_init_data(int id, struct act8865_platform_data *pdata)
|
||||
static struct act8865_regulator_data *act8865_get_regulator_data(
|
||||
int id, struct act8865_platform_data *pdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -396,7 +462,7 @@ static struct regulator_init_data
|
||||
|
||||
for (i = 0; i < pdata->num_regulators; i++) {
|
||||
if (pdata->regulators[i].id == id)
|
||||
return pdata->regulators[i].init_data;
|
||||
return &pdata->regulators[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -418,9 +484,9 @@ static int act8865_pmic_probe(struct i2c_client *client,
|
||||
const struct regulator_desc *regulators;
|
||||
struct act8865_platform_data pdata_of, *pdata;
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node **of_node;
|
||||
int i, ret, num_regulators;
|
||||
struct act8865 *act8865;
|
||||
const struct regmap_config *regmap_config;
|
||||
unsigned long type;
|
||||
int off_reg, off_mask;
|
||||
int voltage_select = 0;
|
||||
@ -447,12 +513,14 @@ static int act8865_pmic_probe(struct i2c_client *client,
|
||||
case ACT8600:
|
||||
regulators = act8600_regulators;
|
||||
num_regulators = ARRAY_SIZE(act8600_regulators);
|
||||
regmap_config = &act8600_regmap_config;
|
||||
off_reg = -1;
|
||||
off_mask = -1;
|
||||
break;
|
||||
case ACT8846:
|
||||
regulators = act8846_regulators;
|
||||
num_regulators = ARRAY_SIZE(act8846_regulators);
|
||||
regmap_config = &act8865_regmap_config;
|
||||
off_reg = ACT8846_GLB_OFF_CTRL;
|
||||
off_mask = ACT8846_OFF_SYSMASK;
|
||||
break;
|
||||
@ -464,6 +532,7 @@ static int act8865_pmic_probe(struct i2c_client *client,
|
||||
regulators = act8865_regulators;
|
||||
num_regulators = ARRAY_SIZE(act8865_regulators);
|
||||
}
|
||||
regmap_config = &act8865_regmap_config;
|
||||
off_reg = ACT8865_SYS_CTRL;
|
||||
off_mask = ACT8865_MSTROFF;
|
||||
break;
|
||||
@ -472,34 +541,22 @@ static int act8865_pmic_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
of_node = devm_kzalloc(dev, sizeof(struct device_node *) *
|
||||
num_regulators, GFP_KERNEL);
|
||||
if (!of_node)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dev->of_node && !pdata) {
|
||||
ret = act8865_pdata_from_dt(dev, of_node, &pdata_of, type);
|
||||
ret = act8865_pdata_from_dt(dev, &pdata_of, type);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pdata = &pdata_of;
|
||||
}
|
||||
|
||||
if (pdata->num_regulators > num_regulators) {
|
||||
dev_err(dev, "too many regulators: %d\n",
|
||||
pdata->num_regulators);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
act8865 = devm_kzalloc(dev, sizeof(struct act8865), GFP_KERNEL);
|
||||
if (!act8865)
|
||||
return -ENOMEM;
|
||||
|
||||
act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config);
|
||||
act8865->regmap = devm_regmap_init_i2c(client, regmap_config);
|
||||
if (IS_ERR(act8865->regmap)) {
|
||||
ret = PTR_ERR(act8865->regmap);
|
||||
dev_err(&client->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
dev_err(dev, "Failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -518,15 +575,20 @@ static int act8865_pmic_probe(struct i2c_client *client,
|
||||
for (i = 0; i < num_regulators; i++) {
|
||||
const struct regulator_desc *desc = ®ulators[i];
|
||||
struct regulator_config config = { };
|
||||
struct act8865_regulator_data *rdata;
|
||||
struct regulator_dev *rdev;
|
||||
|
||||
config.dev = dev;
|
||||
config.init_data = act8865_get_init_data(desc->id, pdata);
|
||||
config.of_node = of_node[i];
|
||||
config.driver_data = act8865;
|
||||
config.regmap = act8865->regmap;
|
||||
|
||||
rdev = devm_regulator_register(&client->dev, desc, &config);
|
||||
rdata = act8865_get_regulator_data(desc->id, pdata);
|
||||
if (rdata) {
|
||||
config.init_data = rdata->init_data;
|
||||
config.of_node = rdata->of_node;
|
||||
}
|
||||
|
||||
rdev = devm_regulator_register(dev, desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(dev, "failed to register %s\n", desc->name);
|
||||
return PTR_ERR(rdev);
|
||||
@ -534,7 +596,6 @@ static int act8865_pmic_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, act8865);
|
||||
devm_kfree(dev, of_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -372,7 +372,7 @@ static int as3722_ldo_set_current_limit(struct regulator_dev *rdev,
|
||||
AS3722_LDO_ILIMIT_MASK, reg);
|
||||
}
|
||||
|
||||
static struct regulator_ops as3722_ldo0_ops = {
|
||||
static const struct regulator_ops as3722_ldo0_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
@ -383,7 +383,7 @@ static struct regulator_ops as3722_ldo0_ops = {
|
||||
.set_current_limit = as3722_ldo_set_current_limit,
|
||||
};
|
||||
|
||||
static struct regulator_ops as3722_ldo0_extcntrl_ops = {
|
||||
static const struct regulator_ops as3722_ldo0_extcntrl_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
@ -415,7 +415,7 @@ static int as3722_ldo3_get_current_limit(struct regulator_dev *rdev)
|
||||
return 150000;
|
||||
}
|
||||
|
||||
static struct regulator_ops as3722_ldo3_ops = {
|
||||
static const struct regulator_ops as3722_ldo3_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
@ -425,20 +425,45 @@ static struct regulator_ops as3722_ldo3_ops = {
|
||||
.get_current_limit = as3722_ldo3_get_current_limit,
|
||||
};
|
||||
|
||||
static struct regulator_ops as3722_ldo3_extcntrl_ops = {
|
||||
static const struct regulator_ops as3722_ldo3_extcntrl_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_current_limit = as3722_ldo3_get_current_limit,
|
||||
};
|
||||
|
||||
static const struct regulator_ops as3722_ldo6_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
.get_current_limit = as3722_ldo_get_current_limit,
|
||||
.set_current_limit = as3722_ldo_set_current_limit,
|
||||
.get_bypass = regulator_get_bypass_regmap,
|
||||
.set_bypass = regulator_set_bypass_regmap,
|
||||
};
|
||||
|
||||
static const struct regulator_ops as3722_ldo6_extcntrl_ops = {
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
.get_current_limit = as3722_ldo_get_current_limit,
|
||||
.set_current_limit = as3722_ldo_set_current_limit,
|
||||
.get_bypass = regulator_get_bypass_regmap,
|
||||
.set_bypass = regulator_set_bypass_regmap,
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range as3722_ldo_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(0, 0x00, 0x00, 0),
|
||||
REGULATOR_LINEAR_RANGE(825000, 0x01, 0x24, 25000),
|
||||
REGULATOR_LINEAR_RANGE(1725000, 0x40, 0x7F, 25000),
|
||||
};
|
||||
|
||||
static struct regulator_ops as3722_ldo_ops = {
|
||||
static const struct regulator_ops as3722_ldo_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
@ -450,7 +475,7 @@ static struct regulator_ops as3722_ldo_ops = {
|
||||
.set_current_limit = as3722_ldo_set_current_limit,
|
||||
};
|
||||
|
||||
static struct regulator_ops as3722_ldo_extcntrl_ops = {
|
||||
static const struct regulator_ops as3722_ldo_extcntrl_ops = {
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
@ -616,7 +641,7 @@ static const struct regulator_linear_range as3722_sd2345_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7F, 50000),
|
||||
};
|
||||
|
||||
static struct regulator_ops as3722_sd016_ops = {
|
||||
static const struct regulator_ops as3722_sd016_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
@ -630,7 +655,7 @@ static struct regulator_ops as3722_sd016_ops = {
|
||||
.set_mode = as3722_sd_set_mode,
|
||||
};
|
||||
|
||||
static struct regulator_ops as3722_sd016_extcntrl_ops = {
|
||||
static const struct regulator_ops as3722_sd016_extcntrl_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.map_voltage = regulator_map_voltage_linear,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
@ -641,7 +666,7 @@ static struct regulator_ops as3722_sd016_extcntrl_ops = {
|
||||
.set_mode = as3722_sd_set_mode,
|
||||
};
|
||||
|
||||
static struct regulator_ops as3722_sd2345_ops = {
|
||||
static const struct regulator_ops as3722_sd2345_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
@ -653,7 +678,7 @@ static struct regulator_ops as3722_sd2345_ops = {
|
||||
.set_mode = as3722_sd_set_mode,
|
||||
};
|
||||
|
||||
static struct regulator_ops as3722_sd2345_extcntrl_ops = {
|
||||
static const struct regulator_ops as3722_sd2345_extcntrl_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
@ -760,7 +785,7 @@ static int as3722_regulator_probe(struct platform_device *pdev)
|
||||
struct as3722_regulator_config_data *reg_config;
|
||||
struct regulator_dev *rdev;
|
||||
struct regulator_config config = { };
|
||||
struct regulator_ops *ops;
|
||||
const struct regulator_ops *ops;
|
||||
int id;
|
||||
int ret;
|
||||
|
||||
@ -829,6 +854,24 @@ static int as3722_regulator_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AS3722_REGULATOR_ID_LDO6:
|
||||
if (reg_config->ext_control)
|
||||
ops = &as3722_ldo6_extcntrl_ops;
|
||||
else
|
||||
ops = &as3722_ldo6_ops;
|
||||
as3722_regs->desc[id].enable_time = 500;
|
||||
as3722_regs->desc[id].bypass_reg =
|
||||
AS3722_LDO6_VOLTAGE_REG;
|
||||
as3722_regs->desc[id].bypass_mask =
|
||||
AS3722_LDO_VSEL_MASK;
|
||||
as3722_regs->desc[id].bypass_val_on =
|
||||
AS3722_LDO6_VSEL_BYPASS;
|
||||
as3722_regs->desc[id].bypass_val_off =
|
||||
AS3722_LDO6_VSEL_BYPASS;
|
||||
as3722_regs->desc[id].linear_ranges = as3722_ldo_ranges;
|
||||
as3722_regs->desc[id].n_linear_ranges =
|
||||
ARRAY_SIZE(as3722_ldo_ranges);
|
||||
break;
|
||||
case AS3722_REGULATOR_ID_SD0:
|
||||
case AS3722_REGULATOR_ID_SD1:
|
||||
case AS3722_REGULATOR_ID_SD6:
|
||||
|
@ -132,6 +132,19 @@ static bool have_full_constraints(void)
|
||||
return has_full_constraints || of_have_populated_dt();
|
||||
}
|
||||
|
||||
static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops)
|
||||
{
|
||||
if (!rdev->constraints) {
|
||||
rdev_err(rdev, "no constraints\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rdev->constraints->valid_ops_mask & ops)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
|
||||
{
|
||||
if (rdev && rdev->supply)
|
||||
@ -198,28 +211,13 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp
|
||||
return regnode;
|
||||
}
|
||||
|
||||
static int _regulator_can_change_status(struct regulator_dev *rdev)
|
||||
{
|
||||
if (!rdev->constraints)
|
||||
return 0;
|
||||
|
||||
if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Platform voltage constraint check */
|
||||
static int regulator_check_voltage(struct regulator_dev *rdev,
|
||||
int *min_uV, int *max_uV)
|
||||
{
|
||||
BUG_ON(*min_uV > *max_uV);
|
||||
|
||||
if (!rdev->constraints) {
|
||||
rdev_err(rdev, "no constraints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
|
||||
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
|
||||
rdev_err(rdev, "voltage operation not allowed\n");
|
||||
return -EPERM;
|
||||
}
|
||||
@ -275,11 +273,7 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
|
||||
{
|
||||
BUG_ON(*min_uA > *max_uA);
|
||||
|
||||
if (!rdev->constraints) {
|
||||
rdev_err(rdev, "no constraints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) {
|
||||
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_CURRENT)) {
|
||||
rdev_err(rdev, "current operation not allowed\n");
|
||||
return -EPERM;
|
||||
}
|
||||
@ -312,11 +306,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!rdev->constraints) {
|
||||
rdev_err(rdev, "no constraints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) {
|
||||
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_MODE)) {
|
||||
rdev_err(rdev, "mode operation not allowed\n");
|
||||
return -EPERM;
|
||||
}
|
||||
@ -333,20 +323,6 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* dynamic regulator mode switching constraint check */
|
||||
static int regulator_check_drms(struct regulator_dev *rdev)
|
||||
{
|
||||
if (!rdev->constraints) {
|
||||
rdev_err(rdev, "no constraints\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) {
|
||||
rdev_dbg(rdev, "drms operation not allowed\n");
|
||||
return -EPERM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t regulator_uV_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -692,8 +668,7 @@ static int drms_uA_update(struct regulator_dev *rdev)
|
||||
* first check to see if we can set modes at all, otherwise just
|
||||
* tell the consumer everything is OK.
|
||||
*/
|
||||
err = regulator_check_drms(rdev);
|
||||
if (err < 0)
|
||||
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
|
||||
return 0;
|
||||
|
||||
if (!rdev->desc->ops->get_optimum_mode &&
|
||||
@ -808,8 +783,6 @@ static int suspend_set_state(struct regulator_dev *rdev,
|
||||
/* locks held by caller */
|
||||
static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state)
|
||||
{
|
||||
lockdep_assert_held_once(&rdev->mutex);
|
||||
|
||||
if (!rdev->constraints)
|
||||
return -EINVAL;
|
||||
|
||||
@ -893,7 +866,7 @@ static void print_constraints(struct regulator_dev *rdev)
|
||||
rdev_dbg(rdev, "%s\n", buf);
|
||||
|
||||
if ((constraints->min_uV != constraints->max_uV) &&
|
||||
!(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE))
|
||||
!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE))
|
||||
rdev_warn(rdev,
|
||||
"Voltage range but no REGULATOR_CHANGE_VOLTAGE\n");
|
||||
}
|
||||
@ -906,7 +879,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
|
||||
|
||||
/* do we need to apply the constraint voltage */
|
||||
if (rdev->constraints->apply_uV &&
|
||||
rdev->constraints->min_uV == rdev->constraints->max_uV) {
|
||||
rdev->constraints->min_uV && rdev->constraints->max_uV) {
|
||||
int target_min, target_max;
|
||||
int current_uV = _regulator_get_voltage(rdev);
|
||||
if (current_uV < 0) {
|
||||
rdev_err(rdev,
|
||||
@ -914,15 +888,34 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
|
||||
current_uV);
|
||||
return current_uV;
|
||||
}
|
||||
if (current_uV < rdev->constraints->min_uV ||
|
||||
current_uV > rdev->constraints->max_uV) {
|
||||
|
||||
/*
|
||||
* If we're below the minimum voltage move up to the
|
||||
* minimum voltage, if we're above the maximum voltage
|
||||
* then move down to the maximum.
|
||||
*/
|
||||
target_min = current_uV;
|
||||
target_max = current_uV;
|
||||
|
||||
if (current_uV < rdev->constraints->min_uV) {
|
||||
target_min = rdev->constraints->min_uV;
|
||||
target_max = rdev->constraints->min_uV;
|
||||
}
|
||||
|
||||
if (current_uV > rdev->constraints->max_uV) {
|
||||
target_min = rdev->constraints->max_uV;
|
||||
target_max = rdev->constraints->max_uV;
|
||||
}
|
||||
|
||||
if (target_min != current_uV || target_max != current_uV) {
|
||||
rdev_info(rdev, "Bringing %duV into %d-%duV\n",
|
||||
current_uV, target_min, target_max);
|
||||
ret = _regulator_do_set_voltage(
|
||||
rdev, rdev->constraints->min_uV,
|
||||
rdev->constraints->max_uV);
|
||||
rdev, target_min, target_max);
|
||||
if (ret < 0) {
|
||||
rdev_err(rdev,
|
||||
"failed to apply %duV constraint(%d)\n",
|
||||
rdev->constraints->min_uV, ret);
|
||||
"failed to apply %d-%duV constraint(%d)\n",
|
||||
target_min, target_max, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -1150,17 +1143,6 @@ static int set_machine_constraints(struct regulator_dev *rdev,
|
||||
}
|
||||
}
|
||||
|
||||
if (rdev->constraints->active_discharge && ops->set_active_discharge) {
|
||||
bool ad_state = (rdev->constraints->active_discharge ==
|
||||
REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;
|
||||
|
||||
ret = ops->set_active_discharge(rdev, ad_state);
|
||||
if (ret < 0) {
|
||||
rdev_err(rdev, "failed to set active discharge\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
print_constraints(rdev);
|
||||
return 0;
|
||||
}
|
||||
@ -1272,6 +1254,55 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static ssize_t constraint_flags_read_file(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
const struct regulator *regulator = file->private_data;
|
||||
const struct regulation_constraints *c = regulator->rdev->constraints;
|
||||
char *buf;
|
||||
ssize_t ret;
|
||||
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = snprintf(buf, PAGE_SIZE,
|
||||
"always_on: %u\n"
|
||||
"boot_on: %u\n"
|
||||
"apply_uV: %u\n"
|
||||
"ramp_disable: %u\n"
|
||||
"soft_start: %u\n"
|
||||
"pull_down: %u\n"
|
||||
"over_current_protection: %u\n",
|
||||
c->always_on,
|
||||
c->boot_on,
|
||||
c->apply_uV,
|
||||
c->ramp_disable,
|
||||
c->soft_start,
|
||||
c->pull_down,
|
||||
c->over_current_protection);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
|
||||
kfree(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const struct file_operations constraint_flags_fops = {
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
.open = simple_open,
|
||||
.read = constraint_flags_read_file,
|
||||
.llseek = default_llseek,
|
||||
#endif
|
||||
};
|
||||
|
||||
#define REG_STR_SIZE 64
|
||||
|
||||
static struct regulator *create_regulator(struct regulator_dev *rdev,
|
||||
@ -1327,6 +1358,9 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
|
||||
®ulator->min_uV);
|
||||
debugfs_create_u32("max_uV", 0444, regulator->debugfs,
|
||||
®ulator->max_uV);
|
||||
debugfs_create_file("constraint_flags", 0444,
|
||||
regulator->debugfs, regulator,
|
||||
&constraint_flags_fops);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1334,7 +1368,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
|
||||
* it is then we don't need to do nearly so much work for
|
||||
* enable/disable calls.
|
||||
*/
|
||||
if (!_regulator_can_change_status(rdev) &&
|
||||
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS) &&
|
||||
_regulator_is_enabled(rdev))
|
||||
regulator->always_on = true;
|
||||
|
||||
@ -1532,10 +1566,11 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
|
||||
}
|
||||
|
||||
/* Cascade always-on state to supply */
|
||||
if (_regulator_is_enabled(rdev) && rdev->supply) {
|
||||
if (_regulator_is_enabled(rdev)) {
|
||||
ret = regulator_enable(rdev->supply);
|
||||
if (ret < 0) {
|
||||
_regulator_put(rdev->supply);
|
||||
rdev->supply = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -2111,15 +2146,15 @@ static int _regulator_enable(struct regulator_dev *rdev)
|
||||
lockdep_assert_held_once(&rdev->mutex);
|
||||
|
||||
/* check voltage and requested load before enabling */
|
||||
if (rdev->constraints &&
|
||||
(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
|
||||
if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
|
||||
drms_uA_update(rdev);
|
||||
|
||||
if (rdev->use_count == 0) {
|
||||
/* The regulator may on if it's not switchable or left on */
|
||||
ret = _regulator_is_enabled(rdev);
|
||||
if (ret == -EINVAL || ret == 0) {
|
||||
if (!_regulator_can_change_status(rdev))
|
||||
if (!regulator_ops_is_valid(rdev,
|
||||
REGULATOR_CHANGE_STATUS))
|
||||
return -EPERM;
|
||||
|
||||
ret = _regulator_do_enable(rdev);
|
||||
@ -2221,7 +2256,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
|
||||
(rdev->constraints && !rdev->constraints->always_on)) {
|
||||
|
||||
/* we are last user */
|
||||
if (_regulator_can_change_status(rdev)) {
|
||||
if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) {
|
||||
ret = _notifier_call_chain(rdev,
|
||||
REGULATOR_EVENT_PRE_DISABLE,
|
||||
NULL);
|
||||
@ -2242,10 +2277,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
|
||||
|
||||
rdev->use_count = 0;
|
||||
} else if (rdev->use_count > 1) {
|
||||
|
||||
if (rdev->constraints &&
|
||||
(rdev->constraints->valid_ops_mask &
|
||||
REGULATOR_CHANGE_DRMS))
|
||||
if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
|
||||
drms_uA_update(rdev);
|
||||
|
||||
rdev->use_count--;
|
||||
@ -2489,8 +2521,7 @@ int regulator_can_change_voltage(struct regulator *regulator)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
|
||||
if (rdev->constraints &&
|
||||
(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
|
||||
if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
|
||||
if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1)
|
||||
return 1;
|
||||
|
||||
@ -2644,7 +2675,7 @@ int regulator_is_supported_voltage(struct regulator *regulator,
|
||||
int i, voltages, ret;
|
||||
|
||||
/* If we can't change voltage check the current voltage */
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
|
||||
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
|
||||
ret = regulator_get_voltage(regulator);
|
||||
if (ret >= 0)
|
||||
return min_uV <= ret && ret <= max_uV;
|
||||
@ -2850,7 +2881,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
|
||||
* return successfully even though the regulator does not support
|
||||
* changing the voltage.
|
||||
*/
|
||||
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
|
||||
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
|
||||
current_uV = _regulator_get_voltage(rdev);
|
||||
if (min_uV <= current_uV && current_uV <= max_uV) {
|
||||
regulator->min_uV = min_uV;
|
||||
@ -3109,6 +3140,23 @@ EXPORT_SYMBOL_GPL(regulator_sync_voltage);
|
||||
static int _regulator_get_voltage(struct regulator_dev *rdev)
|
||||
{
|
||||
int sel, ret;
|
||||
bool bypassed;
|
||||
|
||||
if (rdev->desc->ops->get_bypass) {
|
||||
ret = rdev->desc->ops->get_bypass(rdev, &bypassed);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (bypassed) {
|
||||
/* if bypassed the regulator must have a supply */
|
||||
if (!rdev->supply) {
|
||||
rdev_err(rdev,
|
||||
"bypassed regulator has no supply!\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
return _regulator_get_voltage(rdev->supply->rdev);
|
||||
}
|
||||
}
|
||||
|
||||
if (rdev->desc->ops->get_voltage_sel) {
|
||||
sel = rdev->desc->ops->get_voltage_sel(rdev);
|
||||
@ -3365,8 +3413,7 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable)
|
||||
if (!rdev->desc->ops->set_bypass)
|
||||
return 0;
|
||||
|
||||
if (rdev->constraints &&
|
||||
!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS))
|
||||
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_BYPASS))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
@ -3840,6 +3887,16 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
|
||||
&rdev->bypass_count);
|
||||
}
|
||||
|
||||
static int regulator_register_resolve_supply(struct device *dev, void *data)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_to_rdev(dev);
|
||||
|
||||
if (regulator_resolve_supply(rdev))
|
||||
rdev_dbg(rdev, "unable to resolve supply\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_register - register regulator
|
||||
* @regulator_desc: regulator to register
|
||||
@ -3911,8 +3968,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
|
||||
rdev->dev.of_node = of_node_get(config->of_node);
|
||||
}
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
|
||||
mutex_init(&rdev->mutex);
|
||||
rdev->reg_data = config->driver_data;
|
||||
rdev->owner = regulator_desc->owner;
|
||||
@ -3937,7 +3992,9 @@ regulator_register(const struct regulator_desc *regulator_desc,
|
||||
|
||||
if ((config->ena_gpio || config->ena_gpio_initialized) &&
|
||||
gpio_is_valid(config->ena_gpio)) {
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
ret = regulator_ena_gpio_request(rdev, config);
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
if (ret != 0) {
|
||||
rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
|
||||
config->ena_gpio, ret);
|
||||
@ -3950,63 +4007,73 @@ regulator_register(const struct regulator_desc *regulator_desc,
|
||||
rdev->dev.parent = dev;
|
||||
dev_set_name(&rdev->dev, "regulator.%lu",
|
||||
(unsigned long) atomic_inc_return(®ulator_no));
|
||||
ret = device_register(&rdev->dev);
|
||||
if (ret != 0) {
|
||||
put_device(&rdev->dev);
|
||||
goto wash;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&rdev->dev, rdev);
|
||||
|
||||
/* set regulator constraints */
|
||||
if (init_data)
|
||||
constraints = &init_data->constraints;
|
||||
|
||||
ret = set_machine_constraints(rdev, constraints);
|
||||
if (ret < 0)
|
||||
goto scrub;
|
||||
|
||||
if (init_data && init_data->supply_regulator)
|
||||
rdev->supply_name = init_data->supply_regulator;
|
||||
else if (regulator_desc->supply_name)
|
||||
rdev->supply_name = regulator_desc->supply_name;
|
||||
|
||||
/*
|
||||
* Attempt to resolve the regulator supply, if specified,
|
||||
* but don't return an error if we fail because we will try
|
||||
* to resolve it again later as more regulators are added.
|
||||
*/
|
||||
if (regulator_resolve_supply(rdev))
|
||||
rdev_dbg(rdev, "unable to resolve supply\n");
|
||||
|
||||
ret = set_machine_constraints(rdev, constraints);
|
||||
if (ret < 0)
|
||||
goto wash;
|
||||
|
||||
/* add consumers devices */
|
||||
if (init_data) {
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
for (i = 0; i < init_data->num_consumer_supplies; i++) {
|
||||
ret = set_consumer_device_supply(rdev,
|
||||
init_data->consumer_supplies[i].dev_name,
|
||||
init_data->consumer_supplies[i].supply);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
dev_err(dev, "Failed to set supply %s\n",
|
||||
init_data->consumer_supplies[i].supply);
|
||||
goto unset_supplies;
|
||||
}
|
||||
}
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
}
|
||||
|
||||
ret = device_register(&rdev->dev);
|
||||
if (ret != 0) {
|
||||
put_device(&rdev->dev);
|
||||
goto unset_supplies;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&rdev->dev, rdev);
|
||||
rdev_init_debugfs(rdev);
|
||||
out:
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
|
||||
/* try to resolve regulators supply since a new one was registered */
|
||||
class_for_each_device(®ulator_class, NULL, NULL,
|
||||
regulator_register_resolve_supply);
|
||||
kfree(config);
|
||||
return rdev;
|
||||
|
||||
unset_supplies:
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
unset_regulator_supplies(rdev);
|
||||
|
||||
scrub:
|
||||
regulator_ena_gpio_free(rdev);
|
||||
device_unregister(&rdev->dev);
|
||||
/* device core frees rdev */
|
||||
rdev = ERR_PTR(ret);
|
||||
goto out;
|
||||
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
wash:
|
||||
kfree(rdev->constraints);
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
regulator_ena_gpio_free(rdev);
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
clean:
|
||||
kfree(rdev);
|
||||
rdev = ERR_PTR(ret);
|
||||
goto out;
|
||||
kfree(config);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_register);
|
||||
|
||||
@ -4032,8 +4099,8 @@ void regulator_unregister(struct regulator_dev *rdev)
|
||||
WARN_ON(rdev->open_count);
|
||||
unset_regulator_supplies(rdev);
|
||||
list_del(&rdev->list);
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
regulator_ena_gpio_free(rdev);
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
device_unregister(&rdev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_unregister);
|
||||
@ -4386,7 +4453,7 @@ static int __init regulator_late_cleanup(struct device *dev, void *data)
|
||||
if (c && c->always_on)
|
||||
return 0;
|
||||
|
||||
if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))
|
||||
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
|
@ -65,6 +65,13 @@ enum {
|
||||
FAN53555_CHIP_ID_03,
|
||||
FAN53555_CHIP_ID_04,
|
||||
FAN53555_CHIP_ID_05,
|
||||
FAN53555_CHIP_ID_08 = 8,
|
||||
};
|
||||
|
||||
/* IC mask revision */
|
||||
enum {
|
||||
FAN53555_CHIP_REV_00 = 0x3,
|
||||
FAN53555_CHIP_REV_13 = 0xf,
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -217,9 +224,26 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di)
|
||||
/* Init voltage range and step */
|
||||
switch (di->chip_id) {
|
||||
case FAN53555_CHIP_ID_00:
|
||||
switch (di->chip_rev) {
|
||||
case FAN53555_CHIP_REV_00:
|
||||
di->vsel_min = 600000;
|
||||
di->vsel_step = 10000;
|
||||
break;
|
||||
case FAN53555_CHIP_REV_13:
|
||||
di->vsel_min = 800000;
|
||||
di->vsel_step = 10000;
|
||||
break;
|
||||
default:
|
||||
dev_err(di->dev,
|
||||
"Chip ID %d with rev %d not supported!\n",
|
||||
di->chip_id, di->chip_rev);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case FAN53555_CHIP_ID_01:
|
||||
case FAN53555_CHIP_ID_03:
|
||||
case FAN53555_CHIP_ID_05:
|
||||
case FAN53555_CHIP_ID_08:
|
||||
di->vsel_min = 600000;
|
||||
di->vsel_step = 10000;
|
||||
break;
|
||||
|
@ -460,7 +460,7 @@ int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
*enable = val & rdev->desc->bypass_mask;
|
||||
*enable = (val & rdev->desc->bypass_mask) == rdev->desc->bypass_val_on;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -365,8 +365,8 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val)
|
||||
mutex_lock(&lp3971->io_lock);
|
||||
|
||||
ret = lp3971_i2c_read(lp3971->i2c, reg, 1, &tmp);
|
||||
tmp = (tmp & ~mask) | val;
|
||||
if (ret == 0) {
|
||||
tmp = (tmp & ~mask) | val;
|
||||
ret = lp3971_i2c_write(lp3971->i2c, reg, 1, &tmp);
|
||||
dev_dbg(lp3971->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
|
||||
(unsigned)val&0xff);
|
||||
|
@ -211,8 +211,8 @@ static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val)
|
||||
mutex_lock(&lp3972->io_lock);
|
||||
|
||||
ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp);
|
||||
tmp = (tmp & ~mask) | val;
|
||||
if (ret == 0) {
|
||||
tmp = (tmp & ~mask) | val;
|
||||
ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp);
|
||||
dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
|
||||
(unsigned)val & 0xff);
|
||||
|
241
drivers/regulator/lp873x-regulator.c
Normal file
241
drivers/regulator/lp873x-regulator.c
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Regulator driver for LP873X PMIC
|
||||
*
|
||||
* Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/mfd/lp873x.h>
|
||||
|
||||
#define LP873X_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, _er, _em, \
|
||||
_delay, _lr, _nlr, _cr) \
|
||||
[_id] = { \
|
||||
.desc = { \
|
||||
.name = _name, \
|
||||
.id = _id, \
|
||||
.of_match = of_match_ptr(_of), \
|
||||
.regulators_node = of_match_ptr("regulators"),\
|
||||
.ops = &_ops, \
|
||||
.n_voltages = _n, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.vsel_reg = _vr, \
|
||||
.vsel_mask = _vm, \
|
||||
.enable_reg = _er, \
|
||||
.enable_mask = _em, \
|
||||
.ramp_delay = _delay, \
|
||||
.linear_ranges = _lr, \
|
||||
.n_linear_ranges = _nlr, \
|
||||
}, \
|
||||
.ctrl2_reg = _cr, \
|
||||
}
|
||||
|
||||
struct lp873x_regulator {
|
||||
struct regulator_desc desc;
|
||||
unsigned int ctrl2_reg;
|
||||
};
|
||||
|
||||
static const struct lp873x_regulator regulators[];
|
||||
|
||||
static const struct regulator_linear_range buck0_buck1_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(0, 0x0, 0x13, 0),
|
||||
REGULATOR_LINEAR_RANGE(700000, 0x14, 0x17, 10000),
|
||||
REGULATOR_LINEAR_RANGE(735000, 0x18, 0x9d, 5000),
|
||||
REGULATOR_LINEAR_RANGE(1420000, 0x9e, 0xff, 20000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range ldo0_ldo1_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(800000, 0x0, 0x19, 100000),
|
||||
};
|
||||
|
||||
static unsigned int lp873x_buck_ramp_delay[] = {
|
||||
30000, 15000, 10000, 7500, 3800, 1900, 940, 470
|
||||
};
|
||||
|
||||
/* LP873X BUCK current limit */
|
||||
static const unsigned int lp873x_buck_uA[] = {
|
||||
1500000, 2000000, 2500000, 3000000, 3500000, 4000000,
|
||||
};
|
||||
|
||||
static int lp873x_buck_set_ramp_delay(struct regulator_dev *rdev,
|
||||
int ramp_delay)
|
||||
{
|
||||
int id = rdev_get_id(rdev);
|
||||
struct lp873x *lp873 = rdev_get_drvdata(rdev);
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
if (ramp_delay <= 470)
|
||||
reg = 7;
|
||||
else if (ramp_delay <= 940)
|
||||
reg = 6;
|
||||
else if (ramp_delay <= 1900)
|
||||
reg = 5;
|
||||
else if (ramp_delay <= 3800)
|
||||
reg = 4;
|
||||
else if (ramp_delay <= 7500)
|
||||
reg = 3;
|
||||
else if (ramp_delay <= 10000)
|
||||
reg = 2;
|
||||
else if (ramp_delay <= 15000)
|
||||
reg = 1;
|
||||
else
|
||||
reg = 0;
|
||||
|
||||
ret = regmap_update_bits(lp873->regmap, regulators[id].ctrl2_reg,
|
||||
LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE,
|
||||
reg << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE));
|
||||
if (ret) {
|
||||
dev_err(lp873->dev, "SLEW RATE write failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rdev->constraints->ramp_delay = lp873x_buck_ramp_delay[reg];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lp873x_buck_set_current_limit(struct regulator_dev *rdev,
|
||||
int min_uA, int max_uA)
|
||||
{
|
||||
int id = rdev_get_id(rdev);
|
||||
struct lp873x *lp873 = rdev_get_drvdata(rdev);
|
||||
int i;
|
||||
|
||||
for (i = ARRAY_SIZE(lp873x_buck_uA) - 1; i >= 0; i--) {
|
||||
if (lp873x_buck_uA[i] >= min_uA &&
|
||||
lp873x_buck_uA[i] <= max_uA)
|
||||
return regmap_update_bits(lp873->regmap,
|
||||
regulators[id].ctrl2_reg,
|
||||
LP873X_BUCK0_CTRL_2_BUCK0_ILIM,
|
||||
i << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_ILIM));
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int lp873x_buck_get_current_limit(struct regulator_dev *rdev)
|
||||
{
|
||||
int id = rdev_get_id(rdev);
|
||||
struct lp873x *lp873 = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
ret = regmap_read(lp873->regmap, regulators[id].ctrl2_reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = (val & LP873X_BUCK0_CTRL_2_BUCK0_ILIM) >>
|
||||
__ffs(LP873X_BUCK0_CTRL_2_BUCK0_ILIM);
|
||||
|
||||
return (val < ARRAY_SIZE(lp873x_buck_uA)) ?
|
||||
lp873x_buck_uA[val] : -EINVAL;
|
||||
}
|
||||
|
||||
/* Operations permitted on BUCK0, BUCK1 */
|
||||
static struct regulator_ops lp873x_buck01_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||
.set_ramp_delay = lp873x_buck_set_ramp_delay,
|
||||
.set_current_limit = lp873x_buck_set_current_limit,
|
||||
.get_current_limit = lp873x_buck_get_current_limit,
|
||||
};
|
||||
|
||||
/* Operations permitted on LDO0 and LDO1 */
|
||||
static struct regulator_ops lp873x_ldo01_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
};
|
||||
|
||||
static const struct lp873x_regulator regulators[] = {
|
||||
LP873X_REGULATOR("BUCK0", LP873X_BUCK_0, "buck0", lp873x_buck01_ops,
|
||||
256, LP873X_REG_BUCK0_VOUT,
|
||||
LP873X_BUCK0_VOUT_BUCK0_VSET, LP873X_REG_BUCK0_CTRL_1,
|
||||
LP873X_BUCK0_CTRL_1_BUCK0_EN, 10000,
|
||||
buck0_buck1_ranges, 4, LP873X_REG_BUCK0_CTRL_2),
|
||||
LP873X_REGULATOR("BUCK1", LP873X_BUCK_1, "buck1", lp873x_buck01_ops,
|
||||
256, LP873X_REG_BUCK1_VOUT,
|
||||
LP873X_BUCK1_VOUT_BUCK1_VSET, LP873X_REG_BUCK1_CTRL_1,
|
||||
LP873X_BUCK1_CTRL_1_BUCK1_EN, 10000,
|
||||
buck0_buck1_ranges, 4, LP873X_REG_BUCK1_CTRL_2),
|
||||
LP873X_REGULATOR("LDO0", LP873X_LDO_0, "ldo0", lp873x_ldo01_ops, 26,
|
||||
LP873X_REG_LDO0_VOUT, LP873X_LDO0_VOUT_LDO0_VSET,
|
||||
LP873X_REG_LDO0_CTRL,
|
||||
LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 1,
|
||||
0xFF),
|
||||
LP873X_REGULATOR("LDO1", LP873X_LDO_1, "ldo1", lp873x_ldo01_ops, 26,
|
||||
LP873X_REG_LDO1_VOUT, LP873X_LDO1_VOUT_LDO1_VSET,
|
||||
LP873X_REG_LDO1_CTRL,
|
||||
LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 1,
|
||||
0xFF),
|
||||
};
|
||||
|
||||
static int lp873x_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lp873x *lp873 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct regulator_config config = { };
|
||||
struct regulator_dev *rdev;
|
||||
int i;
|
||||
|
||||
platform_set_drvdata(pdev, lp873);
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.dev->of_node = lp873->dev->of_node;
|
||||
config.driver_data = lp873;
|
||||
config.regmap = lp873->regmap;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
|
||||
rdev = devm_regulator_register(&pdev->dev, ®ulators[i].desc,
|
||||
&config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(lp873->dev, "failed to register %s regulator\n",
|
||||
pdev->name);
|
||||
return PTR_ERR(rdev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id lp873x_regulator_id_table[] = {
|
||||
{ "lp873x-regulator", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, lp873x_regulator_id_table);
|
||||
|
||||
static struct platform_driver lp873x_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "lp873x-pmic",
|
||||
},
|
||||
.probe = lp873x_regulator_probe,
|
||||
.id_table = lp873x_regulator_id_table,
|
||||
};
|
||||
module_platform_driver(lp873x_regulator_driver);
|
||||
|
||||
MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
|
||||
MODULE_DESCRIPTION("LP873X voltage regulator driver");
|
||||
MODULE_ALIAS("platform:lp873x-pmic");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -81,6 +81,7 @@ struct max77620_regulator_pdata {
|
||||
int suspend_fps_pd_slot;
|
||||
int suspend_fps_pu_slot;
|
||||
int current_mode;
|
||||
int ramp_rate_setting;
|
||||
};
|
||||
|
||||
struct max77620_regulator {
|
||||
@ -307,6 +308,43 @@ static int max77620_read_slew_rate(struct max77620_regulator *pmic, int id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77620_set_slew_rate(struct max77620_regulator *pmic, int id,
|
||||
int slew_rate)
|
||||
{
|
||||
struct max77620_regulator_info *rinfo = pmic->rinfo[id];
|
||||
unsigned int val;
|
||||
int ret;
|
||||
u8 mask;
|
||||
|
||||
if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) {
|
||||
if (slew_rate <= 13750)
|
||||
val = 0;
|
||||
else if (slew_rate <= 27500)
|
||||
val = 1;
|
||||
else if (slew_rate <= 55000)
|
||||
val = 2;
|
||||
else
|
||||
val = 3;
|
||||
val <<= MAX77620_SD_SR_SHIFT;
|
||||
mask = MAX77620_SD_SR_MASK;
|
||||
} else {
|
||||
if (slew_rate <= 5000)
|
||||
val = 1;
|
||||
else
|
||||
val = 0;
|
||||
mask = MAX77620_LDO_SLEW_RATE_MASK;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, mask, val);
|
||||
if (ret < 0) {
|
||||
dev_err(pmic->dev, "Regulator %d slew rate set failed: %d\n",
|
||||
id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77620_init_pmic(struct max77620_regulator *pmic, int id)
|
||||
{
|
||||
struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
|
||||
@ -351,6 +389,13 @@ static int max77620_init_pmic(struct max77620_regulator *pmic, int id)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (rpdata->ramp_rate_setting) {
|
||||
ret = max77620_set_slew_rate(pmic, id,
|
||||
rpdata->ramp_rate_setting);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -502,35 +547,16 @@ static int max77620_regulator_set_ramp_delay(struct regulator_dev *rdev,
|
||||
{
|
||||
struct max77620_regulator *pmic = rdev_get_drvdata(rdev);
|
||||
int id = rdev_get_id(rdev);
|
||||
struct max77620_regulator_info *rinfo = pmic->rinfo[id];
|
||||
int ret, val;
|
||||
u8 mask;
|
||||
struct max77620_regulator_pdata *rpdata = &pmic->reg_pdata[id];
|
||||
|
||||
if (rinfo->type == MAX77620_REGULATOR_TYPE_SD) {
|
||||
if (ramp_delay <= 13750)
|
||||
val = 0;
|
||||
else if (ramp_delay <= 27500)
|
||||
val = 1;
|
||||
else if (ramp_delay <= 55000)
|
||||
val = 2;
|
||||
else
|
||||
val = 3;
|
||||
val <<= MAX77620_SD_SR_SHIFT;
|
||||
mask = MAX77620_SD_SR_MASK;
|
||||
} else {
|
||||
if (ramp_delay <= 5000)
|
||||
val = 1;
|
||||
else
|
||||
val = 0;
|
||||
mask = MAX77620_LDO_SLEW_RATE_MASK;
|
||||
}
|
||||
/* Device specific ramp rate setting tells that platform has
|
||||
* different ramp rate from advertised value. In this case,
|
||||
* do not configure anything and just return success.
|
||||
*/
|
||||
if (rpdata->ramp_rate_setting)
|
||||
return 0;
|
||||
|
||||
ret = regmap_update_bits(pmic->rmap, rinfo->cfg_addr, mask, val);
|
||||
if (ret < 0)
|
||||
dev_err(pmic->dev, "Reg 0x%02x update failed: %d\n",
|
||||
rinfo->cfg_addr, ret);
|
||||
|
||||
return ret;
|
||||
return max77620_set_slew_rate(pmic, id, ramp_delay);
|
||||
}
|
||||
|
||||
static int max77620_of_parse_cb(struct device_node *np,
|
||||
@ -563,6 +589,9 @@ static int max77620_of_parse_cb(struct device_node *np,
|
||||
np, "maxim,suspend-fps-power-down-slot", &pval);
|
||||
rpdata->suspend_fps_pd_slot = (!ret) ? pval : -1;
|
||||
|
||||
ret = of_property_read_u32(np, "maxim,ramp-rate-setting", &pval);
|
||||
rpdata->ramp_rate_setting = (!ret) ? pval : 0;
|
||||
|
||||
return max77620_init_pmic(pmic, desc->id);
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,8 @@
|
||||
#define MAX77686_LDO_LOW_UVSTEP 25000
|
||||
#define MAX77686_BUCK_MINUV 750000
|
||||
#define MAX77686_BUCK_UVSTEP 50000
|
||||
#define MAX77686_BUCK_ENABLE_TIME 40 /* us */
|
||||
#define MAX77686_DVS_ENABLE_TIME 22 /* us */
|
||||
#define MAX77686_RAMP_DELAY 100000 /* uV/us */
|
||||
#define MAX77686_DVS_RAMP_DELAY 27500 /* uV/us */
|
||||
#define MAX77686_DVS_MINUV 600000
|
||||
@ -422,6 +424,7 @@ static struct regulator_ops max77686_buck_dvs_ops = {
|
||||
.min_uV = MAX77686_BUCK_MINUV, \
|
||||
.uV_step = MAX77686_BUCK_UVSTEP, \
|
||||
.ramp_delay = MAX77686_RAMP_DELAY, \
|
||||
.enable_time = MAX77686_BUCK_ENABLE_TIME, \
|
||||
.n_voltages = MAX77686_VSEL_MASK + 1, \
|
||||
.vsel_reg = MAX77686_REG_BUCK5OUT + (num - 5) * 2, \
|
||||
.vsel_mask = MAX77686_VSEL_MASK, \
|
||||
@ -439,6 +442,7 @@ static struct regulator_ops max77686_buck_dvs_ops = {
|
||||
.min_uV = MAX77686_BUCK_MINUV, \
|
||||
.uV_step = MAX77686_BUCK_UVSTEP, \
|
||||
.ramp_delay = MAX77686_RAMP_DELAY, \
|
||||
.enable_time = MAX77686_BUCK_ENABLE_TIME, \
|
||||
.n_voltages = MAX77686_VSEL_MASK + 1, \
|
||||
.vsel_reg = MAX77686_REG_BUCK1OUT, \
|
||||
.vsel_mask = MAX77686_VSEL_MASK, \
|
||||
@ -456,6 +460,7 @@ static struct regulator_ops max77686_buck_dvs_ops = {
|
||||
.min_uV = MAX77686_DVS_MINUV, \
|
||||
.uV_step = MAX77686_DVS_UVSTEP, \
|
||||
.ramp_delay = MAX77686_DVS_RAMP_DELAY, \
|
||||
.enable_time = MAX77686_DVS_ENABLE_TIME, \
|
||||
.n_voltages = MAX77686_DVS_VSEL_MASK + 1, \
|
||||
.vsel_reg = MAX77686_REG_BUCK2DVS1 + (num - 2) * 10, \
|
||||
.vsel_mask = MAX77686_DVS_VSEL_MASK, \
|
||||
@ -553,17 +558,7 @@ static struct platform_driver max77686_pmic_driver = {
|
||||
.id_table = max77686_pmic_id,
|
||||
};
|
||||
|
||||
static int __init max77686_pmic_init(void)
|
||||
{
|
||||
return platform_driver_register(&max77686_pmic_driver);
|
||||
}
|
||||
subsys_initcall(max77686_pmic_init);
|
||||
|
||||
static void __exit max77686_pmic_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&max77686_pmic_driver);
|
||||
}
|
||||
module_exit(max77686_pmic_cleanup);
|
||||
module_platform_driver(max77686_pmic_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 77686 Regulator Driver");
|
||||
MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Simon Glass <sjg@chromium.org>
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
* Chiwoong Byun <woong.byun@smasung.com>
|
||||
* Chiwoong Byun <woong.byun@samsung.com>
|
||||
* Jonghwa Lee <jonghwa3.lee@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -38,6 +38,9 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
/* Register definitions */
|
||||
#define MAX8973_VOUT 0x0
|
||||
@ -74,6 +77,7 @@
|
||||
#define MAX8973_WDTMR_ENABLE BIT(6)
|
||||
#define MAX8973_DISCH_ENBABLE BIT(5)
|
||||
#define MAX8973_FT_ENABLE BIT(4)
|
||||
#define MAX77621_T_JUNCTION_120 BIT(7)
|
||||
|
||||
#define MAX8973_CKKADV_TRIP_MASK 0xC
|
||||
#define MAX8973_CKKADV_TRIP_DISABLE 0xC
|
||||
@ -93,6 +97,12 @@
|
||||
#define MAX8973_VOLATGE_STEP 6250
|
||||
#define MAX8973_BUCK_N_VOLTAGE 0x80
|
||||
|
||||
#define MAX77621_CHIPID_TJINT_S BIT(0)
|
||||
|
||||
#define MAX77621_NORMAL_OPERATING_TEMP 100000
|
||||
#define MAX77621_TJINT_WARNING_TEMP_120 120000
|
||||
#define MAX77621_TJINT_WARNING_TEMP_140 140000
|
||||
|
||||
enum device_id {
|
||||
MAX8973,
|
||||
MAX77621
|
||||
@ -112,6 +122,9 @@ struct max8973_chip {
|
||||
int curr_gpio_val;
|
||||
struct regulator_ops ops;
|
||||
enum device_id id;
|
||||
int junction_temp_warning;
|
||||
int irq;
|
||||
struct thermal_zone_device *tz_device;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -391,6 +404,10 @@ static int max8973_init_dcdc(struct max8973_chip *max,
|
||||
if (pdata->control_flags & MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE)
|
||||
control1 |= MAX8973_FREQSHIFT_9PER;
|
||||
|
||||
if ((pdata->junction_temp_warning == MAX77621_TJINT_WARNING_TEMP_120) &&
|
||||
(max->id == MAX77621))
|
||||
control2 |= MAX77621_T_JUNCTION_120;
|
||||
|
||||
if (!(pdata->control_flags & MAX8973_CONTROL_PULL_DOWN_ENABLE))
|
||||
control2 |= MAX8973_DISCH_ENBABLE;
|
||||
|
||||
@ -457,6 +474,79 @@ static int max8973_init_dcdc(struct max8973_chip *max,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max8973_thermal_read_temp(void *data, int *temp)
|
||||
{
|
||||
struct max8973_chip *mchip = data;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(mchip->regmap, MAX8973_CHIPID1, &val);
|
||||
if (ret < 0) {
|
||||
dev_err(mchip->dev, "Failed to read register CHIPID1, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* +1 degC to trigger cool devive */
|
||||
if (val & MAX77621_CHIPID_TJINT_S)
|
||||
*temp = mchip->junction_temp_warning + 1000;
|
||||
else
|
||||
*temp = MAX77621_NORMAL_OPERATING_TEMP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t max8973_thermal_irq(int irq, void *data)
|
||||
{
|
||||
struct max8973_chip *mchip = data;
|
||||
|
||||
thermal_zone_device_update(mchip->tz_device);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct thermal_zone_of_device_ops max77621_tz_ops = {
|
||||
.get_temp = max8973_thermal_read_temp,
|
||||
};
|
||||
|
||||
static int max8973_thermal_init(struct max8973_chip *mchip)
|
||||
{
|
||||
struct thermal_zone_device *tzd;
|
||||
struct irq_data *irq_data;
|
||||
unsigned long irq_flags = 0;
|
||||
int ret;
|
||||
|
||||
if (mchip->id != MAX77621)
|
||||
return 0;
|
||||
|
||||
tzd = devm_thermal_zone_of_sensor_register(mchip->dev, 0, mchip,
|
||||
&max77621_tz_ops);
|
||||
if (IS_ERR(tzd)) {
|
||||
ret = PTR_ERR(tzd);
|
||||
dev_err(mchip->dev, "Failed to register thermal sensor: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (mchip->irq <= 0)
|
||||
return 0;
|
||||
|
||||
irq_data = irq_get_irq_data(mchip->irq);
|
||||
if (irq_data)
|
||||
irq_flags = irqd_get_trigger_type(irq_data);
|
||||
|
||||
ret = devm_request_threaded_irq(mchip->dev, mchip->irq, NULL,
|
||||
max8973_thermal_irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED | irq_flags,
|
||||
dev_name(mchip->dev), mchip);
|
||||
if (ret < 0) {
|
||||
dev_err(mchip->dev, "Failed to request irq %d, %d\n",
|
||||
mchip->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config max8973_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
@ -521,6 +611,11 @@ static struct max8973_regulator_platform_data *max8973_parse_dt(
|
||||
pdata->control_flags |= MAX8973_CONTROL_CLKADV_TRIP_DISABLED;
|
||||
}
|
||||
|
||||
pdata->junction_temp_warning = MAX77621_TJINT_WARNING_TEMP_140;
|
||||
ret = of_property_read_u32(np, "junction-warn-millicelsius", &pval);
|
||||
if (!ret && (pval <= MAX77621_TJINT_WARNING_TEMP_120))
|
||||
pdata->junction_temp_warning = MAX77621_TJINT_WARNING_TEMP_120;
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
@ -608,6 +703,7 @@ static int max8973_probe(struct i2c_client *client,
|
||||
max->enable_external_control = pdata->enable_ext_control;
|
||||
max->curr_gpio_val = pdata->dvs_def_state;
|
||||
max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state;
|
||||
max->junction_temp_warning = pdata->junction_temp_warning;
|
||||
|
||||
if (gpio_is_valid(max->enable_gpio))
|
||||
max->enable_external_control = true;
|
||||
@ -718,6 +814,7 @@ static int max8973_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
max8973_thermal_init(max);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* max8997.c - Regulator driver for the Maxim 8997/8966
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics
|
||||
* MyungJoo Ham <myungjoo.ham@smasung.com>
|
||||
* MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
@ -45,9 +45,9 @@ static void of_get_regulation_constraints(struct device_node *np,
|
||||
/* Voltage change possible? */
|
||||
if (constraints->min_uV != constraints->max_uV)
|
||||
constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
|
||||
/* Only one voltage? Then make sure it's set. */
|
||||
if (constraints->min_uV && constraints->max_uV &&
|
||||
constraints->min_uV == constraints->max_uV)
|
||||
|
||||
/* Do we have a voltage range, if so try to apply it? */
|
||||
if (constraints->min_uV && constraints->max_uV)
|
||||
constraints->apply_uV = true;
|
||||
|
||||
if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
|
||||
|
@ -944,6 +944,8 @@ static int palmas_ldo_registration(struct palmas_pmic *pmic,
|
||||
if (id == PALMAS_REG_LDO9) {
|
||||
desc->ops = &palmas_ops_ldo9;
|
||||
desc->bypass_reg = desc->enable_reg;
|
||||
desc->bypass_val_on =
|
||||
PALMAS_LDO9_CTRL_LDO_BYPASS_EN;
|
||||
desc->bypass_mask =
|
||||
PALMAS_LDO9_CTRL_LDO_BYPASS_EN;
|
||||
}
|
||||
@ -1055,6 +1057,8 @@ static int tps65917_ldo_registration(struct palmas_pmic *pmic,
|
||||
id == TPS65917_REG_LDO2) {
|
||||
desc->ops = &tps65917_ops_ldo_1_2;
|
||||
desc->bypass_reg = desc->enable_reg;
|
||||
desc->bypass_val_on =
|
||||
TPS65917_LDO1_CTRL_BYPASS_EN;
|
||||
desc->bypass_mask =
|
||||
TPS65917_LDO1_CTRL_BYPASS_EN;
|
||||
}
|
||||
@ -1206,6 +1210,7 @@ static int palmas_smps_registration(struct palmas_pmic *pmic,
|
||||
desc->enable_mask = SMPS10_BOOST_EN;
|
||||
desc->bypass_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
|
||||
PALMAS_SMPS10_CTRL);
|
||||
desc->bypass_val_on = SMPS10_BYPASS_EN;
|
||||
desc->bypass_mask = SMPS10_BYPASS_EN;
|
||||
desc->min_uV = 3750000;
|
||||
desc->uV_step = 1250000;
|
||||
@ -1462,10 +1467,10 @@ static struct palmas_pmic_driver_data tps65917_ddata = {
|
||||
.ldo_register = tps65917_ldo_registration,
|
||||
};
|
||||
|
||||
static void palmas_dt_to_pdata(struct device *dev,
|
||||
struct device_node *node,
|
||||
struct palmas_pmic_platform_data *pdata,
|
||||
struct palmas_pmic_driver_data *ddata)
|
||||
static int palmas_dt_to_pdata(struct device *dev,
|
||||
struct device_node *node,
|
||||
struct palmas_pmic_platform_data *pdata,
|
||||
struct palmas_pmic_driver_data *ddata)
|
||||
{
|
||||
struct device_node *regulators;
|
||||
u32 prop;
|
||||
@ -1474,7 +1479,7 @@ static void palmas_dt_to_pdata(struct device *dev,
|
||||
regulators = of_get_child_by_name(node, "regulators");
|
||||
if (!regulators) {
|
||||
dev_info(dev, "regulator node not found\n");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = of_regulator_match(dev, regulators, ddata->palmas_matches,
|
||||
@ -1482,25 +1487,29 @@ static void palmas_dt_to_pdata(struct device *dev,
|
||||
of_node_put(regulators);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error parsing regulator init data: %d\n", ret);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < ddata->max_reg; idx++) {
|
||||
if (!ddata->palmas_matches[idx].init_data ||
|
||||
!ddata->palmas_matches[idx].of_node)
|
||||
static struct of_regulator_match *match;
|
||||
struct palmas_reg_init *rinit;
|
||||
struct device_node *np;
|
||||
|
||||
match = &ddata->palmas_matches[idx];
|
||||
np = match->of_node;
|
||||
|
||||
if (!match->init_data || !np)
|
||||
continue;
|
||||
|
||||
pdata->reg_data[idx] = ddata->palmas_matches[idx].init_data;
|
||||
rinit = devm_kzalloc(dev, sizeof(*rinit), GFP_KERNEL);
|
||||
if (!rinit)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata->reg_init[idx] = devm_kzalloc(dev,
|
||||
sizeof(struct palmas_reg_init), GFP_KERNEL);
|
||||
pdata->reg_data[idx] = match->init_data;
|
||||
pdata->reg_init[idx] = rinit;
|
||||
|
||||
pdata->reg_init[idx]->warm_reset =
|
||||
of_property_read_bool(ddata->palmas_matches[idx].of_node,
|
||||
"ti,warm-reset");
|
||||
|
||||
ret = of_property_read_u32(ddata->palmas_matches[idx].of_node,
|
||||
"ti,roof-floor", &prop);
|
||||
rinit->warm_reset = of_property_read_bool(np, "ti,warm-reset");
|
||||
ret = of_property_read_u32(np, "ti,roof-floor", &prop);
|
||||
/* EINVAL: Property not found */
|
||||
if (ret != -EINVAL) {
|
||||
int econtrol;
|
||||
@ -1522,31 +1531,29 @@ static void palmas_dt_to_pdata(struct device *dev,
|
||||
WARN_ON(1);
|
||||
dev_warn(dev,
|
||||
"%s: Invalid roof-floor option: %u\n",
|
||||
palmas_matches[idx].name, prop);
|
||||
match->name, prop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pdata->reg_init[idx]->roof_floor = econtrol;
|
||||
rinit->roof_floor = econtrol;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(ddata->palmas_matches[idx].of_node,
|
||||
"ti,mode-sleep", &prop);
|
||||
ret = of_property_read_u32(np, "ti,mode-sleep", &prop);
|
||||
if (!ret)
|
||||
pdata->reg_init[idx]->mode_sleep = prop;
|
||||
rinit->mode_sleep = prop;
|
||||
|
||||
ret = of_property_read_bool(ddata->palmas_matches[idx].of_node,
|
||||
"ti,smps-range");
|
||||
ret = of_property_read_bool(np, "ti,smps-range");
|
||||
if (ret)
|
||||
pdata->reg_init[idx]->vsel =
|
||||
PALMAS_SMPS12_VOLTAGE_RANGE;
|
||||
rinit->vsel = PALMAS_SMPS12_VOLTAGE_RANGE;
|
||||
|
||||
if (idx == PALMAS_REG_LDO8)
|
||||
pdata->enable_ldo8_tracking = of_property_read_bool(
|
||||
ddata->palmas_matches[idx].of_node,
|
||||
"ti,enable-ldo8-tracking");
|
||||
np, "ti,enable-ldo8-tracking");
|
||||
}
|
||||
|
||||
pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_palmas_match_tbl[] = {
|
||||
@ -1628,7 +1635,9 @@ static int palmas_regulators_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, pmic);
|
||||
pmic->palmas->pmic_ddata = driver_data;
|
||||
|
||||
palmas_dt_to_pdata(&pdev->dev, node, pdata, driver_data);
|
||||
ret = palmas_dt_to_pdata(&pdev->dev, node, pdata, driver_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = palmas_smps_read(palmas, PALMAS_SMPS_CTRL, ®);
|
||||
if (ret)
|
||||
|
419
drivers/regulator/pv88080-regulator.c
Normal file
419
drivers/regulator/pv88080-regulator.c
Normal file
@ -0,0 +1,419 @@
|
||||
/*
|
||||
* pv88080-regulator.c - Regulator device driver for PV88080
|
||||
* Copyright (C) 2016 Powerventure Semiconductor Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "pv88080-regulator.h"
|
||||
|
||||
#define PV88080_MAX_REGULATORS 3
|
||||
|
||||
/* PV88080 REGULATOR IDs */
|
||||
enum {
|
||||
/* BUCKs */
|
||||
PV88080_ID_BUCK1,
|
||||
PV88080_ID_BUCK2,
|
||||
PV88080_ID_BUCK3,
|
||||
};
|
||||
|
||||
struct pv88080_regulator {
|
||||
struct regulator_desc desc;
|
||||
/* Current limiting */
|
||||
unsigned int n_current_limits;
|
||||
const int *current_limits;
|
||||
unsigned int limit_mask;
|
||||
unsigned int conf;
|
||||
unsigned int conf2;
|
||||
unsigned int conf5;
|
||||
};
|
||||
|
||||
struct pv88080 {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regulator_dev *rdev[PV88080_MAX_REGULATORS];
|
||||
};
|
||||
|
||||
struct pv88080_buck_voltage {
|
||||
int min_uV;
|
||||
int max_uV;
|
||||
int uV_step;
|
||||
};
|
||||
|
||||
static const struct regmap_config pv88080_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
/* Current limits array (in uA) for BUCK1, BUCK2, BUCK3.
|
||||
* Entry indexes corresponds to register values.
|
||||
*/
|
||||
|
||||
static const int pv88080_buck1_limits[] = {
|
||||
3230000, 5130000, 6960000, 8790000
|
||||
};
|
||||
|
||||
static const int pv88080_buck23_limits[] = {
|
||||
1496000, 2393000, 3291000, 4189000
|
||||
};
|
||||
|
||||
static const struct pv88080_buck_voltage pv88080_buck_vol[2] = {
|
||||
{
|
||||
.min_uV = 600000,
|
||||
.max_uV = 1393750,
|
||||
.uV_step = 6250,
|
||||
},
|
||||
{
|
||||
.min_uV = 1400000,
|
||||
.max_uV = 2193750,
|
||||
.uV_step = 6250,
|
||||
},
|
||||
};
|
||||
|
||||
static unsigned int pv88080_buck_get_mode(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pv88080_regulator *info = rdev_get_drvdata(rdev);
|
||||
unsigned int data;
|
||||
int ret, mode = 0;
|
||||
|
||||
ret = regmap_read(rdev->regmap, info->conf, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (data & PV88080_BUCK1_MODE_MASK) {
|
||||
case PV88080_BUCK_MODE_SYNC:
|
||||
mode = REGULATOR_MODE_FAST;
|
||||
break;
|
||||
case PV88080_BUCK_MODE_AUTO:
|
||||
mode = REGULATOR_MODE_NORMAL;
|
||||
break;
|
||||
case PV88080_BUCK_MODE_SLEEP:
|
||||
mode = REGULATOR_MODE_STANDBY;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int pv88080_buck_set_mode(struct regulator_dev *rdev,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct pv88080_regulator *info = rdev_get_drvdata(rdev);
|
||||
int val = 0;
|
||||
|
||||
switch (mode) {
|
||||
case REGULATOR_MODE_FAST:
|
||||
val = PV88080_BUCK_MODE_SYNC;
|
||||
break;
|
||||
case REGULATOR_MODE_NORMAL:
|
||||
val = PV88080_BUCK_MODE_AUTO;
|
||||
break;
|
||||
case REGULATOR_MODE_STANDBY:
|
||||
val = PV88080_BUCK_MODE_SLEEP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_update_bits(rdev->regmap, info->conf,
|
||||
PV88080_BUCK1_MODE_MASK, val);
|
||||
}
|
||||
|
||||
static int pv88080_set_current_limit(struct regulator_dev *rdev, int min,
|
||||
int max)
|
||||
{
|
||||
struct pv88080_regulator *info = rdev_get_drvdata(rdev);
|
||||
int i;
|
||||
|
||||
/* search for closest to maximum */
|
||||
for (i = info->n_current_limits; i >= 0; i--) {
|
||||
if (min <= info->current_limits[i]
|
||||
&& max >= info->current_limits[i]) {
|
||||
return regmap_update_bits(rdev->regmap,
|
||||
info->conf,
|
||||
info->limit_mask,
|
||||
i << PV88080_BUCK1_ILIM_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int pv88080_get_current_limit(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pv88080_regulator *info = rdev_get_drvdata(rdev);
|
||||
unsigned int data;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(rdev->regmap, info->conf, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data = (data & info->limit_mask) >> PV88080_BUCK1_ILIM_SHIFT;
|
||||
return info->current_limits[data];
|
||||
}
|
||||
|
||||
static struct regulator_ops pv88080_buck_ops = {
|
||||
.get_mode = pv88080_buck_get_mode,
|
||||
.set_mode = pv88080_buck_set_mode,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.set_current_limit = pv88080_set_current_limit,
|
||||
.get_current_limit = pv88080_get_current_limit,
|
||||
};
|
||||
|
||||
#define PV88080_BUCK(chip, regl_name, min, step, max, limits_array) \
|
||||
{\
|
||||
.desc = {\
|
||||
.id = chip##_ID_##regl_name,\
|
||||
.name = __stringify(chip##_##regl_name),\
|
||||
.of_match = of_match_ptr(#regl_name),\
|
||||
.regulators_node = of_match_ptr("regulators"),\
|
||||
.type = REGULATOR_VOLTAGE,\
|
||||
.owner = THIS_MODULE,\
|
||||
.ops = &pv88080_buck_ops,\
|
||||
.min_uV = min, \
|
||||
.uV_step = step, \
|
||||
.n_voltages = ((max) - (min))/(step) + 1, \
|
||||
.enable_reg = PV88080_REG_##regl_name##_CONF0, \
|
||||
.enable_mask = PV88080_##regl_name##_EN, \
|
||||
.vsel_reg = PV88080_REG_##regl_name##_CONF0, \
|
||||
.vsel_mask = PV88080_V##regl_name##_MASK, \
|
||||
},\
|
||||
.current_limits = limits_array, \
|
||||
.n_current_limits = ARRAY_SIZE(limits_array), \
|
||||
.limit_mask = PV88080_##regl_name##_ILIM_MASK, \
|
||||
.conf = PV88080_REG_##regl_name##_CONF1, \
|
||||
.conf2 = PV88080_REG_##regl_name##_CONF2, \
|
||||
.conf5 = PV88080_REG_##regl_name##_CONF5, \
|
||||
}
|
||||
|
||||
static struct pv88080_regulator pv88080_regulator_info[] = {
|
||||
PV88080_BUCK(PV88080, BUCK1, 600000, 6250, 1393750,
|
||||
pv88080_buck1_limits),
|
||||
PV88080_BUCK(PV88080, BUCK2, 600000, 6250, 1393750,
|
||||
pv88080_buck23_limits),
|
||||
PV88080_BUCK(PV88080, BUCK3, 600000, 6250, 1393750,
|
||||
pv88080_buck23_limits),
|
||||
};
|
||||
|
||||
static irqreturn_t pv88080_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct pv88080 *chip = data;
|
||||
int i, reg_val, err, ret = IRQ_NONE;
|
||||
|
||||
err = regmap_read(chip->regmap, PV88080_REG_EVENT_A, ®_val);
|
||||
if (err < 0)
|
||||
goto error_i2c;
|
||||
|
||||
if (reg_val & PV88080_E_VDD_FLT) {
|
||||
for (i = 0; i < PV88080_MAX_REGULATORS; i++) {
|
||||
if (chip->rdev[i] != NULL) {
|
||||
regulator_notifier_call_chain(chip->rdev[i],
|
||||
REGULATOR_EVENT_UNDER_VOLTAGE,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
err = regmap_write(chip->regmap, PV88080_REG_EVENT_A,
|
||||
PV88080_E_VDD_FLT);
|
||||
if (err < 0)
|
||||
goto error_i2c;
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (reg_val & PV88080_E_OVER_TEMP) {
|
||||
for (i = 0; i < PV88080_MAX_REGULATORS; i++) {
|
||||
if (chip->rdev[i] != NULL) {
|
||||
regulator_notifier_call_chain(chip->rdev[i],
|
||||
REGULATOR_EVENT_OVER_TEMP,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
err = regmap_write(chip->regmap, PV88080_REG_EVENT_A,
|
||||
PV88080_E_OVER_TEMP);
|
||||
if (err < 0)
|
||||
goto error_i2c;
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error_i2c:
|
||||
dev_err(chip->dev, "I2C error : %d\n", err);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C driver interface functions
|
||||
*/
|
||||
static int pv88080_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
|
||||
struct pv88080 *chip;
|
||||
struct regulator_config config = { };
|
||||
int i, error, ret;
|
||||
unsigned int conf2, conf5;
|
||||
|
||||
chip = devm_kzalloc(&i2c->dev, sizeof(struct pv88080), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->dev = &i2c->dev;
|
||||
chip->regmap = devm_regmap_init_i2c(i2c, &pv88080_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
error = PTR_ERR(chip->regmap);
|
||||
dev_err(chip->dev, "Failed to allocate register map: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, chip);
|
||||
|
||||
if (i2c->irq != 0) {
|
||||
ret = regmap_write(chip->regmap, PV88080_REG_MASK_A, 0xFF);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to mask A reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = regmap_write(chip->regmap, PV88080_REG_MASK_B, 0xFF);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to mask B reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = regmap_write(chip->regmap, PV88080_REG_MASK_C, 0xFF);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to mask C reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
|
||||
pv88080_irq_handler,
|
||||
IRQF_TRIGGER_LOW|IRQF_ONESHOT,
|
||||
"pv88080", chip);
|
||||
if (ret != 0) {
|
||||
dev_err(chip->dev, "Failed to request IRQ: %d\n",
|
||||
i2c->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(chip->regmap, PV88080_REG_MASK_A,
|
||||
PV88080_M_VDD_FLT | PV88080_M_OVER_TEMP, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to update mask reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} else {
|
||||
dev_warn(chip->dev, "No IRQ configured\n");
|
||||
}
|
||||
|
||||
config.dev = chip->dev;
|
||||
config.regmap = chip->regmap;
|
||||
|
||||
for (i = 0; i < PV88080_MAX_REGULATORS; i++) {
|
||||
if (init_data)
|
||||
config.init_data = &init_data[i];
|
||||
|
||||
ret = regmap_read(chip->regmap,
|
||||
pv88080_regulator_info[i].conf2, &conf2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
conf2 = ((conf2 >> PV88080_BUCK_VDAC_RANGE_SHIFT) &
|
||||
PV88080_BUCK_VDAC_RANGE_MASK);
|
||||
|
||||
ret = regmap_read(chip->regmap,
|
||||
pv88080_regulator_info[i].conf5, &conf5);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
conf5 = ((conf5 >> PV88080_BUCK_VRANGE_GAIN_SHIFT) &
|
||||
PV88080_BUCK_VRANGE_GAIN_MASK);
|
||||
|
||||
pv88080_regulator_info[i].desc.min_uV =
|
||||
pv88080_buck_vol[conf2].min_uV * (conf5+1);
|
||||
pv88080_regulator_info[i].desc.uV_step =
|
||||
pv88080_buck_vol[conf2].uV_step * (conf5+1);
|
||||
pv88080_regulator_info[i].desc.n_voltages =
|
||||
((pv88080_buck_vol[conf2].max_uV * (conf5+1))
|
||||
- (pv88080_regulator_info[i].desc.min_uV))
|
||||
/(pv88080_regulator_info[i].desc.uV_step) + 1;
|
||||
|
||||
config.driver_data = (void *)&pv88080_regulator_info[i];
|
||||
chip->rdev[i] = devm_regulator_register(chip->dev,
|
||||
&pv88080_regulator_info[i].desc, &config);
|
||||
if (IS_ERR(chip->rdev[i])) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to register PV88080 regulator\n");
|
||||
return PTR_ERR(chip->rdev[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id pv88080_i2c_id[] = {
|
||||
{"pv88080", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pv88080_i2c_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id pv88080_dt_ids[] = {
|
||||
{ .compatible = "pvs,pv88080", .data = &pv88080_i2c_id[0] },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pv88080_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver pv88080_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "pv88080",
|
||||
.of_match_table = of_match_ptr(pv88080_dt_ids),
|
||||
},
|
||||
.probe = pv88080_i2c_probe,
|
||||
.id_table = pv88080_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(pv88080_regulator_driver);
|
||||
|
||||
MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
|
||||
MODULE_DESCRIPTION("Regulator device driver for Powerventure PV88080");
|
||||
MODULE_LICENSE("GPL");
|
92
drivers/regulator/pv88080-regulator.h
Normal file
92
drivers/regulator/pv88080-regulator.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* pv88080-regulator.h - Regulator definitions for PV88080
|
||||
* Copyright (C) 2016 Powerventure Semiconductor Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __PV88080_REGISTERS_H__
|
||||
#define __PV88080_REGISTERS_H__
|
||||
|
||||
/* System Control and Event Registers */
|
||||
#define PV88080_REG_EVENT_A 0x04
|
||||
#define PV88080_REG_MASK_A 0x09
|
||||
#define PV88080_REG_MASK_B 0x0a
|
||||
#define PV88080_REG_MASK_C 0x0b
|
||||
|
||||
/* Regulator Registers */
|
||||
#define PV88080_REG_BUCK1_CONF0 0x27
|
||||
#define PV88080_REG_BUCK1_CONF1 0x28
|
||||
#define PV88080_REG_BUCK1_CONF2 0x59
|
||||
#define PV88080_REG_BUCK1_CONF5 0x5c
|
||||
#define PV88080_REG_BUCK2_CONF0 0x29
|
||||
#define PV88080_REG_BUCK2_CONF1 0x2a
|
||||
#define PV88080_REG_BUCK2_CONF2 0x61
|
||||
#define PV88080_REG_BUCK2_CONF5 0x64
|
||||
#define PV88080_REG_BUCK3_CONF0 0x2b
|
||||
#define PV88080_REG_BUCK3_CONF1 0x2c
|
||||
#define PV88080_REG_BUCK3_CONF2 0x69
|
||||
#define PV88080_REG_BUCK3_CONF5 0x6c
|
||||
|
||||
/* PV88080_REG_EVENT_A (addr=0x04) */
|
||||
#define PV88080_E_VDD_FLT 0x01
|
||||
#define PV88080_E_OVER_TEMP 0x02
|
||||
|
||||
/* PV88080_REG_MASK_A (addr=0x09) */
|
||||
#define PV88080_M_VDD_FLT 0x01
|
||||
#define PV88080_M_OVER_TEMP 0x02
|
||||
|
||||
/* PV88080_REG_BUCK1_CONF0 (addr=0x27) */
|
||||
#define PV88080_BUCK1_EN 0x80
|
||||
#define PV88080_VBUCK1_MASK 0x7F
|
||||
/* PV88080_REG_BUCK2_CONF0 (addr=0x29) */
|
||||
#define PV88080_BUCK2_EN 0x80
|
||||
#define PV88080_VBUCK2_MASK 0x7F
|
||||
/* PV88080_REG_BUCK3_CONF0 (addr=0x2b) */
|
||||
#define PV88080_BUCK3_EN 0x80
|
||||
#define PV88080_VBUCK3_MASK 0x7F
|
||||
|
||||
/* PV88080_REG_BUCK1_CONF1 (addr=0x28) */
|
||||
#define PV88080_BUCK1_ILIM_SHIFT 2
|
||||
#define PV88080_BUCK1_ILIM_MASK 0x0C
|
||||
#define PV88080_BUCK1_MODE_MASK 0x03
|
||||
|
||||
/* PV88080_REG_BUCK2_CONF1 (addr=0x2a) */
|
||||
#define PV88080_BUCK2_ILIM_SHIFT 2
|
||||
#define PV88080_BUCK2_ILIM_MASK 0x0C
|
||||
#define PV88080_BUCK2_MODE_MASK 0x03
|
||||
|
||||
/* PV88080_REG_BUCK3_CONF1 (addr=0x2c) */
|
||||
#define PV88080_BUCK3_ILIM_SHIFT 2
|
||||
#define PV88080_BUCK3_ILIM_MASK 0x0C
|
||||
#define PV88080_BUCK3_MODE_MASK 0x03
|
||||
|
||||
#define PV88080_BUCK_MODE_SLEEP 0x00
|
||||
#define PV88080_BUCK_MODE_AUTO 0x01
|
||||
#define PV88080_BUCK_MODE_SYNC 0x02
|
||||
|
||||
/* PV88080_REG_BUCK2_CONF2 (addr=0x61) */
|
||||
/* PV88080_REG_BUCK3_CONF2 (addr=0x69) */
|
||||
#define PV88080_BUCK_VDAC_RANGE_SHIFT 7
|
||||
#define PV88080_BUCK_VDAC_RANGE_MASK 0x01
|
||||
|
||||
#define PV88080_BUCK_VDAC_RANGE_1 0x00
|
||||
#define PV88080_BUCK_VDAC_RANGE_2 0x01
|
||||
|
||||
/* PV88080_REG_BUCK2_CONF5 (addr=0x64) */
|
||||
/* PV88080_REG_BUCK3_CONF5 (addr=0x6c) */
|
||||
#define PV88080_BUCK_VRANGE_GAIN_SHIFT 0
|
||||
#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01
|
||||
|
||||
#define PV88080_BUCK_VRANGE_GAIN_1 0x00
|
||||
#define PV88080_BUCK_VRANGE_GAIN_2 0x01
|
||||
|
||||
#endif /* __PV88080_REGISTERS_H__ */
|
@ -59,18 +59,18 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
|
||||
unsigned int pwm_reg_period;
|
||||
struct pwm_args pargs;
|
||||
int dutycycle;
|
||||
int ret;
|
||||
|
||||
pwm_reg_period = pwm_get_period(drvdata->pwm);
|
||||
pwm_get_args(drvdata->pwm, &pargs);
|
||||
|
||||
dutycycle = (pwm_reg_period *
|
||||
dutycycle = (pargs.period *
|
||||
drvdata->duty_cycle_table[selector].dutycycle) / 100;
|
||||
|
||||
ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period);
|
||||
ret = pwm_config(drvdata->pwm, dutycycle, pargs.period);
|
||||
if (ret) {
|
||||
dev_err(&rdev->dev, "Failed to configure PWM\n");
|
||||
dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -113,18 +113,6 @@ static int pwm_regulator_is_enabled(struct regulator_dev *dev)
|
||||
return pwm_is_enabled(drvdata->pwm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continuous voltage call-backs
|
||||
*/
|
||||
static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int req_uV)
|
||||
{
|
||||
int min_uV = rdev->constraints->min_uV;
|
||||
int max_uV = rdev->constraints->max_uV;
|
||||
int diff = max_uV - min_uV;
|
||||
|
||||
return ((req_uV * 100) - (min_uV * 100)) / diff;
|
||||
}
|
||||
|
||||
static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
|
||||
{
|
||||
struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
|
||||
@ -138,21 +126,42 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
|
||||
{
|
||||
struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
|
||||
unsigned int ramp_delay = rdev->constraints->ramp_delay;
|
||||
unsigned int period = pwm_get_period(drvdata->pwm);
|
||||
int duty_cycle;
|
||||
struct pwm_args pargs;
|
||||
unsigned int req_diff = min_uV - rdev->constraints->min_uV;
|
||||
unsigned int diff;
|
||||
unsigned int duty_pulse;
|
||||
u64 req_period;
|
||||
u32 rem;
|
||||
int ret;
|
||||
|
||||
duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV);
|
||||
pwm_get_args(drvdata->pwm, &pargs);
|
||||
diff = rdev->constraints->max_uV - rdev->constraints->min_uV;
|
||||
|
||||
ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period);
|
||||
/* First try to find out if we get the iduty cycle time which is
|
||||
* factor of PWM period time. If (request_diff_to_min * pwm_period)
|
||||
* is perfect divided by voltage_range_diff then it is possible to
|
||||
* get duty cycle time which is factor of PWM period. This will help
|
||||
* to get output voltage nearer to requested value as there is no
|
||||
* calculation loss.
|
||||
*/
|
||||
req_period = req_diff * pargs.period;
|
||||
div_u64_rem(req_period, diff, &rem);
|
||||
if (!rem) {
|
||||
do_div(req_period, diff);
|
||||
duty_pulse = (unsigned int)req_period;
|
||||
} else {
|
||||
duty_pulse = (pargs.period / 100) * ((req_diff * 100) / diff);
|
||||
}
|
||||
|
||||
ret = pwm_config(drvdata->pwm, duty_pulse, pargs.period);
|
||||
if (ret) {
|
||||
dev_err(&rdev->dev, "Failed to configure PWM\n");
|
||||
dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pwm_enable(drvdata->pwm);
|
||||
if (ret) {
|
||||
dev_err(&rdev->dev, "Failed to enable PWM\n");
|
||||
dev_err(&rdev->dev, "Failed to enable PWM: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
drvdata->volt_uV = min_uV;
|
||||
@ -200,8 +209,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
|
||||
|
||||
if ((length < sizeof(*duty_cycle_table)) ||
|
||||
(length % sizeof(*duty_cycle_table))) {
|
||||
dev_err(&pdev->dev,
|
||||
"voltage-table length(%d) is invalid\n",
|
||||
dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n",
|
||||
length);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -214,7 +222,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
|
||||
(u32 *)duty_cycle_table,
|
||||
length / sizeof(u32));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to read voltage-table\n");
|
||||
dev_err(&pdev->dev, "Failed to read voltage-table: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -277,16 +285,24 @@ static int pwm_regulator_probe(struct platform_device *pdev)
|
||||
|
||||
drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(drvdata->pwm)) {
|
||||
dev_err(&pdev->dev, "Failed to get PWM\n");
|
||||
return PTR_ERR(drvdata->pwm);
|
||||
ret = PTR_ERR(drvdata->pwm);
|
||||
dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: pwm_apply_args() should be removed when switching to the
|
||||
* atomic PWM API.
|
||||
*/
|
||||
pwm_apply_args(drvdata->pwm);
|
||||
|
||||
regulator = devm_regulator_register(&pdev->dev,
|
||||
&drvdata->desc, &config);
|
||||
if (IS_ERR(regulator)) {
|
||||
dev_err(&pdev->dev, "Failed to register regulator %s\n",
|
||||
drvdata->desc.name);
|
||||
return PTR_ERR(regulator);
|
||||
ret = PTR_ERR(regulator);
|
||||
dev_err(&pdev->dev, "Failed to register regulator %s: %d\n",
|
||||
drvdata->desc.name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -246,6 +246,7 @@ enum spmi_common_control_register_index {
|
||||
|
||||
/* Minimum voltage stepper delay for each step. */
|
||||
#define SPMI_FTSMPS_STEP_DELAY 8
|
||||
#define SPMI_DEFAULT_STEP_DELAY 20
|
||||
|
||||
/*
|
||||
* The ratio SPMI_FTSMPS_STEP_MARGIN_NUM/SPMI_FTSMPS_STEP_MARGIN_DEN is used to
|
||||
@ -254,13 +255,6 @@ enum spmi_common_control_register_index {
|
||||
#define SPMI_FTSMPS_STEP_MARGIN_NUM 4
|
||||
#define SPMI_FTSMPS_STEP_MARGIN_DEN 5
|
||||
|
||||
/*
|
||||
* This voltage in uV is returned by get_voltage functions when there is no way
|
||||
* to determine the current voltage level. It is needed because the regulator
|
||||
* framework treats a 0 uV voltage as an error.
|
||||
*/
|
||||
#define VOLTAGE_UNKNOWN 1
|
||||
|
||||
/* VSET value to decide the range of ULT SMPS */
|
||||
#define ULT_SMPS_RANGE_SPLIT 0x60
|
||||
|
||||
@ -539,12 +533,12 @@ static int spmi_regulator_common_disable(struct regulator_dev *rdev)
|
||||
}
|
||||
|
||||
static int spmi_regulator_select_voltage(struct spmi_regulator *vreg,
|
||||
int min_uV, int max_uV, u8 *range_sel, u8 *voltage_sel,
|
||||
unsigned *selector)
|
||||
int min_uV, int max_uV)
|
||||
{
|
||||
const struct spmi_voltage_range *range;
|
||||
int uV = min_uV;
|
||||
int lim_min_uV, lim_max_uV, i, range_id, range_max_uV;
|
||||
int selector, voltage_sel;
|
||||
|
||||
/* Check if request voltage is outside of physically settable range. */
|
||||
lim_min_uV = vreg->set_points->range[0].set_point_min_uV;
|
||||
@ -570,14 +564,13 @@ static int spmi_regulator_select_voltage(struct spmi_regulator *vreg,
|
||||
|
||||
range_id = i;
|
||||
range = &vreg->set_points->range[range_id];
|
||||
*range_sel = range->range_sel;
|
||||
|
||||
/*
|
||||
* Force uV to be an allowed set point by applying a ceiling function to
|
||||
* the uV value.
|
||||
*/
|
||||
*voltage_sel = DIV_ROUND_UP(uV - range->min_uV, range->step_uV);
|
||||
uV = *voltage_sel * range->step_uV + range->min_uV;
|
||||
voltage_sel = DIV_ROUND_UP(uV - range->min_uV, range->step_uV);
|
||||
uV = voltage_sel * range->step_uV + range->min_uV;
|
||||
|
||||
if (uV > max_uV) {
|
||||
dev_err(vreg->dev,
|
||||
@ -587,12 +580,48 @@ static int spmi_regulator_select_voltage(struct spmi_regulator *vreg,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*selector = 0;
|
||||
selector = 0;
|
||||
for (i = 0; i < range_id; i++)
|
||||
*selector += vreg->set_points->range[i].n_voltages;
|
||||
*selector += (uV - range->set_point_min_uV) / range->step_uV;
|
||||
selector += vreg->set_points->range[i].n_voltages;
|
||||
selector += (uV - range->set_point_min_uV) / range->step_uV;
|
||||
|
||||
return 0;
|
||||
return selector;
|
||||
}
|
||||
|
||||
static int spmi_sw_selector_to_hw(struct spmi_regulator *vreg,
|
||||
unsigned selector, u8 *range_sel,
|
||||
u8 *voltage_sel)
|
||||
{
|
||||
const struct spmi_voltage_range *range, *end;
|
||||
|
||||
range = vreg->set_points->range;
|
||||
end = range + vreg->set_points->count;
|
||||
|
||||
for (; range < end; range++) {
|
||||
if (selector < range->n_voltages) {
|
||||
*voltage_sel = selector;
|
||||
*range_sel = range->range_sel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
selector -= range->n_voltages;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int spmi_hw_selector_to_sw(struct spmi_regulator *vreg, u8 hw_sel,
|
||||
const struct spmi_voltage_range *range)
|
||||
{
|
||||
int sw_sel = hw_sel;
|
||||
const struct spmi_voltage_range *r = vreg->set_points->range;
|
||||
|
||||
while (r != range) {
|
||||
sw_sel += r->n_voltages;
|
||||
r++;
|
||||
}
|
||||
|
||||
return sw_sel;
|
||||
}
|
||||
|
||||
static const struct spmi_voltage_range *
|
||||
@ -614,12 +643,11 @@ spmi_regulator_find_range(struct spmi_regulator *vreg)
|
||||
}
|
||||
|
||||
static int spmi_regulator_select_voltage_same_range(struct spmi_regulator *vreg,
|
||||
int min_uV, int max_uV, u8 *range_sel, u8 *voltage_sel,
|
||||
unsigned *selector)
|
||||
int min_uV, int max_uV)
|
||||
{
|
||||
const struct spmi_voltage_range *range;
|
||||
int uV = min_uV;
|
||||
int i;
|
||||
int i, selector;
|
||||
|
||||
range = spmi_regulator_find_range(vreg);
|
||||
if (!range)
|
||||
@ -637,8 +665,8 @@ static int spmi_regulator_select_voltage_same_range(struct spmi_regulator *vreg,
|
||||
* Force uV to be an allowed set point by applying a ceiling function to
|
||||
* the uV value.
|
||||
*/
|
||||
*voltage_sel = DIV_ROUND_UP(uV - range->min_uV, range->step_uV);
|
||||
uV = *voltage_sel * range->step_uV + range->min_uV;
|
||||
uV = DIV_ROUND_UP(uV - range->min_uV, range->step_uV);
|
||||
uV = uV * range->step_uV + range->min_uV;
|
||||
|
||||
if (uV > max_uV) {
|
||||
/*
|
||||
@ -648,43 +676,49 @@ static int spmi_regulator_select_voltage_same_range(struct spmi_regulator *vreg,
|
||||
goto different_range;
|
||||
}
|
||||
|
||||
*selector = 0;
|
||||
selector = 0;
|
||||
for (i = 0; i < vreg->set_points->count; i++) {
|
||||
if (uV >= vreg->set_points->range[i].set_point_min_uV
|
||||
&& uV <= vreg->set_points->range[i].set_point_max_uV) {
|
||||
*selector +=
|
||||
selector +=
|
||||
(uV - vreg->set_points->range[i].set_point_min_uV)
|
||||
/ vreg->set_points->range[i].step_uV;
|
||||
break;
|
||||
}
|
||||
|
||||
*selector += vreg->set_points->range[i].n_voltages;
|
||||
selector += vreg->set_points->range[i].n_voltages;
|
||||
}
|
||||
|
||||
if (*selector >= vreg->set_points->n_voltages)
|
||||
if (selector >= vreg->set_points->n_voltages)
|
||||
goto different_range;
|
||||
|
||||
return 0;
|
||||
return selector;
|
||||
|
||||
different_range:
|
||||
return spmi_regulator_select_voltage(vreg, min_uV, max_uV,
|
||||
range_sel, voltage_sel, selector);
|
||||
return spmi_regulator_select_voltage(vreg, min_uV, max_uV);
|
||||
}
|
||||
|
||||
static int spmi_regulator_common_set_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV, unsigned *selector)
|
||||
static int spmi_regulator_common_map_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
|
||||
/*
|
||||
* Favor staying in the current voltage range if possible. This avoids
|
||||
* voltage spikes that occur when changing the voltage range.
|
||||
*/
|
||||
return spmi_regulator_select_voltage_same_range(vreg, min_uV, max_uV);
|
||||
}
|
||||
|
||||
static int
|
||||
spmi_regulator_common_set_voltage(struct regulator_dev *rdev, unsigned selector)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
u8 buf[2];
|
||||
u8 range_sel, voltage_sel;
|
||||
|
||||
/*
|
||||
* Favor staying in the current voltage range if possible. This avoids
|
||||
* voltage spikes that occur when changing the voltage range.
|
||||
*/
|
||||
ret = spmi_regulator_select_voltage_same_range(vreg, min_uV, max_uV,
|
||||
&range_sel, &voltage_sel, selector);
|
||||
ret = spmi_sw_selector_to_hw(vreg, selector, &range_sel, &voltage_sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -719,24 +753,24 @@ static int spmi_regulator_common_get_voltage(struct regulator_dev *rdev)
|
||||
|
||||
range = spmi_regulator_find_range(vreg);
|
||||
if (!range)
|
||||
return VOLTAGE_UNKNOWN;
|
||||
return -EINVAL;
|
||||
|
||||
return range->step_uV * voltage_sel + range->min_uV;
|
||||
return spmi_hw_selector_to_sw(vreg, voltage_sel, range);
|
||||
}
|
||||
|
||||
static int spmi_regulator_single_map_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
|
||||
return spmi_regulator_select_voltage(vreg, min_uV, max_uV);
|
||||
}
|
||||
|
||||
static int spmi_regulator_single_range_set_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV, unsigned *selector)
|
||||
unsigned selector)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
u8 range_sel, sel;
|
||||
|
||||
ret = spmi_regulator_select_voltage(vreg, min_uV, max_uV, &range_sel,
|
||||
&sel, selector);
|
||||
if (ret) {
|
||||
dev_err(vreg->dev, "could not set voltage, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
u8 sel = selector;
|
||||
|
||||
/*
|
||||
* Certain types of regulators do not have a range select register so
|
||||
@ -748,27 +782,24 @@ static int spmi_regulator_single_range_set_voltage(struct regulator_dev *rdev,
|
||||
static int spmi_regulator_single_range_get_voltage(struct regulator_dev *rdev)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
const struct spmi_voltage_range *range = vreg->set_points->range;
|
||||
u8 voltage_sel;
|
||||
u8 selector;
|
||||
int ret;
|
||||
|
||||
spmi_vreg_read(vreg, SPMI_COMMON_REG_VOLTAGE_SET, &voltage_sel, 1);
|
||||
ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_VOLTAGE_SET, &selector, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return range->step_uV * voltage_sel + range->min_uV;
|
||||
return selector;
|
||||
}
|
||||
|
||||
static int spmi_regulator_ult_lo_smps_set_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV, unsigned *selector)
|
||||
unsigned selector)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
u8 range_sel, voltage_sel;
|
||||
|
||||
/*
|
||||
* Favor staying in the current voltage range if possible. This avoids
|
||||
* voltage spikes that occur when changing the voltage range.
|
||||
*/
|
||||
ret = spmi_regulator_select_voltage_same_range(vreg, min_uV, max_uV,
|
||||
&range_sel, &voltage_sel, selector);
|
||||
ret = spmi_sw_selector_to_hw(vreg, selector, &range_sel, &voltage_sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -783,7 +814,7 @@ static int spmi_regulator_ult_lo_smps_set_voltage(struct regulator_dev *rdev,
|
||||
voltage_sel |= ULT_SMPS_RANGE_SPLIT;
|
||||
|
||||
return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_VOLTAGE_SET,
|
||||
voltage_sel, 0xff);
|
||||
voltage_sel, 0xff);
|
||||
}
|
||||
|
||||
static int spmi_regulator_ult_lo_smps_get_voltage(struct regulator_dev *rdev)
|
||||
@ -796,12 +827,12 @@ static int spmi_regulator_ult_lo_smps_get_voltage(struct regulator_dev *rdev)
|
||||
|
||||
range = spmi_regulator_find_range(vreg);
|
||||
if (!range)
|
||||
return VOLTAGE_UNKNOWN;
|
||||
return -EINVAL;
|
||||
|
||||
if (range->range_sel == 1)
|
||||
voltage_sel &= ~ULT_SMPS_RANGE_SPLIT;
|
||||
|
||||
return range->step_uV * voltage_sel + range->min_uV;
|
||||
return spmi_hw_selector_to_sw(vreg, voltage_sel, range);
|
||||
}
|
||||
|
||||
static int spmi_regulator_common_list_voltage(struct regulator_dev *rdev,
|
||||
@ -1007,8 +1038,10 @@ static struct regulator_ops spmi_smps_ops = {
|
||||
.enable = spmi_regulator_common_enable,
|
||||
.disable = spmi_regulator_common_disable,
|
||||
.is_enabled = spmi_regulator_common_is_enabled,
|
||||
.set_voltage = spmi_regulator_common_set_voltage,
|
||||
.get_voltage = spmi_regulator_common_get_voltage,
|
||||
.set_voltage_sel = spmi_regulator_common_set_voltage,
|
||||
.set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
|
||||
.get_voltage_sel = spmi_regulator_common_get_voltage,
|
||||
.map_voltage = spmi_regulator_common_map_voltage,
|
||||
.list_voltage = spmi_regulator_common_list_voltage,
|
||||
.set_mode = spmi_regulator_common_set_mode,
|
||||
.get_mode = spmi_regulator_common_get_mode,
|
||||
@ -1020,8 +1053,9 @@ static struct regulator_ops spmi_ldo_ops = {
|
||||
.enable = spmi_regulator_common_enable,
|
||||
.disable = spmi_regulator_common_disable,
|
||||
.is_enabled = spmi_regulator_common_is_enabled,
|
||||
.set_voltage = spmi_regulator_common_set_voltage,
|
||||
.get_voltage = spmi_regulator_common_get_voltage,
|
||||
.set_voltage_sel = spmi_regulator_common_set_voltage,
|
||||
.get_voltage_sel = spmi_regulator_common_get_voltage,
|
||||
.map_voltage = spmi_regulator_common_map_voltage,
|
||||
.list_voltage = spmi_regulator_common_list_voltage,
|
||||
.set_mode = spmi_regulator_common_set_mode,
|
||||
.get_mode = spmi_regulator_common_get_mode,
|
||||
@ -1036,8 +1070,9 @@ static struct regulator_ops spmi_ln_ldo_ops = {
|
||||
.enable = spmi_regulator_common_enable,
|
||||
.disable = spmi_regulator_common_disable,
|
||||
.is_enabled = spmi_regulator_common_is_enabled,
|
||||
.set_voltage = spmi_regulator_common_set_voltage,
|
||||
.get_voltage = spmi_regulator_common_get_voltage,
|
||||
.set_voltage_sel = spmi_regulator_common_set_voltage,
|
||||
.get_voltage_sel = spmi_regulator_common_get_voltage,
|
||||
.map_voltage = spmi_regulator_common_map_voltage,
|
||||
.list_voltage = spmi_regulator_common_list_voltage,
|
||||
.set_bypass = spmi_regulator_common_set_bypass,
|
||||
.get_bypass = spmi_regulator_common_get_bypass,
|
||||
@ -1056,8 +1091,9 @@ static struct regulator_ops spmi_boost_ops = {
|
||||
.enable = spmi_regulator_common_enable,
|
||||
.disable = spmi_regulator_common_disable,
|
||||
.is_enabled = spmi_regulator_common_is_enabled,
|
||||
.set_voltage = spmi_regulator_single_range_set_voltage,
|
||||
.get_voltage = spmi_regulator_single_range_get_voltage,
|
||||
.set_voltage_sel = spmi_regulator_single_range_set_voltage,
|
||||
.get_voltage_sel = spmi_regulator_single_range_get_voltage,
|
||||
.map_voltage = spmi_regulator_single_map_voltage,
|
||||
.list_voltage = spmi_regulator_common_list_voltage,
|
||||
.set_input_current_limit = spmi_regulator_set_ilim,
|
||||
};
|
||||
@ -1066,9 +1102,10 @@ static struct regulator_ops spmi_ftsmps_ops = {
|
||||
.enable = spmi_regulator_common_enable,
|
||||
.disable = spmi_regulator_common_disable,
|
||||
.is_enabled = spmi_regulator_common_is_enabled,
|
||||
.set_voltage = spmi_regulator_common_set_voltage,
|
||||
.set_voltage_sel = spmi_regulator_common_set_voltage,
|
||||
.set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
|
||||
.get_voltage = spmi_regulator_common_get_voltage,
|
||||
.get_voltage_sel = spmi_regulator_common_get_voltage,
|
||||
.map_voltage = spmi_regulator_common_map_voltage,
|
||||
.list_voltage = spmi_regulator_common_list_voltage,
|
||||
.set_mode = spmi_regulator_common_set_mode,
|
||||
.get_mode = spmi_regulator_common_get_mode,
|
||||
@ -1080,8 +1117,9 @@ static struct regulator_ops spmi_ult_lo_smps_ops = {
|
||||
.enable = spmi_regulator_common_enable,
|
||||
.disable = spmi_regulator_common_disable,
|
||||
.is_enabled = spmi_regulator_common_is_enabled,
|
||||
.set_voltage = spmi_regulator_ult_lo_smps_set_voltage,
|
||||
.get_voltage = spmi_regulator_ult_lo_smps_get_voltage,
|
||||
.set_voltage_sel = spmi_regulator_ult_lo_smps_set_voltage,
|
||||
.set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
|
||||
.get_voltage_sel = spmi_regulator_ult_lo_smps_get_voltage,
|
||||
.list_voltage = spmi_regulator_common_list_voltage,
|
||||
.set_mode = spmi_regulator_common_set_mode,
|
||||
.get_mode = spmi_regulator_common_get_mode,
|
||||
@ -1093,8 +1131,10 @@ static struct regulator_ops spmi_ult_ho_smps_ops = {
|
||||
.enable = spmi_regulator_common_enable,
|
||||
.disable = spmi_regulator_common_disable,
|
||||
.is_enabled = spmi_regulator_common_is_enabled,
|
||||
.set_voltage = spmi_regulator_single_range_set_voltage,
|
||||
.get_voltage = spmi_regulator_single_range_get_voltage,
|
||||
.set_voltage_sel = spmi_regulator_single_range_set_voltage,
|
||||
.set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
|
||||
.get_voltage_sel = spmi_regulator_single_range_get_voltage,
|
||||
.map_voltage = spmi_regulator_single_map_voltage,
|
||||
.list_voltage = spmi_regulator_common_list_voltage,
|
||||
.set_mode = spmi_regulator_common_set_mode,
|
||||
.get_mode = spmi_regulator_common_get_mode,
|
||||
@ -1106,8 +1146,9 @@ static struct regulator_ops spmi_ult_ldo_ops = {
|
||||
.enable = spmi_regulator_common_enable,
|
||||
.disable = spmi_regulator_common_disable,
|
||||
.is_enabled = spmi_regulator_common_is_enabled,
|
||||
.set_voltage = spmi_regulator_single_range_set_voltage,
|
||||
.get_voltage = spmi_regulator_single_range_get_voltage,
|
||||
.set_voltage_sel = spmi_regulator_single_range_set_voltage,
|
||||
.get_voltage_sel = spmi_regulator_single_range_get_voltage,
|
||||
.map_voltage = spmi_regulator_single_map_voltage,
|
||||
.list_voltage = spmi_regulator_common_list_voltage,
|
||||
.set_mode = spmi_regulator_common_set_mode,
|
||||
.get_mode = spmi_regulator_common_get_mode,
|
||||
@ -1201,7 +1242,7 @@ static int spmi_regulator_match(struct spmi_regulator *vreg, u16 force_type)
|
||||
ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_DIG_MAJOR_REV, version,
|
||||
ARRAY_SIZE(version));
|
||||
if (ret) {
|
||||
dev_err(vreg->dev, "could not read version registers\n");
|
||||
dev_dbg(vreg->dev, "could not read version registers\n");
|
||||
return ret;
|
||||
}
|
||||
dig_major_rev = version[SPMI_COMMON_REG_DIG_MAJOR_REV
|
||||
@ -1245,11 +1286,11 @@ found:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spmi_regulator_ftsmps_init_slew_rate(struct spmi_regulator *vreg)
|
||||
static int spmi_regulator_init_slew_rate(struct spmi_regulator *vreg)
|
||||
{
|
||||
int ret;
|
||||
u8 reg = 0;
|
||||
int step, delay, slew_rate;
|
||||
int step, delay, slew_rate, step_delay;
|
||||
const struct spmi_voltage_range *range;
|
||||
|
||||
ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_STEP_CTRL, ®, 1);
|
||||
@ -1262,6 +1303,15 @@ static int spmi_regulator_ftsmps_init_slew_rate(struct spmi_regulator *vreg)
|
||||
if (!range)
|
||||
return -EINVAL;
|
||||
|
||||
switch (vreg->logical_type) {
|
||||
case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS:
|
||||
step_delay = SPMI_FTSMPS_STEP_DELAY;
|
||||
break;
|
||||
default:
|
||||
step_delay = SPMI_DEFAULT_STEP_DELAY;
|
||||
break;
|
||||
}
|
||||
|
||||
step = reg & SPMI_FTSMPS_STEP_CTRL_STEP_MASK;
|
||||
step >>= SPMI_FTSMPS_STEP_CTRL_STEP_SHIFT;
|
||||
|
||||
@ -1270,7 +1320,7 @@ static int spmi_regulator_ftsmps_init_slew_rate(struct spmi_regulator *vreg)
|
||||
|
||||
/* slew_rate has units of uV/us */
|
||||
slew_rate = SPMI_FTSMPS_CLOCK_RATE * range->step_uV * (1 << step);
|
||||
slew_rate /= 1000 * (SPMI_FTSMPS_STEP_DELAY << delay);
|
||||
slew_rate /= 1000 * (step_delay << delay);
|
||||
slew_rate *= SPMI_FTSMPS_STEP_MARGIN_NUM;
|
||||
slew_rate /= SPMI_FTSMPS_STEP_MARGIN_DEN;
|
||||
|
||||
@ -1411,10 +1461,16 @@ static int spmi_regulator_of_parse(struct device_node *node,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (vreg->logical_type == SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS) {
|
||||
ret = spmi_regulator_ftsmps_init_slew_rate(vreg);
|
||||
switch (vreg->logical_type) {
|
||||
case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS:
|
||||
case SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS:
|
||||
case SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS:
|
||||
case SPMI_REGULATOR_LOGICAL_TYPE_SMPS:
|
||||
ret = spmi_regulator_init_slew_rate(vreg);
|
||||
if (ret)
|
||||
return ret;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (vreg->logical_type != SPMI_REGULATOR_LOGICAL_TYPE_VS)
|
||||
@ -1510,10 +1566,61 @@ static const struct spmi_regulator_data pm8916_regulators[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct spmi_regulator_data pm8994_regulators[] = {
|
||||
{ "s1", 0x1400, "vdd_s1", },
|
||||
{ "s2", 0x1700, "vdd_s2", },
|
||||
{ "s3", 0x1a00, "vdd_s3", },
|
||||
{ "s4", 0x1d00, "vdd_s4", },
|
||||
{ "s5", 0x2000, "vdd_s5", },
|
||||
{ "s6", 0x2300, "vdd_s6", },
|
||||
{ "s7", 0x2600, "vdd_s7", },
|
||||
{ "s8", 0x2900, "vdd_s8", },
|
||||
{ "s9", 0x2c00, "vdd_s9", },
|
||||
{ "s10", 0x2f00, "vdd_s10", },
|
||||
{ "s11", 0x3200, "vdd_s11", },
|
||||
{ "s12", 0x3500, "vdd_s12", },
|
||||
{ "l1", 0x4000, "vdd_l1", },
|
||||
{ "l2", 0x4100, "vdd_l2_l26_l28", },
|
||||
{ "l3", 0x4200, "vdd_l3_l11", },
|
||||
{ "l4", 0x4300, "vdd_l4_l27_l31", },
|
||||
{ "l5", 0x4400, "vdd_l5_l7", },
|
||||
{ "l6", 0x4500, "vdd_l6_l12_l32", },
|
||||
{ "l7", 0x4600, "vdd_l5_l7", },
|
||||
{ "l8", 0x4700, "vdd_l8_l16_l30", },
|
||||
{ "l9", 0x4800, "vdd_l9_l10_l18_l22", },
|
||||
{ "l10", 0x4900, "vdd_l9_l10_l18_l22", },
|
||||
{ "l11", 0x4a00, "vdd_l3_l11", },
|
||||
{ "l12", 0x4b00, "vdd_l6_l12_l32", },
|
||||
{ "l13", 0x4c00, "vdd_l13_l19_l23_l24", },
|
||||
{ "l14", 0x4d00, "vdd_l14_l15", },
|
||||
{ "l15", 0x4e00, "vdd_l14_l15", },
|
||||
{ "l16", 0x4f00, "vdd_l8_l16_l30", },
|
||||
{ "l17", 0x5000, "vdd_l17_l29", },
|
||||
{ "l18", 0x5100, "vdd_l9_l10_l18_l22", },
|
||||
{ "l19", 0x5200, "vdd_l13_l19_l23_l24", },
|
||||
{ "l20", 0x5300, "vdd_l20_l21", },
|
||||
{ "l21", 0x5400, "vdd_l20_l21", },
|
||||
{ "l22", 0x5500, "vdd_l9_l10_l18_l22", },
|
||||
{ "l23", 0x5600, "vdd_l13_l19_l23_l24", },
|
||||
{ "l24", 0x5700, "vdd_l13_l19_l23_l24", },
|
||||
{ "l25", 0x5800, "vdd_l25", },
|
||||
{ "l26", 0x5900, "vdd_l2_l26_l28", },
|
||||
{ "l27", 0x5a00, "vdd_l4_l27_l31", },
|
||||
{ "l28", 0x5b00, "vdd_l2_l26_l28", },
|
||||
{ "l29", 0x5c00, "vdd_l17_l29", },
|
||||
{ "l30", 0x5d00, "vdd_l8_l16_l30", },
|
||||
{ "l31", 0x5e00, "vdd_l4_l27_l31", },
|
||||
{ "l32", 0x5f00, "vdd_l6_l12_l32", },
|
||||
{ "lvs1", 0x8000, "vdd_lvs_1_2", },
|
||||
{ "lvs2", 0x8100, "vdd_lvs_1_2", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_spmi_regulator_match[] = {
|
||||
{ .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators },
|
||||
{ .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators },
|
||||
{ .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators },
|
||||
{ .compatible = "qcom,pm8994-regulators", .data = &pm8994_regulators },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_spmi_regulator_match);
|
||||
@ -1573,7 +1680,7 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
|
||||
|
||||
ret = spmi_regulator_match(vreg, reg->force_type);
|
||||
if (ret)
|
||||
goto err;
|
||||
continue;
|
||||
|
||||
config.dev = dev;
|
||||
config.driver_data = vreg;
|
||||
|
@ -55,6 +55,42 @@
|
||||
/* max steps for increase voltage of Buck1/2, equal 100mv*/
|
||||
#define MAX_STEPS_ONE_TIME 8
|
||||
|
||||
#define RK8XX_DESC(_id, _match, _supply, _min, _max, _step, _vreg, \
|
||||
_vmask, _ereg, _emask, _etime) \
|
||||
[_id] = { \
|
||||
.name = (_match), \
|
||||
.supply_name = (_supply), \
|
||||
.of_match = of_match_ptr(_match), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = (_id), \
|
||||
.n_voltages = (((_max) - (_min)) / (_step) + 1), \
|
||||
.owner = THIS_MODULE, \
|
||||
.min_uV = (_min) * 1000, \
|
||||
.uV_step = (_step) * 1000, \
|
||||
.vsel_reg = (_vreg), \
|
||||
.vsel_mask = (_vmask), \
|
||||
.enable_reg = (_ereg), \
|
||||
.enable_mask = (_emask), \
|
||||
.enable_time = (_etime), \
|
||||
.ops = &rk808_reg_ops, \
|
||||
}
|
||||
|
||||
#define RK8XX_DESC_SWITCH(_id, _match, _supply, _ereg, _emask) \
|
||||
[_id] = { \
|
||||
.name = (_match), \
|
||||
.supply_name = (_supply), \
|
||||
.of_match = of_match_ptr(_match), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = (_id), \
|
||||
.enable_reg = (_ereg), \
|
||||
.enable_mask = (_emask), \
|
||||
.owner = THIS_MODULE, \
|
||||
.ops = &rk808_switch_ops \
|
||||
}
|
||||
|
||||
|
||||
struct rk808_regulator_data {
|
||||
struct gpio_desc *dvs_gpio[2];
|
||||
};
|
||||
@ -66,27 +102,11 @@ static const int rk808_buck_config_regs[] = {
|
||||
RK808_BUCK4_CONFIG_REG,
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range rk808_buck_voltage_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(712500, 0, 63, 12500),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range rk808_buck4_voltage_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(1800000, 0, 15, 100000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range rk808_ldo_voltage_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(1800000, 0, 16, 100000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000),
|
||||
REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range rk808_ldo6_voltage_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(800000, 0, 17, 100000),
|
||||
};
|
||||
|
||||
static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev)
|
||||
{
|
||||
struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev);
|
||||
@ -240,6 +260,21 @@ static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
|
||||
}
|
||||
|
||||
static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
|
||||
{
|
||||
unsigned int reg;
|
||||
int sel = regulator_map_voltage_linear(rdev, uv, uv);
|
||||
|
||||
if (sel < 0)
|
||||
return -EINVAL;
|
||||
|
||||
reg = rdev->desc->vsel_reg + RK808_SLP_REG_OFFSET;
|
||||
|
||||
return regmap_update_bits(rdev->regmap, reg,
|
||||
rdev->desc->vsel_mask,
|
||||
sel);
|
||||
}
|
||||
|
||||
static int rk808_set_suspend_voltage_range(struct regulator_dev *rdev, int uv)
|
||||
{
|
||||
unsigned int reg;
|
||||
int sel = regulator_map_voltage_linear_range(rdev, uv, uv);
|
||||
@ -277,8 +312,8 @@ static int rk808_set_suspend_disable(struct regulator_dev *rdev)
|
||||
}
|
||||
|
||||
static struct regulator_ops rk808_buck1_2_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.map_voltage = regulator_map_voltage_linear,
|
||||
.get_voltage_sel = rk808_buck1_2_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = rk808_buck1_2_set_voltage_sel,
|
||||
.set_voltage_time_sel = rk808_buck1_2_set_voltage_time_sel,
|
||||
@ -292,6 +327,19 @@ static struct regulator_ops rk808_buck1_2_ops = {
|
||||
};
|
||||
|
||||
static struct regulator_ops rk808_reg_ops = {
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.map_voltage = regulator_map_voltage_linear,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.set_suspend_voltage = rk808_set_suspend_voltage,
|
||||
.set_suspend_enable = rk808_set_suspend_enable,
|
||||
.set_suspend_disable = rk808_set_suspend_disable,
|
||||
};
|
||||
|
||||
static struct regulator_ops rk808_reg_ops_ranges = {
|
||||
.list_voltage = regulator_list_voltage_linear_range,
|
||||
.map_voltage = regulator_map_voltage_linear_range,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
@ -299,7 +347,7 @@ static struct regulator_ops rk808_reg_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.set_suspend_voltage = rk808_set_suspend_voltage,
|
||||
.set_suspend_voltage = rk808_set_suspend_voltage_range,
|
||||
.set_suspend_enable = rk808_set_suspend_enable,
|
||||
.set_suspend_disable = rk808_set_suspend_disable,
|
||||
};
|
||||
@ -316,12 +364,14 @@ static const struct regulator_desc rk808_reg[] = {
|
||||
{
|
||||
.name = "DCDC_REG1",
|
||||
.supply_name = "vcc1",
|
||||
.of_match = of_match_ptr("DCDC_REG1"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.id = RK808_ID_DCDC1,
|
||||
.ops = &rk808_buck1_2_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.min_uV = 712500,
|
||||
.uV_step = 12500,
|
||||
.n_voltages = 64,
|
||||
.linear_ranges = rk808_buck_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges),
|
||||
.vsel_reg = RK808_BUCK1_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_BUCK_VSEL_MASK,
|
||||
.enable_reg = RK808_DCDC_EN_REG,
|
||||
@ -330,12 +380,14 @@ static const struct regulator_desc rk808_reg[] = {
|
||||
}, {
|
||||
.name = "DCDC_REG2",
|
||||
.supply_name = "vcc2",
|
||||
.of_match = of_match_ptr("DCDC_REG2"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.id = RK808_ID_DCDC2,
|
||||
.ops = &rk808_buck1_2_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.min_uV = 712500,
|
||||
.uV_step = 12500,
|
||||
.n_voltages = 64,
|
||||
.linear_ranges = rk808_buck_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_buck_voltage_ranges),
|
||||
.vsel_reg = RK808_BUCK2_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_BUCK_VSEL_MASK,
|
||||
.enable_reg = RK808_DCDC_EN_REG,
|
||||
@ -344,6 +396,8 @@ static const struct regulator_desc rk808_reg[] = {
|
||||
}, {
|
||||
.name = "DCDC_REG3",
|
||||
.supply_name = "vcc3",
|
||||
.of_match = of_match_ptr("DCDC_REG3"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.id = RK808_ID_DCDC3,
|
||||
.ops = &rk808_switch_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
@ -351,55 +405,23 @@ static const struct regulator_desc rk808_reg[] = {
|
||||
.enable_reg = RK808_DCDC_EN_REG,
|
||||
.enable_mask = BIT(2),
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "DCDC_REG4",
|
||||
.supply_name = "vcc4",
|
||||
.id = RK808_ID_DCDC4,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 16,
|
||||
.linear_ranges = rk808_buck4_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_buck4_voltage_ranges),
|
||||
.vsel_reg = RK808_BUCK4_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_BUCK4_VSEL_MASK,
|
||||
.enable_reg = RK808_DCDC_EN_REG,
|
||||
.enable_mask = BIT(3),
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "LDO_REG1",
|
||||
.supply_name = "vcc6",
|
||||
.id = RK808_ID_LDO1,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 17,
|
||||
.linear_ranges = rk808_ldo_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
|
||||
.vsel_reg = RK808_LDO1_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_LDO_VSEL_MASK,
|
||||
.enable_reg = RK808_LDO_EN_REG,
|
||||
.enable_mask = BIT(0),
|
||||
.enable_time = 400,
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "LDO_REG2",
|
||||
.supply_name = "vcc6",
|
||||
.id = RK808_ID_LDO2,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 17,
|
||||
.linear_ranges = rk808_ldo_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
|
||||
.vsel_reg = RK808_LDO2_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_LDO_VSEL_MASK,
|
||||
.enable_reg = RK808_LDO_EN_REG,
|
||||
.enable_mask = BIT(1),
|
||||
.enable_time = 400,
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
},
|
||||
RK8XX_DESC(RK808_ID_DCDC4, "DCDC_REG4", "vcc4", 1800, 3300, 100,
|
||||
RK808_BUCK4_ON_VSEL_REG, RK808_BUCK4_VSEL_MASK,
|
||||
RK808_DCDC_EN_REG, BIT(3), 0),
|
||||
RK8XX_DESC(RK808_ID_LDO1, "LDO_REG1", "vcc6", 1800, 3400, 100,
|
||||
RK808_LDO1_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
|
||||
BIT(0), 400),
|
||||
RK8XX_DESC(RK808_ID_LDO2, "LDO_REG2", "vcc6", 1800, 3400, 100,
|
||||
RK808_LDO2_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
|
||||
BIT(1), 400),
|
||||
{
|
||||
.name = "LDO_REG3",
|
||||
.supply_name = "vcc7",
|
||||
.of_match = of_match_ptr("LDO_REG3"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.id = RK808_ID_LDO3,
|
||||
.ops = &rk808_reg_ops,
|
||||
.ops = &rk808_reg_ops_ranges,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 16,
|
||||
.linear_ranges = rk808_ldo3_voltage_ranges,
|
||||
@ -410,117 +432,26 @@ static const struct regulator_desc rk808_reg[] = {
|
||||
.enable_mask = BIT(2),
|
||||
.enable_time = 400,
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "LDO_REG4",
|
||||
.supply_name = "vcc9",
|
||||
.id = RK808_ID_LDO4,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 17,
|
||||
.linear_ranges = rk808_ldo_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
|
||||
.vsel_reg = RK808_LDO4_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_LDO_VSEL_MASK,
|
||||
.enable_reg = RK808_LDO_EN_REG,
|
||||
.enable_mask = BIT(3),
|
||||
.enable_time = 400,
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "LDO_REG5",
|
||||
.supply_name = "vcc9",
|
||||
.id = RK808_ID_LDO5,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 17,
|
||||
.linear_ranges = rk808_ldo_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
|
||||
.vsel_reg = RK808_LDO5_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_LDO_VSEL_MASK,
|
||||
.enable_reg = RK808_LDO_EN_REG,
|
||||
.enable_mask = BIT(4),
|
||||
.enable_time = 400,
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "LDO_REG6",
|
||||
.supply_name = "vcc10",
|
||||
.id = RK808_ID_LDO6,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 18,
|
||||
.linear_ranges = rk808_ldo6_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges),
|
||||
.vsel_reg = RK808_LDO6_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_LDO_VSEL_MASK,
|
||||
.enable_reg = RK808_LDO_EN_REG,
|
||||
.enable_mask = BIT(5),
|
||||
.enable_time = 400,
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "LDO_REG7",
|
||||
.supply_name = "vcc7",
|
||||
.id = RK808_ID_LDO7,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 18,
|
||||
.linear_ranges = rk808_ldo6_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_ldo6_voltage_ranges),
|
||||
.vsel_reg = RK808_LDO7_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_LDO_VSEL_MASK,
|
||||
.enable_reg = RK808_LDO_EN_REG,
|
||||
.enable_mask = BIT(6),
|
||||
.enable_time = 400,
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "LDO_REG8",
|
||||
.supply_name = "vcc11",
|
||||
.id = RK808_ID_LDO8,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 17,
|
||||
.linear_ranges = rk808_ldo_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_ldo_voltage_ranges),
|
||||
.vsel_reg = RK808_LDO8_ON_VSEL_REG,
|
||||
.vsel_mask = RK808_LDO_VSEL_MASK,
|
||||
.enable_reg = RK808_LDO_EN_REG,
|
||||
.enable_mask = BIT(7),
|
||||
.enable_time = 400,
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "SWITCH_REG1",
|
||||
.supply_name = "vcc8",
|
||||
.id = RK808_ID_SWITCH1,
|
||||
.ops = &rk808_switch_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.enable_reg = RK808_DCDC_EN_REG,
|
||||
.enable_mask = BIT(5),
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "SWITCH_REG2",
|
||||
.supply_name = "vcc12",
|
||||
.id = RK808_ID_SWITCH2,
|
||||
.ops = &rk808_switch_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.enable_reg = RK808_DCDC_EN_REG,
|
||||
.enable_mask = BIT(6),
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static struct of_regulator_match rk808_reg_matches[] = {
|
||||
[RK808_ID_DCDC1] = { .name = "DCDC_REG1" },
|
||||
[RK808_ID_DCDC2] = { .name = "DCDC_REG2" },
|
||||
[RK808_ID_DCDC3] = { .name = "DCDC_REG3" },
|
||||
[RK808_ID_DCDC4] = { .name = "DCDC_REG4" },
|
||||
[RK808_ID_LDO1] = { .name = "LDO_REG1" },
|
||||
[RK808_ID_LDO2] = { .name = "LDO_REG2" },
|
||||
[RK808_ID_LDO3] = { .name = "LDO_REG3" },
|
||||
[RK808_ID_LDO4] = { .name = "LDO_REG4" },
|
||||
[RK808_ID_LDO5] = { .name = "LDO_REG5" },
|
||||
[RK808_ID_LDO6] = { .name = "LDO_REG6" },
|
||||
[RK808_ID_LDO7] = { .name = "LDO_REG7" },
|
||||
[RK808_ID_LDO8] = { .name = "LDO_REG8" },
|
||||
[RK808_ID_SWITCH1] = { .name = "SWITCH_REG1" },
|
||||
[RK808_ID_SWITCH2] = { .name = "SWITCH_REG2" },
|
||||
RK8XX_DESC(RK808_ID_LDO4, "LDO_REG4", "vcc9", 1800, 3400, 100,
|
||||
RK808_LDO4_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
|
||||
BIT(3), 400),
|
||||
RK8XX_DESC(RK808_ID_LDO5, "LDO_REG5", "vcc9", 1800, 3400, 100,
|
||||
RK808_LDO5_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
|
||||
BIT(4), 400),
|
||||
RK8XX_DESC(RK808_ID_LDO6, "LDO_REG6", "vcc10", 800, 2500, 100,
|
||||
RK808_LDO6_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
|
||||
BIT(5), 400),
|
||||
RK8XX_DESC(RK808_ID_LDO7, "LDO_REG7", "vcc7", 800, 2500, 100,
|
||||
RK808_LDO7_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
|
||||
BIT(6), 400),
|
||||
RK8XX_DESC(RK808_ID_LDO8, "LDO_REG8", "vcc11", 1800, 3400, 100,
|
||||
RK808_LDO8_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
|
||||
BIT(7), 400),
|
||||
RK8XX_DESC_SWITCH(RK808_ID_SWITCH1, "SWITCH_REG1", "vcc8",
|
||||
RK808_DCDC_EN_REG, BIT(5)),
|
||||
RK8XX_DESC_SWITCH(RK808_ID_SWITCH2, "SWITCH_REG2", "vcc12",
|
||||
RK808_DCDC_EN_REG, BIT(6)),
|
||||
};
|
||||
|
||||
static int rk808_regulator_dt_parse_pdata(struct device *dev,
|
||||
@ -529,17 +460,12 @@ static int rk808_regulator_dt_parse_pdata(struct device *dev,
|
||||
struct rk808_regulator_data *pdata)
|
||||
{
|
||||
struct device_node *np;
|
||||
int tmp, ret, i;
|
||||
int tmp, ret = 0, i;
|
||||
|
||||
np = of_get_child_by_name(client_dev->of_node, "regulators");
|
||||
if (!np)
|
||||
return -ENXIO;
|
||||
|
||||
ret = of_regulator_match(dev, np, rk808_reg_matches,
|
||||
RK808_NUM_REGULATORS);
|
||||
if (ret < 0)
|
||||
goto dt_parse_end;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) {
|
||||
pdata->dvs_gpio[i] =
|
||||
devm_gpiod_get_index_optional(client_dev, "dvs", i,
|
||||
@ -586,18 +512,12 @@ static int rk808_regulator_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
config.dev = &client->dev;
|
||||
config.driver_data = pdata;
|
||||
config.regmap = rk808->regmap;
|
||||
|
||||
/* Instantiate the regulators */
|
||||
for (i = 0; i < RK808_NUM_REGULATORS; i++) {
|
||||
if (!rk808_reg_matches[i].init_data ||
|
||||
!rk808_reg_matches[i].of_node)
|
||||
continue;
|
||||
|
||||
config.dev = &client->dev;
|
||||
config.driver_data = pdata;
|
||||
config.regmap = rk808->regmap;
|
||||
config.of_node = rk808_reg_matches[i].of_node;
|
||||
config.init_data = rk808_reg_matches[i].init_data;
|
||||
|
||||
rk808_rdev = devm_regulator_register(&pdev->dev,
|
||||
&rk808_reg[i], &config);
|
||||
if (IS_ERR(rk808_rdev)) {
|
||||
|
@ -267,6 +267,7 @@ static struct regulator_ops s2mps11_buck_ops = {
|
||||
.ops = &s2mps11_ldo_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.ramp_delay = RAMP_DELAY_12_MVUS, \
|
||||
.min_uV = MIN_800_MV, \
|
||||
.uV_step = step, \
|
||||
.n_voltages = S2MPS11_LDO_N_VOLTAGES, \
|
||||
@ -1237,17 +1238,7 @@ static struct platform_driver s2mps11_pmic_driver = {
|
||||
.id_table = s2mps11_pmic_id,
|
||||
};
|
||||
|
||||
static int __init s2mps11_pmic_init(void)
|
||||
{
|
||||
return platform_driver_register(&s2mps11_pmic_driver);
|
||||
}
|
||||
subsys_initcall(s2mps11_pmic_init);
|
||||
|
||||
static void __exit s2mps11_pmic_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&s2mps11_pmic_driver);
|
||||
}
|
||||
module_exit(s2mps11_pmic_exit);
|
||||
module_platform_driver(s2mps11_pmic_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
|
||||
|
@ -600,7 +600,7 @@ static int pmic_probe(struct spi_device *spi)
|
||||
|
||||
memset(hw, 0, sizeof(struct tps6524x));
|
||||
hw->dev = dev;
|
||||
hw->spi = spi_dev_get(spi);
|
||||
hw->spi = spi;
|
||||
mutex_init(&hw->lock);
|
||||
|
||||
for (i = 0; i < N_REGULATORS; i++, info++, init_data++) {
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
/*
|
||||
* The TWL4030/TW5030/TPS659x0/TWL6030 family chips include power management, a
|
||||
@ -188,6 +188,74 @@ static int twl6030reg_is_enabled(struct regulator_dev *rdev)
|
||||
return grp && (val == TWL6030_CFG_STATE_ON);
|
||||
}
|
||||
|
||||
#define PB_I2C_BUSY BIT(0)
|
||||
#define PB_I2C_BWEN BIT(1)
|
||||
|
||||
/* Wait until buffer empty/ready to send a word on power bus. */
|
||||
static int twl4030_wait_pb_ready(void)
|
||||
{
|
||||
|
||||
int ret;
|
||||
int timeout = 10;
|
||||
u8 val;
|
||||
|
||||
do {
|
||||
ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
|
||||
TWL4030_PM_MASTER_PB_CFG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!(val & PB_I2C_BUSY))
|
||||
return 0;
|
||||
|
||||
mdelay(1);
|
||||
timeout--;
|
||||
} while (timeout);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Send a word over the powerbus */
|
||||
static int twl4030_send_pb_msg(unsigned msg)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
/* save powerbus configuration */
|
||||
ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
|
||||
TWL4030_PM_MASTER_PB_CFG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable i2c access to powerbus */
|
||||
ret = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val | PB_I2C_BWEN,
|
||||
TWL4030_PM_MASTER_PB_CFG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = twl4030_wait_pb_ready();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, msg >> 8,
|
||||
TWL4030_PM_MASTER_PB_WORD_MSB);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, msg & 0xff,
|
||||
TWL4030_PM_MASTER_PB_WORD_LSB);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = twl4030_wait_pb_ready();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Restore powerbus configuration */
|
||||
return twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val,
|
||||
TWL4030_PM_MASTER_PB_CFG);
|
||||
}
|
||||
|
||||
static int twl4030reg_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct twlreg_info *info = rdev_get_drvdata(rdev);
|
||||
@ -303,7 +371,6 @@ static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
|
||||
{
|
||||
struct twlreg_info *info = rdev_get_drvdata(rdev);
|
||||
unsigned message;
|
||||
int status;
|
||||
|
||||
/* We can only set the mode through state machine commands... */
|
||||
switch (mode) {
|
||||
@ -317,20 +384,19 @@ static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Ensure the resource is associated with some group */
|
||||
status = twlreg_grp(rdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
if (!(status & (P3_GRP_4030 | P2_GRP_4030 | P1_GRP_4030)))
|
||||
return -EACCES;
|
||||
return twl4030_send_pb_msg(message);
|
||||
}
|
||||
|
||||
status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
|
||||
message >> 8, TWL4030_PM_MASTER_PB_WORD_MSB);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
return twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
|
||||
message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB);
|
||||
static inline unsigned int twl4030reg_map_mode(unsigned int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case RES_STATE_ACTIVE:
|
||||
return REGULATOR_MODE_NORMAL;
|
||||
case RES_STATE_SLEEP:
|
||||
return REGULATOR_MODE_STANDBY;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
|
||||
@ -835,10 +901,11 @@ static struct regulator_ops twlsmps_ops = {
|
||||
#define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
|
||||
remap_conf) \
|
||||
TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
|
||||
remap_conf, TWL4030, twl4030fixed_ops)
|
||||
remap_conf, TWL4030, twl4030fixed_ops, \
|
||||
twl4030reg_map_mode)
|
||||
#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \
|
||||
TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \
|
||||
0x0, TWL6030, twl6030fixed_ops)
|
||||
0x0, TWL6030, twl6030fixed_ops, 0x0)
|
||||
|
||||
#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
|
||||
static const struct twlreg_info TWL4030_INFO_##label = { \
|
||||
@ -855,6 +922,7 @@ static const struct twlreg_info TWL4030_INFO_##label = { \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.enable_time = turnon_delay, \
|
||||
.of_map_mode = twl4030reg_map_mode, \
|
||||
}, \
|
||||
}
|
||||
|
||||
@ -870,6 +938,7 @@ static const struct twlreg_info TWL4030_INFO_##label = { \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.enable_time = turnon_delay, \
|
||||
.of_map_mode = twl4030reg_map_mode, \
|
||||
}, \
|
||||
}
|
||||
|
||||
@ -915,7 +984,7 @@ static const struct twlreg_info TWL6032_INFO_##label = { \
|
||||
}
|
||||
|
||||
#define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
|
||||
family, operations) \
|
||||
family, operations, map_mode) \
|
||||
static const struct twlreg_info TWLFIXED_INFO_##label = { \
|
||||
.base = offset, \
|
||||
.id = num, \
|
||||
@ -930,6 +999,7 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \
|
||||
.owner = THIS_MODULE, \
|
||||
.min_uV = mVolts * 1000, \
|
||||
.enable_time = turnon_delay, \
|
||||
.of_map_mode = map_mode, \
|
||||
}, \
|
||||
}
|
||||
|
||||
|
@ -196,6 +196,7 @@
|
||||
#define AS3722_LDO3_VSEL_MIN 0x01
|
||||
#define AS3722_LDO3_VSEL_MAX 0x2D
|
||||
#define AS3722_LDO3_NUM_VOLT 0x2D
|
||||
#define AS3722_LDO6_VSEL_BYPASS 0x3F
|
||||
#define AS3722_LDO_VSEL_MASK 0x7F
|
||||
#define AS3722_LDO_VSEL_MIN 0x01
|
||||
#define AS3722_LDO_VSEL_MAX 0x7F
|
||||
|
@ -30,6 +30,9 @@
|
||||
#define MIN_600_MV 600000
|
||||
#define MIN_500_MV 500000
|
||||
|
||||
/* Ramp delay in uV/us */
|
||||
#define RAMP_DELAY_12_MVUS 12000
|
||||
|
||||
/* Macros to represent steps for LDO/BUCK */
|
||||
#define STEP_50_MV 50000
|
||||
#define STEP_25_MV 25000
|
||||
|
@ -74,6 +74,24 @@ enum pwm_polarity {
|
||||
PWM_POLARITY_INVERSED,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pwm_args - board-dependent PWM arguments
|
||||
* @period: reference period
|
||||
* @polarity: reference polarity
|
||||
*
|
||||
* This structure describes board-dependent arguments attached to a PWM
|
||||
* device. These arguments are usually retrieved from the PWM lookup table or
|
||||
* device tree.
|
||||
*
|
||||
* Do not confuse this with the PWM state: PWM arguments represent the initial
|
||||
* configuration that users want to use on this PWM device rather than the
|
||||
* current PWM hardware state.
|
||||
*/
|
||||
struct pwm_args {
|
||||
unsigned int period;
|
||||
enum pwm_polarity polarity;
|
||||
};
|
||||
|
||||
enum {
|
||||
PWMF_REQUESTED = 1 << 0,
|
||||
PWMF_ENABLED = 1 << 1,
|
||||
@ -92,6 +110,7 @@ enum {
|
||||
* @period: period of the PWM signal (in nanoseconds)
|
||||
* @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
|
||||
* @polarity: polarity of the PWM signal
|
||||
* @args: PWM arguments
|
||||
*/
|
||||
struct pwm_device {
|
||||
const char *label;
|
||||
@ -105,6 +124,8 @@ struct pwm_device {
|
||||
unsigned int period;
|
||||
unsigned int duty_cycle;
|
||||
enum pwm_polarity polarity;
|
||||
|
||||
struct pwm_args args;
|
||||
};
|
||||
|
||||
static inline bool pwm_is_enabled(const struct pwm_device *pwm)
|
||||
@ -144,6 +165,18 @@ static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
|
||||
return pwm ? pwm->polarity : PWM_POLARITY_NORMAL;
|
||||
}
|
||||
|
||||
static inline void pwm_get_args(const struct pwm_device *pwm,
|
||||
struct pwm_args *args)
|
||||
{
|
||||
*args = pwm->args;
|
||||
}
|
||||
|
||||
static inline void pwm_apply_args(struct pwm_device *pwm)
|
||||
{
|
||||
pwm_set_period(pwm, pwm->args.period);
|
||||
pwm_set_polarity(pwm, pwm->args.polarity);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct pwm_ops - PWM controller operations
|
||||
* @request: optional hook for requesting a PWM
|
||||
|
@ -69,11 +69,13 @@ enum {
|
||||
* @id: regulator id
|
||||
* @name: regulator name
|
||||
* @init_data: regulator init data
|
||||
* @of_node: device tree node (optional)
|
||||
*/
|
||||
struct act8865_regulator_data {
|
||||
int id;
|
||||
const char *name;
|
||||
struct regulator_init_data *init_data;
|
||||
struct device_node *of_node;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -224,7 +224,7 @@ int regulator_bulk_force_disable(int num_consumers,
|
||||
void regulator_bulk_free(int num_consumers,
|
||||
struct regulator_bulk_data *consumers);
|
||||
|
||||
int regulator_can_change_voltage(struct regulator *regulator);
|
||||
int __deprecated regulator_can_change_voltage(struct regulator *regulator);
|
||||
int regulator_count_voltages(struct regulator *regulator);
|
||||
int regulator_list_voltage(struct regulator *regulator, unsigned selector);
|
||||
int regulator_is_supported_voltage(struct regulator *regulator,
|
||||
@ -436,7 +436,7 @@ static inline void regulator_bulk_free(int num_consumers,
|
||||
{
|
||||
}
|
||||
|
||||
static inline int regulator_can_change_voltage(struct regulator *regulator)
|
||||
static inline int __deprecated regulator_can_change_voltage(struct regulator *regulator)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -93,6 +93,9 @@ struct regulator_linear_range {
|
||||
* @get_current_limit: Get the configured limit for a current-limited regulator.
|
||||
* @set_input_current_limit: Configure an input limit.
|
||||
*
|
||||
* @set_over_current_protection: Support capability of automatically shutting
|
||||
* down when detecting an over current event.
|
||||
*
|
||||
* @set_active_discharge: Set active discharge enable/disable of regulators.
|
||||
*
|
||||
* @set_mode: Set the configured operating mode for the regulator.
|
||||
@ -255,6 +258,8 @@ enum regulator_type {
|
||||
*
|
||||
* @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
|
||||
* @vsel_mask: Mask for register bitfield used for selector
|
||||
* @csel_reg: Register for TPS65218 LS3 current regulator
|
||||
* @csel_mask: Mask for TPS65218 LS3 current regulator
|
||||
* @apply_reg: Register for initiate voltage change on the output when
|
||||
* using regulator_set_voltage_sel_regmap
|
||||
* @apply_bit: Register bitfield used for initiate voltage change on the
|
||||
@ -292,7 +297,7 @@ struct regulator_desc {
|
||||
const struct regulator_desc *,
|
||||
struct regulator_config *);
|
||||
int id;
|
||||
bool continuous_voltage_range;
|
||||
unsigned int continuous_voltage_range:1;
|
||||
unsigned n_voltages;
|
||||
const struct regulator_ops *ops;
|
||||
int irq;
|
||||
|
@ -97,6 +97,7 @@ struct regulator_state {
|
||||
* @ramp_disable: Disable ramp delay when initialising or when setting voltage.
|
||||
* @soft_start: Enable soft start so that voltage ramps slowly.
|
||||
* @pull_down: Enable pull down when regulator is disabled.
|
||||
* @over_current_protection: Auto disable on over current event.
|
||||
*
|
||||
* @input_uV: Input voltage for regulator when supplied by another regulator.
|
||||
*
|
||||
|
@ -54,6 +54,10 @@
|
||||
* @reg_init_data: The regulator init data.
|
||||
* @control_flags: Control flags which are ORed value of above flags to
|
||||
* configure device.
|
||||
* @junction_temp_warning: Junction temp in millicelcius on which warning need
|
||||
* to be set. Thermal functionality is only supported on
|
||||
* MAX77621. The threshold warning supported by MAX77621
|
||||
* are 120C and 140C.
|
||||
* @enable_ext_control: Enable the voltage enable/disable through external
|
||||
* control signal from EN input pin. If it is false then
|
||||
* voltage output will be enabled/disabled through EN bit of
|
||||
@ -67,6 +71,7 @@
|
||||
struct max8973_regulator_platform_data {
|
||||
struct regulator_init_data *reg_init_data;
|
||||
unsigned long control_flags;
|
||||
unsigned long junction_temp_warning;
|
||||
bool enable_ext_control;
|
||||
int enable_gpio;
|
||||
int dvs_gpio;
|
||||
|
Loading…
Reference in New Issue
Block a user