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: |
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
Current limits
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...
| 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
Dialog Semiconductor DA9141 Single-channel 40A quad-phase buck converter
Dialog Semiconductor DA9142 Single-channel 20A double-phase buck converter
Device parameter ranges
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.
|----------------------------------------------|
| | 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)
......
# 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:
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);
// 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);
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;
const struct of_device_id *match;
struct regulator_config config = { };
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)
{
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;
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);
ret = rpm_regulator_init_vreg(vreg, dev, node, rpm, vreg_data);
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");
// 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)
{
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);
......
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