regulator: Updates for v5.17
This has been a fairly quiet release for the regulator API, the main thing has been the addition of helpers for interrupt handling from Matti Vaittinen. We do also have support for quite a few new devices and included in here is a platform/x86 patch series for Intel INT3472 ACPI devices which this is a dependency for the TPS68470 driver. - Helpers for trivial interrupt notifications, making it easier for drivers to handle error interrupts. - Support for Dialog DA914x, Maxim MAX2008x, Qualcomm PM8826, PMG1100, and PM8450 and TI TPS68470 -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmHcLP8ACgkQJNaLcl1U h9CFYAf9FwoHGtNWL8zxcAXs9egQVDKY36KXJkjXOkI5dlWVVpkCPoX4JWqfocGx lINFI1gLGPiwHx69EY45IQEIElltJYlaA53oBXEPxvNF98yAGqaHmlMxa32SeyVH yTMQfoo0sEjF6l5ELlKyPy51Syda4vTMjVxPkPx0P7XS9EgyXIOXzDfosTTwr9RH rEUGYuvDyITGEFMY3jyYnpAlvoGWMPnN4AwCb/alD1ZRpJXzGCMqGoRR7jgoi8KC 0IIuTOMGQY7V0LRe9zabHzZbDglVX52rmwGhZlDxbjMrdR4HCdv6homPEb/gJd7f icqaxLnW+3hoT3501QuD5JVNO2U7Ag== =htGo -----END PGP SIGNATURE----- Merge tag 'regulator-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator Pull regulator updates from Mark Brown: "This has been a fairly quiet release for the regulator API, the main thing has been the addition of helpers for interrupt handling from Matti Vaittinen. We do also have support for quite a few new devices. Summary: - Helpers for trivial interrupt notifications, making it easier for drivers to handle error interrupts. - Support for Dialog DA914x, Maxim MAX2008x, Qualcomm PM8826, PMG1100, and PM8450 and TI TPS68470" * tag 'regulator-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (30 commits) regulator: Add MAX20086-MAX20089 driver dt-bindings: regulators: Add bindings for Maxim MAX20086-MAX20089 regulator: qcom_smd: Align probe function with rpmh-regulator regulator: remove redundant ret variable regulator: qcom-labibb: OCP interrupts are not a failure while disabled regulator: dt-bindings: samsung,s5m8767: Move fixed string BUCK9 to 'properties' regulator: Introduce tps68470-regulator driver drivers/regulator: remove redundant ret variable regulator: fix bullet lists of regulator_ops comment regulator: Fix type of regulator-coupled-max-spread property regulator: maxim,max8973: Document interrupts property regulator: qcom-rpmh: Add support for PM8450 regulators regulator: qcom,rpmh: Add compatible for PM8450 regulator: da9121: Add DA914x binding info regulator: da9121: Remove erroneous compatible from binding regulator: da9121: Add DA914x support regulator: da9121: Prevent current limit change when enabled regulator: qcom-rpmh: Add PMG1110 regulators dt-bindings: regulator: Add compatible for pmg1110 regulator: qcom_spmi: Add pm8226 regulators ...
This commit is contained in:
commit
fef8dfaea9
@ -17,27 +17,39 @@ description: |
|
||||
Dialog Semiconductor DA9130 Single-channel 10A double-phase buck converter
|
||||
Dialog Semiconductor DA9131 Double-channel 5A single-phase buck converter
|
||||
Dialog Semiconductor DA9132 Double-channel 3A single-phase buck converter
|
||||
Dialog Semiconductor DA9141 Single-channel 40A quad-phase buck converter
|
||||
Dialog Semiconductor DA9142 Single-channel 20A double-phase buck converter
|
||||
|
||||
Current limits
|
||||
Device parameter ranges
|
||||
|
||||
This is PER PHASE, and the current limit setting in the devices reflect
|
||||
that with a maximum 10A limit. Allowing for transients at/near double
|
||||
the rated current, this translates across the device range to per
|
||||
channel figures as so...
|
||||
The current limits can be set to at/near double the rated current per channel
|
||||
to allow for transient peaks.
|
||||
Current limit changes when the output is enabled are not supported, as a
|
||||
precaution against undefined behaviour.
|
||||
|
||||
| DA9121 DA9122 DA9220 DA9217 DA9140
|
||||
| /DA9130 /DA9131 /DA9132
|
||||
-----------------------------------------------------------------------------
|
||||
Output current / channel | 10000000 5000000 3000000 6000000 40000000
|
||||
Output current / phase | 5000000 5000000 3000000 3000000 9500000
|
||||
-----------------------------------------------------------------------------
|
||||
Min regulator-min-microvolt| 300000 300000 300000 300000 500000
|
||||
Max regulator-max-microvolt| 1900000 1900000 1900000 1900000 1000000
|
||||
Device hardware default | 1000000 1000000 1000000 1000000 1000000
|
||||
-----------------------------------------------------------------------------
|
||||
Min regulator-min-microamp | 7000000 3500000 3500000 7000000 26000000
|
||||
Max regulator-max-microamp | 20000000 10000000 6000000 12000000 78000000
|
||||
Device hardware default | 15000000 7500000 5500000 11000000 58000000
|
||||
|----------------------------------------------|
|
||||
| | range & reset default value |
|
||||
| Device |------------------------------|
|
||||
| | microvolt | microamp |
|
||||
|----------------------------------------------|
|
||||
| DA9121/DA9130 | Min: 300000 | Min: 7000000 |
|
||||
| | Max: 1900000 | Max: 20000000 |
|
||||
|----------------------------------------------|
|
||||
| DA9121/DA9131 | Min: 300000 | Min: 3500000 |
|
||||
| | Max: 1900000 | Max: 10000000 |
|
||||
|----------------------------------------------|
|
||||
| DA9121/DA9131 | Min: 300000 | Min: 3500000 |
|
||||
| | Max: 1900000 | Max: 6000000 |
|
||||
|----------------------------------------------|
|
||||
| DA9217 | Min: 300000 | Min: 7000000 |
|
||||
| | Max: 1900000 | Max: 12000000 |
|
||||
|----------------------------------------------|
|
||||
| DA9141 | Min: 300000 | Min: 26000000 |
|
||||
| | Max: 1300000 | Max: 78000000 |
|
||||
|----------------------------------------------|
|
||||
| DA9142 | Min: 300000 | Min: 13000000 |
|
||||
| | Max: 1300000 | Max: 39000000 |
|
||||
|----------------------------------------------|
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
@ -51,7 +63,8 @@ properties:
|
||||
- dlg,da9130
|
||||
- dlg,da9131
|
||||
- dlg,da9132
|
||||
- dlg,da9140
|
||||
- dlg,da9141
|
||||
- dlg,da9142
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -70,26 +83,24 @@ properties:
|
||||
|
||||
regulators:
|
||||
type: object
|
||||
$ref: regulator.yaml#
|
||||
description: |
|
||||
This node defines the settings for the BUCK. The content of the
|
||||
sub-node is defined by the standard binding for regulators; see regulator.yaml.
|
||||
The DA9121 regulator is bound using their names listed below
|
||||
buck1 - BUCK1
|
||||
buck2 - BUCK2 //DA9122, DA9220, DA9131, DA9132 only
|
||||
List of regulators provided by the device
|
||||
|
||||
patternProperties:
|
||||
"^buck([1-2])$":
|
||||
type: object
|
||||
$ref: regulator.yaml#
|
||||
description: |
|
||||
Properties for a single BUCK regulator
|
||||
|
||||
properties:
|
||||
regulator-mode:
|
||||
maxItems: 1
|
||||
description: Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h
|
||||
regulator-name:
|
||||
pattern: "^BUCK([1-2])$"
|
||||
description: |
|
||||
BUCK2 present in DA9122, DA9220, DA9131, DA9132 only
|
||||
|
||||
regulator-initial-mode:
|
||||
maxItems: 1
|
||||
enum: [ 0, 1, 2, 3 ]
|
||||
description: Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h
|
||||
|
||||
enable-gpios:
|
||||
@ -98,6 +109,7 @@ properties:
|
||||
|
||||
dlg,ripple-cancel:
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
enum: [ 0, 1, 2, 3 ]
|
||||
description: |
|
||||
Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h
|
||||
Only present on multi-channel devices (DA9122, DA9220, DA9131, DA9132)
|
||||
|
106
Documentation/devicetree/bindings/regulator/maxim,max20086.yaml
Normal file
106
Documentation/devicetree/bindings/regulator/maxim,max20086.yaml
Normal file
@ -0,0 +1,106 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/regulator/maxim,max20086.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim Integrated MAX20086-MAX20089 Camera Power Protector
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
|
||||
description: |
|
||||
The MAX20086-MAX20089 are dual/quad camera power protectors, designed to
|
||||
deliver power over coax for radar and camera modules. They support
|
||||
software-configurable output switching and monitoring. The output voltage and
|
||||
current limit are fixed by the hardware design.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- maxim,max20086
|
||||
- maxim,max20087
|
||||
- maxim,max20088
|
||||
- maxim,max20089
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
enable-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO connected to the EN pin, active high
|
||||
|
||||
in-supply:
|
||||
description: Input supply for the camera outputs (IN pin, 3.0V to 15.0V)
|
||||
|
||||
vdd-supply:
|
||||
description: Input supply for the device (VDD pin, 3.0V to 5.5V)
|
||||
|
||||
regulators:
|
||||
type: object
|
||||
|
||||
patternProperties:
|
||||
"^OUT[1-4]$":
|
||||
type: object
|
||||
$ref: regulator.yaml#
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- in-supply
|
||||
- vdd-supply
|
||||
- regulators
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- maxim,max20088
|
||||
- maxim,max20089
|
||||
then:
|
||||
properties:
|
||||
regulators:
|
||||
properties:
|
||||
OUT3: false
|
||||
OUT4: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
regulator@28 {
|
||||
compatible = "maxim,max20087";
|
||||
reg = <0x28>;
|
||||
|
||||
in-supply = <®_12v0>;
|
||||
vdd-supply = <®_3v3>;
|
||||
|
||||
enable-gpios = <&gpio 108 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
regulators {
|
||||
OUT1 {
|
||||
regulator-name = "VOUT1";
|
||||
};
|
||||
OUT2 {
|
||||
regulator-name = "VOUT2";
|
||||
};
|
||||
OUT3 {
|
||||
regulator-name = "VOUT3";
|
||||
};
|
||||
OUT4 {
|
||||
regulator-name = "VOUT4";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
@ -86,6 +86,9 @@ properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -43,6 +43,7 @@ description: |
|
||||
For PM8150L, smps1 - smps8, ldo1 - ldo11, bob, flash, rgb
|
||||
For PM8350, smps1 - smps12, ldo1 - ldo10
|
||||
For PM8350C, smps1 - smps10, ldo1 - ldo13, bob
|
||||
For PM8450, smps1 - smps6, ldo1 - ldo4
|
||||
For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2
|
||||
For PMI8998, bob
|
||||
For PMR735A, smps1 - smps3, ldo1 - ldo7
|
||||
@ -62,7 +63,9 @@ properties:
|
||||
- qcom,pm8150l-rpmh-regulators
|
||||
- qcom,pm8350-rpmh-regulators
|
||||
- qcom,pm8350c-rpmh-regulators
|
||||
- qcom,pm8450-rpmh-regulators
|
||||
- qcom,pm8998-rpmh-regulators
|
||||
- qcom,pmg1110-rpmh-regulators
|
||||
- qcom,pmi8998-rpmh-regulators
|
||||
- qcom,pmm8155au-rpmh-regulators
|
||||
- qcom,pmr735a-rpmh-regulators
|
||||
|
@ -6,6 +6,7 @@ Qualcomm SPMI Regulators
|
||||
Definition: must be one of:
|
||||
"qcom,pm8004-regulators"
|
||||
"qcom,pm8005-regulators"
|
||||
"qcom,pm8226-regulators"
|
||||
"qcom,pm8841-regulators"
|
||||
"qcom,pm8916-regulators"
|
||||
"qcom,pm8941-regulators"
|
||||
|
@ -218,7 +218,7 @@ properties:
|
||||
description: Array of maximum spread between voltages of coupled regulators
|
||||
in microvolts, each value in the array relates to the corresponding
|
||||
couple specified by the regulator-coupled-with property.
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32-array"
|
||||
|
||||
regulator-max-step-microvolt:
|
||||
description: Maximum difference between current and target voltages
|
||||
|
@ -67,8 +67,9 @@ patternProperties:
|
||||
required:
|
||||
- regulator-name
|
||||
|
||||
properties:
|
||||
# 9 buck
|
||||
"^BUCK9$":
|
||||
BUCK9:
|
||||
type: object
|
||||
$ref: regulator.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
@ -11653,6 +11653,13 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml
|
||||
F: drivers/power/supply/max17042_battery.c
|
||||
|
||||
MAXIM MAX20086 CAMERA POWER PROTECTOR DRIVER
|
||||
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/regulator/maxim,max20086.yaml
|
||||
F: drivers/regulator/max20086-regulator.c
|
||||
|
||||
MAXIM MAX77650 PMIC MFD DRIVER
|
||||
M: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
|
@ -636,6 +636,15 @@ config REGULATOR_MAX8998
|
||||
via I2C bus. The provided regulator is suitable for S3C6410
|
||||
and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
|
||||
|
||||
config REGULATOR_MAX20086
|
||||
tristate "Maxim MAX20086-MAX20089 Camera Power Protectors"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
This driver controls a Maxim MAX20086-MAX20089 camera power
|
||||
protectorvia I2C bus. The regulator has 2 or 4 outputs depending on
|
||||
the device model. This driver is only capable to turn on/off them.
|
||||
|
||||
config REGULATOR_MAX77686
|
||||
tristate "Maxim 77686 regulator"
|
||||
depends on MFD_MAX77686 || COMPILE_TEST
|
||||
@ -1339,6 +1348,15 @@ config REGULATOR_TPS65912
|
||||
help
|
||||
This driver supports TPS65912 voltage regulator chip.
|
||||
|
||||
config REGULATOR_TPS68470
|
||||
tristate "TI TPS68470 PMIC Regulators Driver"
|
||||
depends on INTEL_SKL_INT3472 || COMPILE_TEST
|
||||
help
|
||||
This driver adds support for the TPS68470 PMIC to register
|
||||
regulators against the usual framework.
|
||||
|
||||
The module will be called "tps68470-regulator".
|
||||
|
||||
config REGULATOR_TWL4030
|
||||
tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
|
||||
depends on TWL4030_CORE
|
||||
@ -1415,4 +1433,3 @@ config REGULATOR_QCOM_LABIBB
|
||||
for LCD display panel.
|
||||
|
||||
endif
|
||||
|
||||
|
@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8997) += max8997-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
|
||||
obj-$(CONFIG_REGULATOR_MAX20086) += max20086-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
|
||||
@ -159,6 +160,7 @@ obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TPS68470) += tps68470-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o
|
||||
|
@ -125,27 +125,6 @@ static int bd71837_get_buck34_enable_hwctrl(struct regulator_dev *rdev)
|
||||
|
||||
return !!(BD718XX_BUCK_RUN_ON & val);
|
||||
}
|
||||
/*
|
||||
* On BD71837 (not on BD71847, BD71850, ...)
|
||||
* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed.
|
||||
* Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage
|
||||
* is changed. Hence we return -EBUSY for these if voltage is changed
|
||||
* when BUCK/LDO is enabled.
|
||||
*
|
||||
* On BD71847, BD71850, ... The LDO voltage can be changed when LDO is
|
||||
* enabled. But if voltage is increased the LDO power-good monitoring
|
||||
* must be disabled for the duration of changing + 1mS to ensure voltage
|
||||
* has reached the higher level before HW does next under voltage detection
|
||||
* cycle.
|
||||
*/
|
||||
static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev,
|
||||
unsigned int sel)
|
||||
{
|
||||
if (rdev->desc->ops->is_enabled(rdev))
|
||||
return -EBUSY;
|
||||
|
||||
return regulator_set_voltage_sel_regmap(rdev, sel);
|
||||
}
|
||||
|
||||
static void voltage_change_done(struct regulator_dev *rdev, unsigned int sel,
|
||||
unsigned int *mask)
|
||||
@ -642,22 +621,22 @@ BD718XX_OPS(bd71837_pickable_range_buck_ops,
|
||||
bd718x7_set_buck_ovp);
|
||||
|
||||
BD718XX_OPS(bd71837_ldo_regulator_ops, regulator_list_voltage_linear_range,
|
||||
NULL, bd71837_set_voltage_sel_restricted,
|
||||
NULL, rohm_regulator_set_voltage_sel_restricted,
|
||||
regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp,
|
||||
NULL);
|
||||
|
||||
BD718XX_OPS(bd71837_ldo_regulator_nolinear_ops, regulator_list_voltage_table,
|
||||
NULL, bd71837_set_voltage_sel_restricted,
|
||||
NULL, rohm_regulator_set_voltage_sel_restricted,
|
||||
regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp,
|
||||
NULL);
|
||||
|
||||
BD718XX_OPS(bd71837_buck_regulator_ops, regulator_list_voltage_linear_range,
|
||||
NULL, bd71837_set_voltage_sel_restricted,
|
||||
NULL, rohm_regulator_set_voltage_sel_restricted,
|
||||
regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
|
||||
NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp);
|
||||
|
||||
BD718XX_OPS(bd71837_buck_regulator_nolinear_ops, regulator_list_voltage_table,
|
||||
regulator_map_voltage_ascend, bd71837_set_voltage_sel_restricted,
|
||||
regulator_map_voltage_ascend, rohm_regulator_set_voltage_sel_restricted,
|
||||
regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
|
||||
NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp);
|
||||
/*
|
||||
|
@ -86,6 +86,22 @@ static struct da9121_range da9121_3A_1phase_current = {
|
||||
.reg_max = 6,
|
||||
};
|
||||
|
||||
static struct da9121_range da914x_40A_4phase_current = {
|
||||
.val_min = 14000000,
|
||||
.val_max = 80000000,
|
||||
.val_stp = 2000000,
|
||||
.reg_min = 1,
|
||||
.reg_max = 14,
|
||||
};
|
||||
|
||||
static struct da9121_range da914x_20A_2phase_current = {
|
||||
.val_min = 7000000,
|
||||
.val_max = 40000000,
|
||||
.val_stp = 2000000,
|
||||
.reg_min = 1,
|
||||
.reg_max = 14,
|
||||
};
|
||||
|
||||
struct da9121_variant_info {
|
||||
int num_bucks;
|
||||
int num_phases;
|
||||
@ -97,6 +113,8 @@ static const struct da9121_variant_info variant_parameters[] = {
|
||||
{ 2, 1, &da9121_3A_1phase_current }, //DA9121_TYPE_DA9220_DA9132
|
||||
{ 2, 1, &da9121_5A_1phase_current }, //DA9121_TYPE_DA9122_DA9131
|
||||
{ 1, 2, &da9121_6A_2phase_current }, //DA9121_TYPE_DA9217
|
||||
{ 1, 4, &da914x_40A_4phase_current }, //DA9121_TYPE_DA9141
|
||||
{ 1, 2, &da914x_20A_2phase_current }, //DA9121_TYPE_DA9142
|
||||
};
|
||||
|
||||
struct da9121_field {
|
||||
@ -253,6 +271,11 @@ static int da9121_set_current_limit(struct regulator_dev *rdev,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (rdev->desc->ops->is_enabled(rdev)) {
|
||||
ret = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = da9121_ceiling_selector(rdev, min_ua, max_ua, &sel);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
@ -537,11 +560,65 @@ static const struct regulator_desc da9217_reg = {
|
||||
.vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT,
|
||||
};
|
||||
|
||||
#define DA914X_MIN_MV 500
|
||||
#define DA914X_MAX_MV 1000
|
||||
#define DA914X_STEP_MV 10
|
||||
#define DA914X_MIN_SEL (DA914X_MIN_MV / DA914X_STEP_MV)
|
||||
#define DA914X_N_VOLTAGES (((DA914X_MAX_MV - DA914X_MIN_MV) / DA914X_STEP_MV) \
|
||||
+ 1 + DA914X_MIN_SEL)
|
||||
|
||||
static const struct regulator_desc da9141_reg = {
|
||||
.id = DA9121_IDX_BUCK1,
|
||||
.name = "DA9141",
|
||||
.of_match = "buck1",
|
||||
.of_parse_cb = da9121_of_parse_cb,
|
||||
.owner = THIS_MODULE,
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.of_map_mode = da9121_map_mode,
|
||||
.ops = &da9121_buck_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = DA914X_N_VOLTAGES,
|
||||
.min_uV = DA914X_MIN_MV * 1000,
|
||||
.uV_step = DA914X_STEP_MV * 1000,
|
||||
.linear_min_sel = DA914X_MIN_SEL,
|
||||
.vsel_reg = DA9121_REG_BUCK_BUCK1_5,
|
||||
.vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT,
|
||||
.enable_reg = DA9121_REG_BUCK_BUCK1_0,
|
||||
.enable_mask = DA9121_MASK_BUCK_BUCKx_0_CHx_EN,
|
||||
/* Default value of BUCK_BUCK1_0.CH1_SRC_DVC_UP */
|
||||
.ramp_delay = 20000,
|
||||
/* tBUCK_EN */
|
||||
.enable_time = 20,
|
||||
};
|
||||
|
||||
static const struct regulator_desc da9142_reg = {
|
||||
.id = DA9121_IDX_BUCK1,
|
||||
.name = "DA9142 BUCK1",
|
||||
.of_match = "buck1",
|
||||
.of_parse_cb = da9121_of_parse_cb,
|
||||
.owner = THIS_MODULE,
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.of_map_mode = da9121_map_mode,
|
||||
.ops = &da9121_buck_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = DA914X_N_VOLTAGES,
|
||||
.min_uV = DA914X_MIN_MV * 1000,
|
||||
.uV_step = DA914X_STEP_MV * 1000,
|
||||
.linear_min_sel = DA914X_MIN_SEL,
|
||||
.enable_reg = DA9121_REG_BUCK_BUCK1_0,
|
||||
.enable_mask = DA9121_MASK_BUCK_BUCKx_0_CHx_EN,
|
||||
.vsel_reg = DA9121_REG_BUCK_BUCK1_5,
|
||||
.vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT,
|
||||
};
|
||||
|
||||
|
||||
static const struct regulator_desc *local_da9121_regulators[][DA9121_IDX_MAX] = {
|
||||
[DA9121_TYPE_DA9121_DA9130] = { &da9121_reg, NULL },
|
||||
[DA9121_TYPE_DA9220_DA9132] = { &da9220_reg[0], &da9220_reg[1] },
|
||||
[DA9121_TYPE_DA9122_DA9131] = { &da9122_reg[0], &da9122_reg[1] },
|
||||
[DA9121_TYPE_DA9217] = { &da9217_reg, NULL },
|
||||
[DA9121_TYPE_DA9141] = { &da9141_reg, NULL },
|
||||
[DA9121_TYPE_DA9142] = { &da9142_reg, NULL },
|
||||
};
|
||||
|
||||
static void da9121_status_poll_on(struct work_struct *work)
|
||||
@ -835,7 +912,7 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (device_id != DA9121_DEVICE_ID) {
|
||||
if ((device_id != DA9121_DEVICE_ID) && (device_id != DA914x_DEVICE_ID)) {
|
||||
dev_err(chip->dev, "Invalid device ID: 0x%02x\n", device_id);
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
@ -877,6 +954,22 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip)
|
||||
break;
|
||||
}
|
||||
|
||||
if (device_id == DA914x_DEVICE_ID) {
|
||||
switch (chip->subvariant_id) {
|
||||
case DA9121_SUBTYPE_DA9141:
|
||||
type = "DA9141";
|
||||
config_match = (variant_vrc == DA9141_VARIANT_VRC);
|
||||
break;
|
||||
case DA9121_SUBTYPE_DA9142:
|
||||
type = "DA9142";
|
||||
config_match = (variant_vrc == DA9142_VARIANT_VRC);
|
||||
break;
|
||||
default:
|
||||
type = "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(chip->dev,
|
||||
"Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n",
|
||||
device_id, variant_id, type);
|
||||
@ -890,8 +983,10 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip)
|
||||
variant_mrc = (variant_id & DA9121_MASK_OTP_VARIANT_ID_MRC)
|
||||
>> DA9121_SHIFT_OTP_VARIANT_ID_MRC;
|
||||
|
||||
if ((device_id == DA9121_DEVICE_ID) &&
|
||||
(variant_mrc < DA9121_VARIANT_MRC_BASE)) {
|
||||
if (((device_id == DA9121_DEVICE_ID) &&
|
||||
(variant_mrc < DA9121_VARIANT_MRC_BASE)) ||
|
||||
((device_id == DA914x_DEVICE_ID) &&
|
||||
(variant_mrc != DA914x_VARIANT_MRC_BASE))) {
|
||||
dev_err(chip->dev,
|
||||
"Cannot support variant MRC: 0x%02X\n", variant_mrc);
|
||||
ret = -EINVAL;
|
||||
@ -931,6 +1026,14 @@ static int da9121_assign_chip_model(struct i2c_client *i2c,
|
||||
chip->variant_id = DA9121_TYPE_DA9220_DA9132;
|
||||
regmap = &da9121_2ch_regmap_config;
|
||||
break;
|
||||
case DA9121_SUBTYPE_DA9141:
|
||||
chip->variant_id = DA9121_TYPE_DA9141;
|
||||
regmap = &da9121_1ch_regmap_config;
|
||||
break;
|
||||
case DA9121_SUBTYPE_DA9142:
|
||||
chip->variant_id = DA9121_TYPE_DA9142;
|
||||
regmap = &da9121_2ch_regmap_config;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set these up for of_regulator_match call which may want .of_map_modes */
|
||||
@ -1010,6 +1113,8 @@ static const struct of_device_id da9121_dt_ids[] = {
|
||||
{ .compatible = "dlg,da9131", .data = (void *) DA9121_SUBTYPE_DA9131 },
|
||||
{ .compatible = "dlg,da9220", .data = (void *) DA9121_SUBTYPE_DA9220 },
|
||||
{ .compatible = "dlg,da9132", .data = (void *) DA9121_SUBTYPE_DA9132 },
|
||||
{ .compatible = "dlg,da9141", .data = (void *) DA9121_SUBTYPE_DA9141 },
|
||||
{ .compatible = "dlg,da9142", .data = (void *) DA9121_SUBTYPE_DA9142 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, da9121_dt_ids);
|
||||
@ -1065,7 +1170,7 @@ static int da9121_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct da9121 *chip = i2c_get_clientdata(i2c);
|
||||
const int mask_all[4] = { 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
free_irq(chip->chip_irq, chip);
|
||||
cancel_delayed_work_sync(&chip->work);
|
||||
@ -1073,7 +1178,7 @@ static int da9121_i2c_remove(struct i2c_client *i2c)
|
||||
ret = regmap_bulk_write(chip->regmap, DA9121_REG_SYS_MASK_0, mask_all, 4);
|
||||
if (ret != 0)
|
||||
dev_err(chip->dev, "Failed to set IRQ masks: %d\n", ret);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id da9121_i2c_id[] = {
|
||||
@ -1084,6 +1189,8 @@ static const struct i2c_device_id da9121_i2c_id[] = {
|
||||
{"da9131", DA9121_TYPE_DA9122_DA9131},
|
||||
{"da9220", DA9121_TYPE_DA9220_DA9132},
|
||||
{"da9132", DA9121_TYPE_DA9220_DA9132},
|
||||
{"da9141", DA9121_TYPE_DA9141},
|
||||
{"da9142", DA9121_TYPE_DA9142},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, da9121_i2c_id);
|
||||
|
@ -26,7 +26,9 @@ enum da9121_variant {
|
||||
DA9121_TYPE_DA9121_DA9130,
|
||||
DA9121_TYPE_DA9220_DA9132,
|
||||
DA9121_TYPE_DA9122_DA9131,
|
||||
DA9121_TYPE_DA9217
|
||||
DA9121_TYPE_DA9217,
|
||||
DA9121_TYPE_DA9141,
|
||||
DA9121_TYPE_DA9142
|
||||
};
|
||||
|
||||
enum da9121_subvariant {
|
||||
@ -36,7 +38,9 @@ enum da9121_subvariant {
|
||||
DA9121_SUBTYPE_DA9132,
|
||||
DA9121_SUBTYPE_DA9122,
|
||||
DA9121_SUBTYPE_DA9131,
|
||||
DA9121_SUBTYPE_DA9217
|
||||
DA9121_SUBTYPE_DA9217,
|
||||
DA9121_SUBTYPE_DA9141,
|
||||
DA9121_SUBTYPE_DA9142
|
||||
};
|
||||
|
||||
/* Minimum, maximum and default polling millisecond periods are provided
|
||||
@ -70,6 +74,14 @@ enum da9121_subvariant {
|
||||
#define DA9121_REG_SYS_GPIO1_1 0x13
|
||||
#define DA9121_REG_SYS_GPIO2_0 0x14
|
||||
#define DA9121_REG_SYS_GPIO2_1 0x15
|
||||
#define DA914x_REG_SYS_GPIO3_0 0x16
|
||||
#define DA914x_REG_SYS_GPIO3_1 0x17
|
||||
#define DA914x_REG_SYS_GPIO4_0 0x18
|
||||
#define DA914x_REG_SYS_GPIO4_1 0x19
|
||||
#define DA914x_REG_SYS_ADMUX1_0 0x1A
|
||||
#define DA914x_REG_SYS_ADMUX1_1 0x1B
|
||||
#define DA914x_REG_SYS_ADMUX2_0 0x1C
|
||||
#define DA914x_REG_SYS_ADMUX2_1 0x1D
|
||||
#define DA9121_REG_BUCK_BUCK1_0 0x20
|
||||
#define DA9121_REG_BUCK_BUCK1_1 0x21
|
||||
#define DA9121_REG_BUCK_BUCK1_2 0x22
|
||||
@ -276,6 +288,7 @@ enum da9121_subvariant {
|
||||
#define DA9121_MASK_OTP_DEVICE_ID_DEV_ID 0xFF
|
||||
|
||||
#define DA9121_DEVICE_ID 0x05
|
||||
#define DA914x_DEVICE_ID 0x26
|
||||
|
||||
/* DA9121_REG_OTP_VARIANT_ID */
|
||||
|
||||
@ -293,6 +306,10 @@ enum da9121_subvariant {
|
||||
#define DA9131_VARIANT_VRC 0x1
|
||||
#define DA9132_VARIANT_VRC 0x2
|
||||
|
||||
#define DA914x_VARIANT_MRC_BASE 0x0
|
||||
#define DA9141_VARIANT_VRC 0x1
|
||||
#define DA9142_VARIANT_VRC 0x2
|
||||
|
||||
/* DA9121_REG_OTP_CUSTOMER_ID */
|
||||
|
||||
#define DA9121_MASK_OTP_CUSTOMER_ID_CUST_ID 0xFF
|
||||
|
@ -320,7 +320,9 @@ static void init_rdev_errors(struct regulator_irq *h)
|
||||
* IRQF_ONESHOT when requesting the (threaded) irq.
|
||||
* @common_errs: Errors which can be flagged by this IRQ for all rdevs.
|
||||
* When IRQ is re-enabled these errors will be cleared
|
||||
* from all associated regulators
|
||||
* from all associated regulators. Use this instead of the
|
||||
* per_rdev_errs if you use
|
||||
* regulator_irq_map_event_simple() for event mapping.
|
||||
* @per_rdev_errs: Optional error flag array describing errors specific
|
||||
* for only some of the regulators. These errors will be
|
||||
* or'ed with common errors. If this is given the array
|
||||
@ -395,3 +397,40 @@ void regulator_irq_helper_cancel(void **handle)
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_irq_helper_cancel);
|
||||
|
||||
/**
|
||||
* regulator_irq_map_event_simple - regulator IRQ notification for trivial IRQs
|
||||
*
|
||||
* @irq: Number of IRQ that occurred
|
||||
* @rid: Information about the event IRQ indicates
|
||||
* @dev_mask: mask indicating the regulator originating the IRQ
|
||||
*
|
||||
* Regulators whose IRQ has single, well defined purpose (always indicate
|
||||
* exactly one event, and are relevant to exactly one regulator device) can
|
||||
* use this function as their map_event callbac for their regulator IRQ
|
||||
* notification helperk. Exactly one rdev and exactly one error (in
|
||||
* "common_errs"-field) can be given at IRQ helper registration for
|
||||
* regulator_irq_map_event_simple() to be viable.
|
||||
*/
|
||||
int regulator_irq_map_event_simple(int irq, struct regulator_irq_data *rid,
|
||||
unsigned long *dev_mask)
|
||||
{
|
||||
int err = rid->states[0].possible_errs;
|
||||
|
||||
*dev_mask = 1;
|
||||
/*
|
||||
* This helper should only be used in a situation where the IRQ
|
||||
* can indicate only one type of problem for one specific rdev.
|
||||
* Something fishy is going on if we are having multiple rdevs or ERROR
|
||||
* flags here.
|
||||
*/
|
||||
if (WARN_ON(rid->num_states != 1 || hweight32(err) != 1))
|
||||
return 0;
|
||||
|
||||
rid->states[0].errors = err;
|
||||
rid->states[0].notifs = regulator_err2notif(err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_irq_map_event_simple);
|
||||
|
||||
|
332
drivers/regulator/max20086-regulator.c
Normal file
332
drivers/regulator/max20086-regulator.c
Normal file
@ -0,0 +1,332 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
//
|
||||
// max20086-regulator.c - MAX20086-MAX20089 camera power protector driver
|
||||
//
|
||||
// Copyright (C) 2022 Laurent Pinchart <laurent.pinchart@idesonboard.com>
|
||||
// Copyright (C) 2018 Avnet, Inc.
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Register Offset */
|
||||
#define MAX20086_REG_MASK 0x00
|
||||
#define MAX20086_REG_CONFIG 0x01
|
||||
#define MAX20086_REG_ID 0x02
|
||||
#define MAX20086_REG_STAT1 0x03
|
||||
#define MAX20086_REG_STAT2_L 0x04
|
||||
#define MAX20086_REG_STAT2_H 0x05
|
||||
#define MAX20086_REG_ADC1 0x06
|
||||
#define MAX20086_REG_ADC2 0x07
|
||||
#define MAX20086_REG_ADC3 0x08
|
||||
#define MAX20086_REG_ADC4 0x09
|
||||
|
||||
/* DEVICE IDs */
|
||||
#define MAX20086_DEVICE_ID_MAX20086 0x40
|
||||
#define MAX20086_DEVICE_ID_MAX20087 0x20
|
||||
#define MAX20086_DEVICE_ID_MAX20088 0x10
|
||||
#define MAX20086_DEVICE_ID_MAX20089 0x00
|
||||
#define DEVICE_ID_MASK 0xf0
|
||||
|
||||
/* Register bits */
|
||||
#define MAX20086_EN_MASK 0x0f
|
||||
#define MAX20086_EN_OUT1 0x01
|
||||
#define MAX20086_EN_OUT2 0x02
|
||||
#define MAX20086_EN_OUT3 0x04
|
||||
#define MAX20086_EN_OUT4 0x08
|
||||
#define MAX20086_INT_DISABLE_ALL 0x3f
|
||||
|
||||
#define MAX20086_MAX_REGULATORS 4
|
||||
|
||||
struct max20086_chip_info {
|
||||
u8 id;
|
||||
unsigned int num_outputs;
|
||||
};
|
||||
|
||||
struct max20086_regulator {
|
||||
struct device_node *of_node;
|
||||
struct regulator_init_data *init_data;
|
||||
const struct regulator_desc *desc;
|
||||
struct regulator_dev *rdev;
|
||||
};
|
||||
|
||||
struct max20086 {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct gpio_desc *ena_gpiod;
|
||||
|
||||
const struct max20086_chip_info *info;
|
||||
|
||||
struct max20086_regulator regulators[MAX20086_MAX_REGULATORS];
|
||||
};
|
||||
|
||||
static const struct regulator_ops max20086_buck_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
};
|
||||
|
||||
#define MAX20086_REGULATOR_DESC(n) \
|
||||
{ \
|
||||
.name = "OUT"#n, \
|
||||
.supply_name = "in", \
|
||||
.id = (n) - 1, \
|
||||
.ops = &max20086_buck_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.enable_reg = MAX20086_REG_CONFIG, \
|
||||
.enable_mask = 1 << ((n) - 1), \
|
||||
.enable_val = 1 << ((n) - 1), \
|
||||
.disable_val = 0, \
|
||||
}
|
||||
|
||||
static const char * const max20086_output_names[] = {
|
||||
"OUT1",
|
||||
"OUT2",
|
||||
"OUT3",
|
||||
"OUT4",
|
||||
};
|
||||
|
||||
static const struct regulator_desc max20086_regulators[] = {
|
||||
MAX20086_REGULATOR_DESC(1),
|
||||
MAX20086_REGULATOR_DESC(2),
|
||||
MAX20086_REGULATOR_DESC(3),
|
||||
MAX20086_REGULATOR_DESC(4),
|
||||
};
|
||||
|
||||
static int max20086_regulators_register(struct max20086 *chip)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < chip->info->num_outputs; i++) {
|
||||
struct max20086_regulator *reg = &chip->regulators[i];
|
||||
struct regulator_config config = { };
|
||||
struct regulator_dev *rdev;
|
||||
|
||||
config.dev = chip->dev;
|
||||
config.init_data = reg->init_data;
|
||||
config.driver_data = chip;
|
||||
config.of_node = reg->of_node;
|
||||
config.regmap = chip->regmap;
|
||||
config.ena_gpiod = chip->ena_gpiod;
|
||||
|
||||
rdev = devm_regulator_register(chip->dev, reg->desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to register regulator output %s\n",
|
||||
reg->desc->name);
|
||||
return PTR_ERR(rdev);
|
||||
}
|
||||
|
||||
reg->rdev = rdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max20086_parse_regulators_dt(struct max20086 *chip, bool *boot_on)
|
||||
{
|
||||
struct of_regulator_match matches[MAX20086_MAX_REGULATORS] = { };
|
||||
struct device_node *node;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
node = of_get_child_by_name(chip->dev->of_node, "regulators");
|
||||
if (!node) {
|
||||
dev_err(chip->dev, "regulators node not found\n");
|
||||
return PTR_ERR(node);
|
||||
}
|
||||
|
||||
for (i = 0; i < chip->info->num_outputs; ++i)
|
||||
matches[i].name = max20086_output_names[i];
|
||||
|
||||
ret = of_regulator_match(chip->dev, node, matches,
|
||||
chip->info->num_outputs);
|
||||
of_node_put(node);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to match regulators\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*boot_on = false;
|
||||
|
||||
for (i = 0; i < chip->info->num_outputs; i++) {
|
||||
struct max20086_regulator *reg = &chip->regulators[i];
|
||||
|
||||
reg->init_data = matches[i].init_data;
|
||||
reg->of_node = matches[i].of_node;
|
||||
reg->desc = &max20086_regulators[i];
|
||||
|
||||
if (reg->init_data) {
|
||||
if (reg->init_data->constraints.always_on ||
|
||||
reg->init_data->constraints.boot_on)
|
||||
*boot_on = true;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max20086_detect(struct max20086 *chip)
|
||||
{
|
||||
unsigned int data;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(chip->regmap, MAX20086_REG_ID, &data);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to read DEVICE_ID reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((data & DEVICE_ID_MASK) != chip->info->id) {
|
||||
dev_err(chip->dev, "Invalid device ID 0x%02x\n", data);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool max20086_gen_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MAX20086_REG_MASK:
|
||||
case MAX20086_REG_CONFIG:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config max20086_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.writeable_reg = max20086_gen_is_writeable_reg,
|
||||
.max_register = 0x9,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
static int max20086_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct max20086 *chip;
|
||||
enum gpiod_flags flags;
|
||||
bool boot_on;
|
||||
int ret;
|
||||
|
||||
chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->dev = &i2c->dev;
|
||||
chip->info = device_get_match_data(chip->dev);
|
||||
|
||||
i2c_set_clientdata(i2c, chip);
|
||||
|
||||
chip->regmap = devm_regmap_init_i2c(i2c, &max20086_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
ret = PTR_ERR(chip->regmap);
|
||||
dev_err(chip->dev, "Failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max20086_parse_regulators_dt(chip, &boot_on);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = max20086_detect(chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Until IRQ support is added, just disable all interrupts. */
|
||||
ret = regmap_update_bits(chip->regmap, MAX20086_REG_MASK,
|
||||
MAX20086_INT_DISABLE_ALL,
|
||||
MAX20086_INT_DISABLE_ALL);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to disable interrupts: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the enable GPIO. If any of the outputs is marked as being
|
||||
* enabled at boot, request the GPIO with an initial high state to
|
||||
* avoid disabling outputs that may have been turned on by the boot
|
||||
* loader. Otherwise, request it with a low state to enter lower-power
|
||||
* shutdown.
|
||||
*/
|
||||
flags = boot_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
|
||||
chip->ena_gpiod = devm_gpiod_get(chip->dev, "enable", flags);
|
||||
if (IS_ERR(chip->ena_gpiod)) {
|
||||
ret = PTR_ERR(chip->ena_gpiod);
|
||||
dev_err(chip->dev, "Failed to get enable GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max20086_regulators_register(chip);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to register regulators: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max20086_i2c_id[] = {
|
||||
{ "max20086" },
|
||||
{ "max20087" },
|
||||
{ "max20088" },
|
||||
{ "max20089" },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, max20086_i2c_id);
|
||||
|
||||
static const struct of_device_id max20086_dt_ids[] = {
|
||||
{
|
||||
.compatible = "maxim,max20086",
|
||||
.data = &(const struct max20086_chip_info) {
|
||||
.id = MAX20086_DEVICE_ID_MAX20086,
|
||||
.num_outputs = 4,
|
||||
}
|
||||
}, {
|
||||
.compatible = "maxim,max20087",
|
||||
.data = &(const struct max20086_chip_info) {
|
||||
.id = MAX20086_DEVICE_ID_MAX20087,
|
||||
.num_outputs = 4,
|
||||
}
|
||||
}, {
|
||||
.compatible = "maxim,max20088",
|
||||
.data = &(const struct max20086_chip_info) {
|
||||
.id = MAX20086_DEVICE_ID_MAX20088,
|
||||
.num_outputs = 2,
|
||||
}
|
||||
}, {
|
||||
.compatible = "maxim,max20089",
|
||||
.data = &(const struct max20086_chip_info) {
|
||||
.id = MAX20086_DEVICE_ID_MAX20089,
|
||||
.num_outputs = 2,
|
||||
}
|
||||
},
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, max20086_dt_ids);
|
||||
|
||||
static struct i2c_driver max20086_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "max20086",
|
||||
.of_match_table = of_match_ptr(max20086_dt_ids),
|
||||
},
|
||||
.probe_new = max20086_i2c_probe,
|
||||
.id_table = max20086_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(max20086_regulator_driver);
|
||||
|
||||
MODULE_AUTHOR("Watson Chow <watson.chow@avnet.com>");
|
||||
MODULE_DESCRIPTION("MAX20086-MAX20089 Camera Power Protector Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -183,7 +183,7 @@ static const unsigned int ldo_volt_table4[] = {
|
||||
static int mt6380_regulator_set_mode(struct regulator_dev *rdev,
|
||||
unsigned int mode)
|
||||
{
|
||||
int ret, val = 0;
|
||||
int val = 0;
|
||||
struct mt6380_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
|
||||
switch (mode) {
|
||||
@ -199,10 +199,8 @@ static int mt6380_regulator_set_mode(struct regulator_dev *rdev,
|
||||
|
||||
val <<= ffs(info->modeset_mask) - 1;
|
||||
|
||||
ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
|
||||
return regmap_update_bits(rdev->regmap, info->modeset_reg,
|
||||
info->modeset_mask, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int mt6380_regulator_get_mode(struct regulator_dev *rdev)
|
||||
|
@ -260,7 +260,7 @@ static irqreturn_t qcom_labibb_ocp_isr(int irq, void *chip)
|
||||
|
||||
/* If the regulator is not enabled, this is a fake event */
|
||||
if (!ops->is_enabled(vreg->rdev))
|
||||
return 0;
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* If we tried to recover for too many times it's not getting better */
|
||||
if (vreg->ocp_irq_count > LABIBB_MAX_OCP_COUNT)
|
||||
|
@ -814,6 +814,11 @@ static const struct rpmh_vreg_init_data pm8998_vreg_data[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct rpmh_vreg_init_data pmg1110_vreg_data[] = {
|
||||
RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = {
|
||||
RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
|
||||
{}
|
||||
@ -969,6 +974,20 @@ static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct rpmh_vreg_init_data pm8450_vreg_data[] = {
|
||||
RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"),
|
||||
RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
|
||||
RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"),
|
||||
RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"),
|
||||
RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"),
|
||||
RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"),
|
||||
RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
|
||||
RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
|
||||
RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
|
||||
RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"),
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
|
||||
RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
|
||||
RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515, "vdd-s2"),
|
||||
@ -1213,10 +1232,18 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
|
||||
.compatible = "qcom,pm8350c-rpmh-regulators",
|
||||
.data = pm8350c_vreg_data,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,pm8450-rpmh-regulators",
|
||||
.data = pm8450_vreg_data,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,pm8998-rpmh-regulators",
|
||||
.data = pm8998_vreg_data,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,pmg1110-rpmh-regulators",
|
||||
.data = pmg1110_vreg_data,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,pmi8998-rpmh-regulators",
|
||||
.data = pmi8998_vreg_data,
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/soc/qcom/smd-rpm.h>
|
||||
|
||||
struct qcom_rpm_reg {
|
||||
@ -1239,52 +1240,91 @@ static const struct of_device_id rpm_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rpm_of_match);
|
||||
|
||||
/**
|
||||
* rpm_regulator_init_vreg() - initialize all attributes of a qcom_smd-regulator
|
||||
* @vreg: Pointer to the individual qcom_smd-regulator resource
|
||||
* @dev: Pointer to the top level qcom_smd-regulator PMIC device
|
||||
* @node: Pointer to the individual qcom_smd-regulator resource
|
||||
* device node
|
||||
* @rpm: Pointer to the rpm bus node
|
||||
* @pmic_rpm_data: Pointer to a null-terminated array of qcom_smd-regulator
|
||||
* resources defined for the top level PMIC device
|
||||
*
|
||||
* Return: 0 on success, errno on failure
|
||||
*/
|
||||
static int rpm_regulator_init_vreg(struct qcom_rpm_reg *vreg, struct device *dev,
|
||||
struct device_node *node, struct qcom_smd_rpm *rpm,
|
||||
const struct rpm_regulator_data *pmic_rpm_data)
|
||||
{
|
||||
struct regulator_config config = {};
|
||||
const struct rpm_regulator_data *rpm_data;
|
||||
struct regulator_dev *rdev;
|
||||
int ret;
|
||||
|
||||
for (rpm_data = pmic_rpm_data; rpm_data->name; rpm_data++)
|
||||
if (of_node_name_eq(node, rpm_data->name))
|
||||
break;
|
||||
|
||||
if (!rpm_data->name) {
|
||||
dev_err(dev, "Unknown regulator %pOFn\n", node);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vreg->dev = dev;
|
||||
vreg->rpm = rpm;
|
||||
vreg->type = rpm_data->type;
|
||||
vreg->id = rpm_data->id;
|
||||
|
||||
memcpy(&vreg->desc, rpm_data->desc, sizeof(vreg->desc));
|
||||
vreg->desc.name = rpm_data->name;
|
||||
vreg->desc.supply_name = rpm_data->supply;
|
||||
vreg->desc.owner = THIS_MODULE;
|
||||
vreg->desc.type = REGULATOR_VOLTAGE;
|
||||
vreg->desc.of_match = rpm_data->name;
|
||||
|
||||
config.dev = dev;
|
||||
config.of_node = node;
|
||||
config.driver_data = vreg;
|
||||
|
||||
rdev = devm_regulator_register(dev, &vreg->desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
ret = PTR_ERR(rdev);
|
||||
dev_err(dev, "%pOFn: devm_regulator_register() failed, ret=%d\n", node, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpm_reg_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct rpm_regulator_data *reg;
|
||||
const struct of_device_id *match;
|
||||
struct regulator_config config = { };
|
||||
struct regulator_dev *rdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct rpm_regulator_data *vreg_data;
|
||||
struct device_node *node;
|
||||
struct qcom_rpm_reg *vreg;
|
||||
struct qcom_smd_rpm *rpm;
|
||||
int ret;
|
||||
|
||||
rpm = dev_get_drvdata(pdev->dev.parent);
|
||||
if (!rpm) {
|
||||
dev_err(&pdev->dev, "unable to retrieve handle to rpm\n");
|
||||
dev_err(&pdev->dev, "Unable to retrieve handle to rpm\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
match = of_match_device(rpm_of_match, &pdev->dev);
|
||||
if (!match) {
|
||||
dev_err(&pdev->dev, "failed to match device\n");
|
||||
vreg_data = of_device_get_match_data(dev);
|
||||
if (!vreg_data)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (reg = match->data; reg->name; reg++) {
|
||||
for_each_available_child_of_node(dev->of_node, node) {
|
||||
vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
|
||||
if (!vreg)
|
||||
return -ENOMEM;
|
||||
|
||||
vreg->dev = &pdev->dev;
|
||||
vreg->type = reg->type;
|
||||
vreg->id = reg->id;
|
||||
vreg->rpm = rpm;
|
||||
ret = rpm_regulator_init_vreg(vreg, dev, node, rpm, vreg_data);
|
||||
|
||||
memcpy(&vreg->desc, reg->desc, sizeof(vreg->desc));
|
||||
|
||||
vreg->desc.id = -1;
|
||||
vreg->desc.owner = THIS_MODULE;
|
||||
vreg->desc.type = REGULATOR_VOLTAGE;
|
||||
vreg->desc.name = reg->name;
|
||||
vreg->desc.supply_name = reg->supply;
|
||||
vreg->desc.of_match = reg->name;
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.driver_data = vreg;
|
||||
rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(&pdev->dev, "failed to register %s\n", reg->name);
|
||||
return PTR_ERR(rdev);
|
||||
if (ret < 0) {
|
||||
of_node_put(node);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1895,6 +1895,44 @@ static const struct spmi_regulator_data pm8941_regulators[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct spmi_regulator_data pm8226_regulators[] = {
|
||||
{ "s1", 0x1400, "vdd_s1", },
|
||||
{ "s2", 0x1700, "vdd_s2", },
|
||||
{ "s3", 0x1a00, "vdd_s3", },
|
||||
{ "s4", 0x1d00, "vdd_s4", },
|
||||
{ "s5", 0x2000, "vdd_s5", },
|
||||
{ "l1", 0x4000, "vdd_l1_l2_l4_l5", },
|
||||
{ "l2", 0x4100, "vdd_l1_l2_l4_l5", },
|
||||
{ "l3", 0x4200, "vdd_l3_l24_l26", },
|
||||
{ "l4", 0x4300, "vdd_l1_l2_l4_l5", },
|
||||
{ "l5", 0x4400, "vdd_l1_l2_l4_l5", },
|
||||
{ "l6", 0x4500, "vdd_l6_l7_l8_l9_l27", },
|
||||
{ "l7", 0x4600, "vdd_l6_l7_l8_l9_l27", },
|
||||
{ "l8", 0x4700, "vdd_l6_l7_l8_l9_l27", },
|
||||
{ "l9", 0x4800, "vdd_l6_l7_l8_l9_l27", },
|
||||
{ "l10", 0x4900, "vdd_l10_l11_l13", },
|
||||
{ "l11", 0x4a00, "vdd_l10_l11_l13", },
|
||||
{ "l12", 0x4b00, "vdd_l12_l14", },
|
||||
{ "l13", 0x4c00, "vdd_l10_l11_l13", },
|
||||
{ "l14", 0x4d00, "vdd_l12_l14", },
|
||||
{ "l15", 0x4e00, "vdd_l15_l16_l17_l18", },
|
||||
{ "l16", 0x4f00, "vdd_l15_l16_l17_l18", },
|
||||
{ "l17", 0x5000, "vdd_l15_l16_l17_l18", },
|
||||
{ "l18", 0x5100, "vdd_l15_l16_l17_l18", },
|
||||
{ "l19", 0x5200, "vdd_l19_l20_l21_l22_l23_l28", },
|
||||
{ "l20", 0x5300, "vdd_l19_l20_l21_l22_l23_l28", },
|
||||
{ "l21", 0x5400, "vdd_l19_l20_l21_l22_l23_l28", },
|
||||
{ "l22", 0x5500, "vdd_l19_l20_l21_l22_l23_l28", },
|
||||
{ "l23", 0x5600, "vdd_l19_l20_l21_l22_l23_l28", },
|
||||
{ "l24", 0x5700, "vdd_l3_l24_l26", },
|
||||
{ "l25", 0x5800, "vdd_l25", },
|
||||
{ "l26", 0x5900, "vdd_l3_l24_l26", },
|
||||
{ "l27", 0x5a00, "vdd_l6_l7_l8_l9_l27", },
|
||||
{ "l28", 0x5b00, "vdd_l19_l20_l21_l22_l23_l28", },
|
||||
{ "lvs1", 0x8000, "vdd_lvs1", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct spmi_regulator_data pm8841_regulators[] = {
|
||||
{ "s1", 0x1400, "vdd_s1", },
|
||||
{ "s2", 0x1700, "vdd_s2", NULL, 0x1c08 },
|
||||
@ -2095,6 +2133,7 @@ static const struct spmi_regulator_data pms405_regulators[] = {
|
||||
static const struct of_device_id qcom_spmi_regulator_match[] = {
|
||||
{ .compatible = "qcom,pm8004-regulators", .data = &pm8004_regulators },
|
||||
{ .compatible = "qcom,pm8005-regulators", .data = &pm8005_regulators },
|
||||
{ .compatible = "qcom,pm8226-regulators", .data = &pm8226_regulators },
|
||||
{ .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators },
|
||||
{ .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators },
|
||||
{ .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators },
|
||||
|
@ -112,6 +112,22 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
|
||||
}
|
||||
EXPORT_SYMBOL(rohm_regulator_set_dvs_levels);
|
||||
|
||||
/*
|
||||
* Few ROHM PMIC ICs have constrains on voltage changing:
|
||||
* BD71837 - only buck 1-4 voltages can be changed when they are enabled.
|
||||
* Other bucks and all LDOs must be disabled when voltage is changed.
|
||||
* BD96801 - LDO voltage levels can be changed when LDOs are disabled.
|
||||
*/
|
||||
int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev,
|
||||
unsigned int sel)
|
||||
{
|
||||
if (rdev->desc->ops->is_enabled(rdev))
|
||||
return -EBUSY;
|
||||
|
||||
return regulator_set_voltage_sel_regmap(rdev, sel);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
|
||||
MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");
|
||||
|
201
drivers/regulator/tps68470-regulator.c
Normal file
201
drivers/regulator/tps68470-regulator.c
Normal file
@ -0,0 +1,201 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Regulator driver for TPS68470 PMIC
|
||||
//
|
||||
// Copyright (c) 2021 Red Hat Inc.
|
||||
// Copyright (C) 2018 Intel Corporation
|
||||
//
|
||||
// Authors:
|
||||
// Hans de Goede <hdegoede@redhat.com>
|
||||
// Zaikuo Wang <zaikuo.wang@intel.com>
|
||||
// Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
// Jian Xu Zheng <jian.xu.zheng@intel.com>
|
||||
// Yuning Pu <yuning.pu@intel.com>
|
||||
// Rajmohan Mani <rajmohan.mani@intel.com>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/tps68470.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/tps68470.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
struct tps68470_regulator_data {
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
#define TPS68470_REGULATOR(_name, _id, _ops, _n, \
|
||||
_vr, _vm, _er, _em, _lr, _nlr) \
|
||||
[TPS68470_ ## _name] = { \
|
||||
.name = # _name, \
|
||||
.id = _id, \
|
||||
.ops = &_ops, \
|
||||
.n_voltages = _n, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.vsel_reg = _vr, \
|
||||
.vsel_mask = _vm, \
|
||||
.enable_reg = _er, \
|
||||
.enable_mask = _em, \
|
||||
.linear_ranges = _lr, \
|
||||
.n_linear_ranges = _nlr, \
|
||||
}
|
||||
|
||||
static const struct linear_range tps68470_ldo_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(875000, 0, 125, 17800),
|
||||
};
|
||||
|
||||
static const struct linear_range tps68470_core_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(900000, 0, 42, 25000),
|
||||
};
|
||||
|
||||
static int tps68470_regulator_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps68470_regulator_data *data = rdev->reg_data;
|
||||
int ret;
|
||||
|
||||
/* The Core buck regulator needs the PMIC's PLL to be enabled */
|
||||
if (rdev->desc->id == TPS68470_CORE) {
|
||||
ret = clk_prepare_enable(data->clk);
|
||||
if (ret) {
|
||||
dev_err(&rdev->dev, "Error enabling TPS68470 clock\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return regulator_enable_regmap(rdev);
|
||||
}
|
||||
|
||||
static int tps68470_regulator_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tps68470_regulator_data *data = rdev->reg_data;
|
||||
|
||||
if (rdev->desc->id == TPS68470_CORE)
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
return regulator_disable_regmap(rdev);
|
||||
}
|
||||
|
||||
/* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */
|
||||
static const struct regulator_ops tps68470_regulator_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = tps68470_regulator_enable,
|
||||
.disable = tps68470_regulator_disable,
|
||||
.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 regulator_ops tps68470_always_on_reg_ops = {
|
||||
.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 regulator_desc regulators[] = {
|
||||
TPS68470_REGULATOR(CORE, TPS68470_CORE, tps68470_regulator_ops, 43,
|
||||
TPS68470_REG_VDVAL, TPS68470_VDVAL_DVOLT_MASK,
|
||||
TPS68470_REG_VDCTL, TPS68470_VDCTL_EN_MASK,
|
||||
tps68470_core_ranges, ARRAY_SIZE(tps68470_core_ranges)),
|
||||
TPS68470_REGULATOR(ANA, TPS68470_ANA, tps68470_regulator_ops, 126,
|
||||
TPS68470_REG_VAVAL, TPS68470_VAVAL_AVOLT_MASK,
|
||||
TPS68470_REG_VACTL, TPS68470_VACTL_EN_MASK,
|
||||
tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)),
|
||||
TPS68470_REGULATOR(VCM, TPS68470_VCM, tps68470_regulator_ops, 126,
|
||||
TPS68470_REG_VCMVAL, TPS68470_VCMVAL_VCVOLT_MASK,
|
||||
TPS68470_REG_VCMCTL, TPS68470_VCMCTL_EN_MASK,
|
||||
tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)),
|
||||
TPS68470_REGULATOR(VIO, TPS68470_VIO, tps68470_always_on_reg_ops, 126,
|
||||
TPS68470_REG_VIOVAL, TPS68470_VIOVAL_IOVOLT_MASK,
|
||||
0, 0,
|
||||
tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)),
|
||||
/*
|
||||
* (1) This regulator must have the same voltage as VIO if S_IO LDO is used to
|
||||
* power a sensor/VCM which I2C is daisy chained behind the PMIC.
|
||||
* (2) If there is no I2C daisy chain it can be set freely.
|
||||
*/
|
||||
TPS68470_REGULATOR(VSIO, TPS68470_VSIO, tps68470_regulator_ops, 126,
|
||||
TPS68470_REG_VSIOVAL, TPS68470_VSIOVAL_IOVOLT_MASK,
|
||||
TPS68470_REG_S_I2C_CTL, TPS68470_S_I2C_CTL_EN_MASK,
|
||||
tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)),
|
||||
TPS68470_REGULATOR(AUX1, TPS68470_AUX1, tps68470_regulator_ops, 126,
|
||||
TPS68470_REG_VAUX1VAL, TPS68470_VAUX1VAL_AUX1VOLT_MASK,
|
||||
TPS68470_REG_VAUX1CTL, TPS68470_VAUX1CTL_EN_MASK,
|
||||
tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)),
|
||||
TPS68470_REGULATOR(AUX2, TPS68470_AUX2, tps68470_regulator_ops, 126,
|
||||
TPS68470_REG_VAUX2VAL, TPS68470_VAUX2VAL_AUX2VOLT_MASK,
|
||||
TPS68470_REG_VAUX2CTL, TPS68470_VAUX2CTL_EN_MASK,
|
||||
tps68470_ldo_ranges, ARRAY_SIZE(tps68470_ldo_ranges)),
|
||||
};
|
||||
|
||||
static int tps68470_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct tps68470_regulator_platform_data *pdata = dev_get_platdata(dev);
|
||||
struct tps68470_regulator_data *data;
|
||||
struct regulator_config config = { };
|
||||
struct regulator_dev *rdev;
|
||||
int i;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->clk = devm_clk_get(dev, "tps68470-clk");
|
||||
if (IS_ERR(data->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(data->clk), "getting tps68470-clk\n");
|
||||
|
||||
config.dev = dev->parent;
|
||||
config.regmap = dev_get_drvdata(dev->parent);
|
||||
config.driver_data = data;
|
||||
|
||||
for (i = 0; i < TPS68470_NUM_REGULATORS; i++) {
|
||||
if (pdata)
|
||||
config.init_data = pdata->reg_init_data[i];
|
||||
else
|
||||
config.init_data = NULL;
|
||||
|
||||
rdev = devm_regulator_register(dev, ®ulators[i], &config);
|
||||
if (IS_ERR(rdev))
|
||||
return dev_err_probe(dev, PTR_ERR(rdev),
|
||||
"registering %s regulator\n",
|
||||
regulators[i].name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tps68470_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "tps68470-regulator",
|
||||
},
|
||||
.probe = tps68470_regulator_probe,
|
||||
};
|
||||
|
||||
/*
|
||||
* The ACPI tps68470 probe-ordering depends on the clk/gpio/regulator drivers
|
||||
* registering before the drivers for the camera-sensors which use them bind.
|
||||
* subsys_initcall() ensures this when the drivers are builtin.
|
||||
*/
|
||||
static int __init tps68470_regulator_init(void)
|
||||
{
|
||||
return platform_driver_register(&tps68470_regulator_driver);
|
||||
}
|
||||
subsys_initcall(tps68470_regulator_init);
|
||||
|
||||
static void __exit tps68470_regulator_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tps68470_regulator_driver);
|
||||
}
|
||||
module_exit(tps68470_regulator_exit);
|
||||
|
||||
MODULE_ALIAS("platform:tps68470-regulator");
|
||||
MODULE_DESCRIPTION("TPS68470 voltage regulator driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -196,7 +196,6 @@ static int twl4030reg_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct twlreg_info *info = rdev_get_drvdata(rdev);
|
||||
int grp;
|
||||
int ret;
|
||||
|
||||
grp = twlreg_grp(rdev);
|
||||
if (grp < 0)
|
||||
@ -204,16 +203,13 @@ static int twl4030reg_enable(struct regulator_dev *rdev)
|
||||
|
||||
grp |= P1_GRP_4030;
|
||||
|
||||
ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
|
||||
|
||||
return ret;
|
||||
return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
|
||||
}
|
||||
|
||||
static int twl4030reg_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct twlreg_info *info = rdev_get_drvdata(rdev);
|
||||
int grp;
|
||||
int ret;
|
||||
|
||||
grp = twlreg_grp(rdev);
|
||||
if (grp < 0)
|
||||
@ -221,9 +217,7 @@ static int twl4030reg_disable(struct regulator_dev *rdev)
|
||||
|
||||
grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
|
||||
|
||||
ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
|
||||
|
||||
return ret;
|
||||
return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
|
||||
}
|
||||
|
||||
static int twl4030reg_get_status(struct regulator_dev *rdev)
|
||||
|
@ -80,14 +80,8 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
|
||||
const struct regulator_desc *desc,
|
||||
struct regmap *regmap);
|
||||
|
||||
#else
|
||||
static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
|
||||
struct device_node *np,
|
||||
const struct regulator_desc *desc,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev,
|
||||
unsigned int sel);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -90,22 +90,28 @@ enum regulator_detection_severity {
|
||||
* @set_over_current_protection: Support enabling of and setting limits for over
|
||||
* current situation detection. Detection can be configured for three
|
||||
* levels of severity.
|
||||
* REGULATOR_SEVERITY_PROT should automatically shut down the regulator(s).
|
||||
* REGULATOR_SEVERITY_ERR should indicate that over-current situation is
|
||||
* caused by an unrecoverable error but HW does not perform
|
||||
* automatic shut down.
|
||||
* REGULATOR_SEVERITY_WARN should indicate situation where hardware is
|
||||
* still believed to not be damaged but that a board sepcific
|
||||
* recovery action is needed. If lim_uA is 0 the limit should not
|
||||
* be changed but the detection should just be enabled/disabled as
|
||||
* is requested.
|
||||
*
|
||||
* - REGULATOR_SEVERITY_PROT should automatically shut down the regulator(s).
|
||||
*
|
||||
* - REGULATOR_SEVERITY_ERR should indicate that over-current situation is
|
||||
* caused by an unrecoverable error but HW does not perform
|
||||
* automatic shut down.
|
||||
*
|
||||
* - REGULATOR_SEVERITY_WARN should indicate situation where hardware is
|
||||
* still believed to not be damaged but that a board sepcific
|
||||
* recovery action is needed. If lim_uA is 0 the limit should not
|
||||
* be changed but the detection should just be enabled/disabled as
|
||||
* is requested.
|
||||
*
|
||||
* @set_over_voltage_protection: Support enabling of and setting limits for over
|
||||
* voltage situation detection. Detection can be configured for same
|
||||
* severities as over current protection.
|
||||
* severities as over current protection. Units of uV.
|
||||
* @set_under_voltage_protection: Support enabling of and setting limits for
|
||||
* under situation detection.
|
||||
* under voltage situation detection. Detection can be configured for same
|
||||
* severities as over current protection. Units of uV.
|
||||
* @set_thermal_protection: Support enabling of and setting limits for over
|
||||
* temperature situation detection.
|
||||
* temperature situation detection.Detection can be configured for same
|
||||
* severities as over current protection. Units of degree Kelvin.
|
||||
*
|
||||
* @set_active_discharge: Set active discharge enable/disable of regulators.
|
||||
*
|
||||
@ -554,7 +560,6 @@ struct regulator_irq_data {
|
||||
*/
|
||||
struct regulator_irq_desc {
|
||||
const char *name;
|
||||
int irq_flags;
|
||||
int fatal_cnt;
|
||||
int reread_ms;
|
||||
int irq_off_ms;
|
||||
@ -646,6 +651,40 @@ struct regulator_dev {
|
||||
spinlock_t err_lock;
|
||||
};
|
||||
|
||||
/*
|
||||
* Convert error flags to corresponding notifications.
|
||||
*
|
||||
* Can be used by drivers which use the notification helpers to
|
||||
* find out correct notification flags based on the error flags. Drivers
|
||||
* can avoid storing both supported notification and error flags which
|
||||
* may save few bytes.
|
||||
*/
|
||||
static inline int regulator_err2notif(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case REGULATOR_ERROR_UNDER_VOLTAGE:
|
||||
return REGULATOR_EVENT_UNDER_VOLTAGE;
|
||||
case REGULATOR_ERROR_OVER_CURRENT:
|
||||
return REGULATOR_EVENT_OVER_CURRENT;
|
||||
case REGULATOR_ERROR_REGULATION_OUT:
|
||||
return REGULATOR_EVENT_REGULATION_OUT;
|
||||
case REGULATOR_ERROR_FAIL:
|
||||
return REGULATOR_EVENT_FAIL;
|
||||
case REGULATOR_ERROR_OVER_TEMP:
|
||||
return REGULATOR_EVENT_OVER_TEMP;
|
||||
case REGULATOR_ERROR_UNDER_VOLTAGE_WARN:
|
||||
return REGULATOR_EVENT_UNDER_VOLTAGE_WARN;
|
||||
case REGULATOR_ERROR_OVER_CURRENT_WARN:
|
||||
return REGULATOR_EVENT_OVER_CURRENT_WARN;
|
||||
case REGULATOR_ERROR_OVER_VOLTAGE_WARN:
|
||||
return REGULATOR_EVENT_OVER_VOLTAGE_WARN;
|
||||
case REGULATOR_ERROR_OVER_TEMP_WARN:
|
||||
return REGULATOR_EVENT_OVER_TEMP_WARN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct regulator_dev *
|
||||
regulator_register(const struct regulator_desc *regulator_desc,
|
||||
const struct regulator_config *config);
|
||||
@ -667,6 +706,8 @@ void *regulator_irq_helper(struct device *dev,
|
||||
int irq_flags, int common_errs, int *per_rdev_errs,
|
||||
struct regulator_dev **rdev, int rdev_amount);
|
||||
void regulator_irq_helper_cancel(void **handle);
|
||||
int regulator_irq_map_event_simple(int irq, struct regulator_irq_data *rid,
|
||||
unsigned long *dev_mask);
|
||||
|
||||
void *rdev_get_drvdata(struct regulator_dev *rdev);
|
||||
struct device *rdev_get_dev(struct regulator_dev *rdev);
|
||||
|
Loading…
Reference in New Issue
Block a user