Commit fef8dfae authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 2d7852c3 bfff546a
...@@ -17,27 +17,39 @@ description: | ...@@ -17,27 +17,39 @@ description: |
Dialog Semiconductor DA9130 Single-channel 10A double-phase buck converter Dialog Semiconductor DA9130 Single-channel 10A double-phase buck converter
Dialog Semiconductor DA9131 Double-channel 5A single-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 DA9132 Double-channel 3A single-phase buck converter
Dialog Semiconductor DA9141 Single-channel 40A quad-phase buck converter
Current limits Dialog Semiconductor DA9142 Single-channel 20A double-phase buck converter
This is PER PHASE, and the current limit setting in the devices reflect Device parameter ranges
that with a maximum 10A limit. Allowing for transients at/near double
the rated current, this translates across the device range to per The current limits can be set to at/near double the rated current per channel
channel figures as so... to allow for transient peaks.
Current limit changes when the output is enabled are not supported, as a
| DA9121 DA9122 DA9220 DA9217 DA9140 precaution against undefined behaviour.
| /DA9130 /DA9131 /DA9132
----------------------------------------------------------------------------- |----------------------------------------------|
Output current / channel | 10000000 5000000 3000000 6000000 40000000 | | range & reset default value |
Output current / phase | 5000000 5000000 3000000 3000000 9500000 | Device |------------------------------|
----------------------------------------------------------------------------- | | microvolt | microamp |
Min regulator-min-microvolt| 300000 300000 300000 300000 500000 |----------------------------------------------|
Max regulator-max-microvolt| 1900000 1900000 1900000 1900000 1000000 | DA9121/DA9130 | Min: 300000 | Min: 7000000 |
Device hardware default | 1000000 1000000 1000000 1000000 1000000 | | Max: 1900000 | Max: 20000000 |
----------------------------------------------------------------------------- |----------------------------------------------|
Min regulator-min-microamp | 7000000 3500000 3500000 7000000 26000000 | DA9121/DA9131 | Min: 300000 | Min: 3500000 |
Max regulator-max-microamp | 20000000 10000000 6000000 12000000 78000000 | | Max: 1900000 | Max: 10000000 |
Device hardware default | 15000000 7500000 5500000 11000000 58000000 |----------------------------------------------|
| 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: properties:
$nodename: $nodename:
...@@ -51,7 +63,8 @@ properties: ...@@ -51,7 +63,8 @@ properties:
- dlg,da9130 - dlg,da9130
- dlg,da9131 - dlg,da9131
- dlg,da9132 - dlg,da9132
- dlg,da9140 - dlg,da9141
- dlg,da9142
reg: reg:
maxItems: 1 maxItems: 1
...@@ -70,26 +83,24 @@ properties: ...@@ -70,26 +83,24 @@ properties:
regulators: regulators:
type: object type: object
$ref: regulator.yaml#
description: | description: |
This node defines the settings for the BUCK. The content of the List of regulators provided by the device
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
patternProperties: patternProperties:
"^buck([1-2])$": "^buck([1-2])$":
type: object type: object
$ref: regulator.yaml# $ref: regulator.yaml#
description: |
Properties for a single BUCK regulator
properties: properties:
regulator-mode: regulator-name:
maxItems: 1 pattern: "^BUCK([1-2])$"
description: Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h description: |
BUCK2 present in DA9122, DA9220, DA9131, DA9132 only
regulator-initial-mode: regulator-initial-mode:
maxItems: 1 enum: [ 0, 1, 2, 3 ]
description: Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h description: Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h
enable-gpios: enable-gpios:
...@@ -98,6 +109,7 @@ properties: ...@@ -98,6 +109,7 @@ properties:
dlg,ripple-cancel: dlg,ripple-cancel:
$ref: "/schemas/types.yaml#/definitions/uint32" $ref: "/schemas/types.yaml#/definitions/uint32"
enum: [ 0, 1, 2, 3 ]
description: | description: |
Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h Defined in include/dt-bindings/regulator/dlg,da9121-regulator.h
Only present on multi-channel devices (DA9122, DA9220, DA9131, DA9132) Only present on multi-channel devices (DA9122, DA9220, DA9131, DA9132)
......
# 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 = <&reg_12v0>;
vdd-supply = <&reg_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: ...@@ -86,6 +86,9 @@ properties:
reg: reg:
maxItems: 1 maxItems: 1
interrupts:
maxItems: 1
required: required:
- compatible - compatible
- reg - reg
......
...@@ -43,6 +43,7 @@ description: | ...@@ -43,6 +43,7 @@ description: |
For PM8150L, smps1 - smps8, ldo1 - ldo11, bob, flash, rgb For PM8150L, smps1 - smps8, ldo1 - ldo11, bob, flash, rgb
For PM8350, smps1 - smps12, ldo1 - ldo10 For PM8350, smps1 - smps12, ldo1 - ldo10
For PM8350C, smps1 - smps10, ldo1 - ldo13, bob For PM8350C, smps1 - smps10, ldo1 - ldo13, bob
For PM8450, smps1 - smps6, ldo1 - ldo4
For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 For PM8998, smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2
For PMI8998, bob For PMI8998, bob
For PMR735A, smps1 - smps3, ldo1 - ldo7 For PMR735A, smps1 - smps3, ldo1 - ldo7
...@@ -62,7 +63,9 @@ properties: ...@@ -62,7 +63,9 @@ properties:
- qcom,pm8150l-rpmh-regulators - qcom,pm8150l-rpmh-regulators
- qcom,pm8350-rpmh-regulators - qcom,pm8350-rpmh-regulators
- qcom,pm8350c-rpmh-regulators - qcom,pm8350c-rpmh-regulators
- qcom,pm8450-rpmh-regulators
- qcom,pm8998-rpmh-regulators - qcom,pm8998-rpmh-regulators
- qcom,pmg1110-rpmh-regulators
- qcom,pmi8998-rpmh-regulators - qcom,pmi8998-rpmh-regulators
- qcom,pmm8155au-rpmh-regulators - qcom,pmm8155au-rpmh-regulators
- qcom,pmr735a-rpmh-regulators - qcom,pmr735a-rpmh-regulators
......
...@@ -6,6 +6,7 @@ Qualcomm SPMI Regulators ...@@ -6,6 +6,7 @@ Qualcomm SPMI Regulators
Definition: must be one of: Definition: must be one of:
"qcom,pm8004-regulators" "qcom,pm8004-regulators"
"qcom,pm8005-regulators" "qcom,pm8005-regulators"
"qcom,pm8226-regulators"
"qcom,pm8841-regulators" "qcom,pm8841-regulators"
"qcom,pm8916-regulators" "qcom,pm8916-regulators"
"qcom,pm8941-regulators" "qcom,pm8941-regulators"
......
...@@ -218,7 +218,7 @@ properties: ...@@ -218,7 +218,7 @@ properties:
description: Array of maximum spread between voltages of coupled regulators description: Array of maximum spread between voltages of coupled regulators
in microvolts, each value in the array relates to the corresponding in microvolts, each value in the array relates to the corresponding
couple specified by the regulator-coupled-with property. 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: regulator-max-step-microvolt:
description: Maximum difference between current and target voltages description: Maximum difference between current and target voltages
......
...@@ -67,8 +67,9 @@ patternProperties: ...@@ -67,8 +67,9 @@ patternProperties:
required: required:
- regulator-name - regulator-name
properties:
# 9 buck # 9 buck
"^BUCK9$": BUCK9:
type: object type: object
$ref: regulator.yaml# $ref: regulator.yaml#
unevaluatedProperties: false unevaluatedProperties: false
......
...@@ -11653,6 +11653,13 @@ S: Maintained ...@@ -11653,6 +11653,13 @@ S: Maintained
F: Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml F: Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml
F: drivers/power/supply/max17042_battery.c 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 MAXIM MAX77650 PMIC MFD DRIVER
M: Bartosz Golaszewski <brgl@bgdev.pl> M: Bartosz Golaszewski <brgl@bgdev.pl>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
......
...@@ -636,6 +636,15 @@ config REGULATOR_MAX8998 ...@@ -636,6 +636,15 @@ config REGULATOR_MAX8998
via I2C bus. The provided regulator is suitable for S3C6410 via I2C bus. The provided regulator is suitable for S3C6410
and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. 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 config REGULATOR_MAX77686
tristate "Maxim 77686 regulator" tristate "Maxim 77686 regulator"
depends on MFD_MAX77686 || COMPILE_TEST depends on MFD_MAX77686 || COMPILE_TEST
...@@ -1339,6 +1348,15 @@ config REGULATOR_TPS65912 ...@@ -1339,6 +1348,15 @@ config REGULATOR_TPS65912
help help
This driver supports TPS65912 voltage regulator chip. 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 config REGULATOR_TWL4030
tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
depends on TWL4030_CORE depends on TWL4030_CORE
...@@ -1415,4 +1433,3 @@ config REGULATOR_QCOM_LABIBB ...@@ -1415,4 +1433,3 @@ config REGULATOR_QCOM_LABIBB
for LCD display panel. for LCD display panel.
endif endif
...@@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o ...@@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
obj-$(CONFIG_REGULATOR_MAX8997) += max8997-regulator.o obj-$(CONFIG_REGULATOR_MAX8997) += max8997-regulator.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MAX20086) += max20086-regulator.o
obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o obj-$(CONFIG_REGULATOR_MAX77686) += max77686-regulator.o
obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o
obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o
...@@ -159,6 +160,7 @@ obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o ...@@ -159,6 +160,7 @@ obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-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_TWL4030) += twl-regulator.o twl6030-regulator.o
obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o
obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o
......
...@@ -125,27 +125,6 @@ static int bd71837_get_buck34_enable_hwctrl(struct regulator_dev *rdev) ...@@ -125,27 +125,6 @@ static int bd71837_get_buck34_enable_hwctrl(struct regulator_dev *rdev)
return !!(BD718XX_BUCK_RUN_ON & val); 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, static void voltage_change_done(struct regulator_dev *rdev, unsigned int sel,
unsigned int *mask) unsigned int *mask)
...@@ -642,22 +621,22 @@ BD718XX_OPS(bd71837_pickable_range_buck_ops, ...@@ -642,22 +621,22 @@ BD718XX_OPS(bd71837_pickable_range_buck_ops,
bd718x7_set_buck_ovp); bd718x7_set_buck_ovp);
BD718XX_OPS(bd71837_ldo_regulator_ops, regulator_list_voltage_linear_range, 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, regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp,
NULL); NULL);
BD718XX_OPS(bd71837_ldo_regulator_nolinear_ops, regulator_list_voltage_table, 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, regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp,
NULL); NULL);
BD718XX_OPS(bd71837_buck_regulator_ops, regulator_list_voltage_linear_range, 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, regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp);
BD718XX_OPS(bd71837_buck_regulator_nolinear_ops, regulator_list_voltage_table, 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, regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp);
/* /*
......
...@@ -86,6 +86,22 @@ static struct da9121_range da9121_3A_1phase_current = { ...@@ -86,6 +86,22 @@ static struct da9121_range da9121_3A_1phase_current = {
.reg_max = 6, .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 { struct da9121_variant_info {
int num_bucks; int num_bucks;
int num_phases; int num_phases;
...@@ -97,6 +113,8 @@ static const struct da9121_variant_info variant_parameters[] = { ...@@ -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_3A_1phase_current }, //DA9121_TYPE_DA9220_DA9132
{ 2, 1, &da9121_5A_1phase_current }, //DA9121_TYPE_DA9122_DA9131 { 2, 1, &da9121_5A_1phase_current }, //DA9121_TYPE_DA9122_DA9131
{ 1, 2, &da9121_6A_2phase_current }, //DA9121_TYPE_DA9217 { 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 { struct da9121_field {
...@@ -253,6 +271,11 @@ static int da9121_set_current_limit(struct regulator_dev *rdev, ...@@ -253,6 +271,11 @@ static int da9121_set_current_limit(struct regulator_dev *rdev,
goto error; goto error;
} }
if (rdev->desc->ops->is_enabled(rdev)) {
ret = -EBUSY;
goto error;
}
ret = da9121_ceiling_selector(rdev, min_ua, max_ua, &sel); ret = da9121_ceiling_selector(rdev, min_ua, max_ua, &sel);
if (ret < 0) if (ret < 0)
goto error; goto error;
...@@ -537,11 +560,65 @@ static const struct regulator_desc da9217_reg = { ...@@ -537,11 +560,65 @@ static const struct regulator_desc da9217_reg = {
.vsel_mask = DA9121_MASK_BUCK_BUCKx_5_CHx_A_VOUT, .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] = { static const struct regulator_desc *local_da9121_regulators[][DA9121_IDX_MAX] = {
[DA9121_TYPE_DA9121_DA9130] = { &da9121_reg, NULL }, [DA9121_TYPE_DA9121_DA9130] = { &da9121_reg, NULL },
[DA9121_TYPE_DA9220_DA9132] = { &da9220_reg[0], &da9220_reg[1] }, [DA9121_TYPE_DA9220_DA9132] = { &da9220_reg[0], &da9220_reg[1] },
[DA9121_TYPE_DA9122_DA9131] = { &da9122_reg[0], &da9122_reg[1] }, [DA9121_TYPE_DA9122_DA9131] = { &da9122_reg[0], &da9122_reg[1] },
[DA9121_TYPE_DA9217] = { &da9217_reg, NULL }, [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) 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) ...@@ -835,7 +912,7 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip)
goto error; 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); dev_err(chip->dev, "Invalid device ID: 0x%02x\n", device_id);
ret = -ENODEV; ret = -ENODEV;
goto error; goto error;
...@@ -877,6 +954,22 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) ...@@ -877,6 +954,22 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip)
break; 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, dev_info(chip->dev,
"Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n", "Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n",
device_id, variant_id, type); device_id, variant_id, type);
...@@ -890,8 +983,10 @@ static int da9121_check_device_type(struct i2c_client *i2c, struct da9121 *chip) ...@@ -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) variant_mrc = (variant_id & DA9121_MASK_OTP_VARIANT_ID_MRC)
>> DA9121_SHIFT_OTP_VARIANT_ID_MRC; >> DA9121_SHIFT_OTP_VARIANT_ID_MRC;
if ((device_id == DA9121_DEVICE_ID) && if (((device_id == DA9121_DEVICE_ID) &&
(variant_mrc < DA9121_VARIANT_MRC_BASE)) { (variant_mrc < DA9121_VARIANT_MRC_BASE)) ||
((device_id == DA914x_DEVICE_ID) &&
(variant_mrc != DA914x_VARIANT_MRC_BASE))) {
dev_err(chip->dev, dev_err(chip->dev,
"Cannot support variant MRC: 0x%02X\n", variant_mrc); "Cannot support variant MRC: 0x%02X\n", variant_mrc);
ret = -EINVAL; ret = -EINVAL;
...@@ -931,6 +1026,14 @@ static int da9121_assign_chip_model(struct i2c_client *i2c, ...@@ -931,6 +1026,14 @@ static int da9121_assign_chip_model(struct i2c_client *i2c,
chip->variant_id = DA9121_TYPE_DA9220_DA9132; chip->variant_id = DA9121_TYPE_DA9220_DA9132;
regmap = &da9121_2ch_regmap_config; regmap = &da9121_2ch_regmap_config;
break; 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 */ /* 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[] = { ...@@ -1010,6 +1113,8 @@ static const struct of_device_id da9121_dt_ids[] = {
{ .compatible = "dlg,da9131", .data = (void *) DA9121_SUBTYPE_DA9131 }, { .compatible = "dlg,da9131", .data = (void *) DA9121_SUBTYPE_DA9131 },
{ .compatible = "dlg,da9220", .data = (void *) DA9121_SUBTYPE_DA9220 }, { .compatible = "dlg,da9220", .data = (void *) DA9121_SUBTYPE_DA9220 },
{ .compatible = "dlg,da9132", .data = (void *) DA9121_SUBTYPE_DA9132 }, { .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); MODULE_DEVICE_TABLE(of, da9121_dt_ids);
...@@ -1065,7 +1170,7 @@ static int da9121_i2c_remove(struct i2c_client *i2c) ...@@ -1065,7 +1170,7 @@ static int da9121_i2c_remove(struct i2c_client *i2c)
{ {
struct da9121 *chip = i2c_get_clientdata(i2c); struct da9121 *chip = i2c_get_clientdata(i2c);
const int mask_all[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; const int mask_all[4] = { 0xFF, 0xFF, 0xFF, 0xFF };
int ret = 0; int ret;
free_irq(chip->chip_irq, chip); free_irq(chip->chip_irq, chip);
cancel_delayed_work_sync(&chip->work); cancel_delayed_work_sync(&chip->work);
...@@ -1073,7 +1178,7 @@ static int da9121_i2c_remove(struct i2c_client *i2c) ...@@ -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); ret = regmap_bulk_write(chip->regmap, DA9121_REG_SYS_MASK_0, mask_all, 4);
if (ret != 0) if (ret != 0)
dev_err(chip->dev, "Failed to set IRQ masks: %d\n", ret); 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[] = { static const struct i2c_device_id da9121_i2c_id[] = {
...@@ -1084,6 +1189,8 @@ 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}, {"da9131", DA9121_TYPE_DA9122_DA9131},
{"da9220", DA9121_TYPE_DA9220_DA9132}, {"da9220", DA9121_TYPE_DA9220_DA9132},
{"da9132", DA9121_TYPE_DA9220_DA9132}, {"da9132", DA9121_TYPE_DA9220_DA9132},
{"da9141", DA9121_TYPE_DA9141},
{"da9142", DA9121_TYPE_DA9142},
{}, {},
}; };
MODULE_DEVICE_TABLE(i2c, da9121_i2c_id); MODULE_DEVICE_TABLE(i2c, da9121_i2c_id);
......
...@@ -26,7 +26,9 @@ enum da9121_variant { ...@@ -26,7 +26,9 @@ enum da9121_variant {
DA9121_TYPE_DA9121_DA9130, DA9121_TYPE_DA9121_DA9130,
DA9121_TYPE_DA9220_DA9132, DA9121_TYPE_DA9220_DA9132,
DA9121_TYPE_DA9122_DA9131, DA9121_TYPE_DA9122_DA9131,
DA9121_TYPE_DA9217 DA9121_TYPE_DA9217,
DA9121_TYPE_DA9141,
DA9121_TYPE_DA9142
}; };
enum da9121_subvariant { enum da9121_subvariant {
...@@ -36,7 +38,9 @@ enum da9121_subvariant { ...@@ -36,7 +38,9 @@ enum da9121_subvariant {
DA9121_SUBTYPE_DA9132, DA9121_SUBTYPE_DA9132,
DA9121_SUBTYPE_DA9122, DA9121_SUBTYPE_DA9122,
DA9121_SUBTYPE_DA9131, DA9121_SUBTYPE_DA9131,
DA9121_SUBTYPE_DA9217 DA9121_SUBTYPE_DA9217,
DA9121_SUBTYPE_DA9141,
DA9121_SUBTYPE_DA9142
}; };
/* Minimum, maximum and default polling millisecond periods are provided /* Minimum, maximum and default polling millisecond periods are provided
...@@ -70,6 +74,14 @@ enum da9121_subvariant { ...@@ -70,6 +74,14 @@ enum da9121_subvariant {
#define DA9121_REG_SYS_GPIO1_1 0x13 #define DA9121_REG_SYS_GPIO1_1 0x13
#define DA9121_REG_SYS_GPIO2_0 0x14 #define DA9121_REG_SYS_GPIO2_0 0x14
#define DA9121_REG_SYS_GPIO2_1 0x15 #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_0 0x20
#define DA9121_REG_BUCK_BUCK1_1 0x21 #define DA9121_REG_BUCK_BUCK1_1 0x21
#define DA9121_REG_BUCK_BUCK1_2 0x22 #define DA9121_REG_BUCK_BUCK1_2 0x22
...@@ -276,6 +288,7 @@ enum da9121_subvariant { ...@@ -276,6 +288,7 @@ enum da9121_subvariant {
#define DA9121_MASK_OTP_DEVICE_ID_DEV_ID 0xFF #define DA9121_MASK_OTP_DEVICE_ID_DEV_ID 0xFF
#define DA9121_DEVICE_ID 0x05 #define DA9121_DEVICE_ID 0x05
#define DA914x_DEVICE_ID 0x26
/* DA9121_REG_OTP_VARIANT_ID */ /* DA9121_REG_OTP_VARIANT_ID */
...@@ -293,6 +306,10 @@ enum da9121_subvariant { ...@@ -293,6 +306,10 @@ enum da9121_subvariant {
#define DA9131_VARIANT_VRC 0x1 #define DA9131_VARIANT_VRC 0x1
#define DA9132_VARIANT_VRC 0x2 #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 */ /* DA9121_REG_OTP_CUSTOMER_ID */
#define DA9121_MASK_OTP_CUSTOMER_ID_CUST_ID 0xFF #define DA9121_MASK_OTP_CUSTOMER_ID_CUST_ID 0xFF
......
...@@ -320,7 +320,9 @@ static void init_rdev_errors(struct regulator_irq *h) ...@@ -320,7 +320,9 @@ static void init_rdev_errors(struct regulator_irq *h)
* IRQF_ONESHOT when requesting the (threaded) irq. * IRQF_ONESHOT when requesting the (threaded) irq.
* @common_errs: Errors which can be flagged by this IRQ for all rdevs. * @common_errs: Errors which can be flagged by this IRQ for all rdevs.
* When IRQ is re-enabled these errors will be cleared * 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 * @per_rdev_errs: Optional error flag array describing errors specific
* for only some of the regulators. These errors will be * for only some of the regulators. These errors will be
* or'ed with common errors. If this is given the array * or'ed with common errors. If this is given the array
...@@ -395,3 +397,40 @@ void regulator_irq_helper_cancel(void **handle) ...@@ -395,3 +397,40 @@ void regulator_irq_helper_cancel(void **handle)
} }
} }
EXPORT_SYMBOL_GPL(regulator_irq_helper_cancel); 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);
// 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[] = { ...@@ -183,7 +183,7 @@ static const unsigned int ldo_volt_table4[] = {
static int mt6380_regulator_set_mode(struct regulator_dev *rdev, static int mt6380_regulator_set_mode(struct regulator_dev *rdev,
unsigned int mode) unsigned int mode)
{ {
int ret, val = 0; int val = 0;
struct mt6380_regulator_info *info = rdev_get_drvdata(rdev); struct mt6380_regulator_info *info = rdev_get_drvdata(rdev);
switch (mode) { switch (mode) {
...@@ -199,10 +199,8 @@ static int mt6380_regulator_set_mode(struct regulator_dev *rdev, ...@@ -199,10 +199,8 @@ static int mt6380_regulator_set_mode(struct regulator_dev *rdev,
val <<= ffs(info->modeset_mask) - 1; 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); info->modeset_mask, val);
return ret;
} }
static unsigned int mt6380_regulator_get_mode(struct regulator_dev *rdev) 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) ...@@ -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 the regulator is not enabled, this is a fake event */
if (!ops->is_enabled(vreg->rdev)) 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 we tried to recover for too many times it's not getting better */
if (vreg->ocp_irq_count > LABIBB_MAX_OCP_COUNT) if (vreg->ocp_irq_count > LABIBB_MAX_OCP_COUNT)
......
...@@ -814,6 +814,11 @@ static const struct rpmh_vreg_init_data pm8998_vreg_data[] = { ...@@ -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[] = { static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = {
RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"), RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
{} {}
...@@ -969,6 +974,20 @@ static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = { ...@@ -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[] = { static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515, "vdd-s2"), 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[] = { ...@@ -1213,10 +1232,18 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
.compatible = "qcom,pm8350c-rpmh-regulators", .compatible = "qcom,pm8350c-rpmh-regulators",
.data = pm8350c_vreg_data, .data = pm8350c_vreg_data,
}, },
{
.compatible = "qcom,pm8450-rpmh-regulators",
.data = pm8450_vreg_data,
},
{ {
.compatible = "qcom,pm8998-rpmh-regulators", .compatible = "qcom,pm8998-rpmh-regulators",
.data = pm8998_vreg_data, .data = pm8998_vreg_data,
}, },
{
.compatible = "qcom,pmg1110-rpmh-regulators",
.data = pmg1110_vreg_data,
},
{ {
.compatible = "qcom,pmi8998-rpmh-regulators", .compatible = "qcom,pmi8998-rpmh-regulators",
.data = pmi8998_vreg_data, .data = pmi8998_vreg_data,
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/soc/qcom/smd-rpm.h> #include <linux/soc/qcom/smd-rpm.h>
struct qcom_rpm_reg { struct qcom_rpm_reg {
...@@ -1239,52 +1240,91 @@ static const struct of_device_id rpm_of_match[] = { ...@@ -1239,52 +1240,91 @@ static const struct of_device_id rpm_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, rpm_of_match); MODULE_DEVICE_TABLE(of, rpm_of_match);
static int rpm_reg_probe(struct platform_device *pdev) /**
* 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)
{ {
const struct rpm_regulator_data *reg; struct regulator_config config = {};
const struct of_device_id *match; const struct rpm_regulator_data *rpm_data;
struct regulator_config config = { };
struct regulator_dev *rdev; 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)
{
struct device *dev = &pdev->dev;
const struct rpm_regulator_data *vreg_data;
struct device_node *node;
struct qcom_rpm_reg *vreg; struct qcom_rpm_reg *vreg;
struct qcom_smd_rpm *rpm; struct qcom_smd_rpm *rpm;
int ret;
rpm = dev_get_drvdata(pdev->dev.parent); rpm = dev_get_drvdata(pdev->dev.parent);
if (!rpm) { 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; return -ENODEV;
} }
match = of_match_device(rpm_of_match, &pdev->dev); vreg_data = of_device_get_match_data(dev);
if (!match) { if (!vreg_data)
dev_err(&pdev->dev, "failed to match device\n");
return -ENODEV; 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); vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
if (!vreg) if (!vreg)
return -ENOMEM; return -ENOMEM;
vreg->dev = &pdev->dev; ret = rpm_regulator_init_vreg(vreg, dev, node, rpm, vreg_data);
vreg->type = reg->type;
vreg->id = reg->id;
vreg->rpm = rpm;
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; if (ret < 0) {
config.driver_data = vreg; of_node_put(node);
rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config); return ret;
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s\n", reg->name);
return PTR_ERR(rdev);
} }
} }
......
...@@ -1895,6 +1895,44 @@ static const struct spmi_regulator_data pm8941_regulators[] = { ...@@ -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[] = { static const struct spmi_regulator_data pm8841_regulators[] = {
{ "s1", 0x1400, "vdd_s1", }, { "s1", 0x1400, "vdd_s1", },
{ "s2", 0x1700, "vdd_s2", NULL, 0x1c08 }, { "s2", 0x1700, "vdd_s2", NULL, 0x1c08 },
...@@ -2095,6 +2133,7 @@ static const struct spmi_regulator_data pms405_regulators[] = { ...@@ -2095,6 +2133,7 @@ static const struct spmi_regulator_data pms405_regulators[] = {
static const struct of_device_id qcom_spmi_regulator_match[] = { static const struct of_device_id qcom_spmi_regulator_match[] = {
{ .compatible = "qcom,pm8004-regulators", .data = &pm8004_regulators }, { .compatible = "qcom,pm8004-regulators", .data = &pm8004_regulators },
{ .compatible = "qcom,pm8005-regulators", .data = &pm8005_regulators }, { .compatible = "qcom,pm8005-regulators", .data = &pm8005_regulators },
{ .compatible = "qcom,pm8226-regulators", .data = &pm8226_regulators },
{ .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators }, { .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators },
{ .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators }, { .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators },
{ .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators }, { .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators },
......
...@@ -112,6 +112,22 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, ...@@ -112,6 +112,22 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
} }
EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); 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_LICENSE("GPL v2");
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");
// 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, &regulators[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) ...@@ -196,7 +196,6 @@ static int twl4030reg_enable(struct regulator_dev *rdev)
{ {
struct twlreg_info *info = rdev_get_drvdata(rdev); struct twlreg_info *info = rdev_get_drvdata(rdev);
int grp; int grp;
int ret;
grp = twlreg_grp(rdev); grp = twlreg_grp(rdev);
if (grp < 0) if (grp < 0)
...@@ -204,16 +203,13 @@ static int twl4030reg_enable(struct regulator_dev *rdev) ...@@ -204,16 +203,13 @@ static int twl4030reg_enable(struct regulator_dev *rdev)
grp |= P1_GRP_4030; grp |= P1_GRP_4030;
ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
return ret;
} }
static int twl4030reg_disable(struct regulator_dev *rdev) static int twl4030reg_disable(struct regulator_dev *rdev)
{ {
struct twlreg_info *info = rdev_get_drvdata(rdev); struct twlreg_info *info = rdev_get_drvdata(rdev);
int grp; int grp;
int ret;
grp = twlreg_grp(rdev); grp = twlreg_grp(rdev);
if (grp < 0) if (grp < 0)
...@@ -221,9 +217,7 @@ static int twl4030reg_disable(struct regulator_dev *rdev) ...@@ -221,9 +217,7 @@ static int twl4030reg_disable(struct regulator_dev *rdev)
grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030); grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
return ret;
} }
static int twl4030reg_get_status(struct regulator_dev *rdev) 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, ...@@ -80,14 +80,8 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
const struct regulator_desc *desc, const struct regulator_desc *desc,
struct regmap *regmap); struct regmap *regmap);
#else int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev,
static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, unsigned int sel);
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap)
{
return 0;
}
#endif #endif
#endif #endif
...@@ -90,22 +90,28 @@ enum regulator_detection_severity { ...@@ -90,22 +90,28 @@ enum regulator_detection_severity {
* @set_over_current_protection: Support enabling of and setting limits for over * @set_over_current_protection: Support enabling of and setting limits for over
* current situation detection. Detection can be configured for three * current situation detection. Detection can be configured for three
* levels of severity. * levels of severity.
* REGULATOR_SEVERITY_PROT should automatically shut down the regulator(s). *
* REGULATOR_SEVERITY_ERR should indicate that over-current situation is * - 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 * caused by an unrecoverable error but HW does not perform
* automatic shut down. * automatic shut down.
* REGULATOR_SEVERITY_WARN should indicate situation where hardware is *
* - REGULATOR_SEVERITY_WARN should indicate situation where hardware is
* still believed to not be damaged but that a board sepcific * still believed to not be damaged but that a board sepcific
* recovery action is needed. If lim_uA is 0 the limit should not * recovery action is needed. If lim_uA is 0 the limit should not
* be changed but the detection should just be enabled/disabled as * be changed but the detection should just be enabled/disabled as
* is requested. * is requested.
*
* @set_over_voltage_protection: Support enabling of and setting limits for over * @set_over_voltage_protection: Support enabling of and setting limits for over
* voltage situation detection. Detection can be configured for same * 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 * @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 * @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. * @set_active_discharge: Set active discharge enable/disable of regulators.
* *
...@@ -554,7 +560,6 @@ struct regulator_irq_data { ...@@ -554,7 +560,6 @@ struct regulator_irq_data {
*/ */
struct regulator_irq_desc { struct regulator_irq_desc {
const char *name; const char *name;
int irq_flags;
int fatal_cnt; int fatal_cnt;
int reread_ms; int reread_ms;
int irq_off_ms; int irq_off_ms;
...@@ -646,6 +651,40 @@ struct regulator_dev { ...@@ -646,6 +651,40 @@ struct regulator_dev {
spinlock_t err_lock; 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 * struct regulator_dev *
regulator_register(const struct regulator_desc *regulator_desc, regulator_register(const struct regulator_desc *regulator_desc,
const struct regulator_config *config); const struct regulator_config *config);
...@@ -667,6 +706,8 @@ void *regulator_irq_helper(struct device *dev, ...@@ -667,6 +706,8 @@ void *regulator_irq_helper(struct device *dev,
int irq_flags, int common_errs, int *per_rdev_errs, int irq_flags, int common_errs, int *per_rdev_errs,
struct regulator_dev **rdev, int rdev_amount); struct regulator_dev **rdev, int rdev_amount);
void regulator_irq_helper_cancel(void **handle); 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); void *rdev_get_drvdata(struct regulator_dev *rdev);
struct device *rdev_get_dev(struct regulator_dev *rdev); struct device *rdev_get_dev(struct regulator_dev *rdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment