summaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-10-23 01:54:44 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-23 01:54:44 +0100
commitca9eb48fe01fa7fa60ff9f2196b1bd0d84dc81af (patch)
tree587767dc1d9a4211a54430f0b9058397cd749617 /drivers/regulator
parentb537149a2fb45ef9936b7a55aa801fbab8ea2a8a (diff)
parentf35b1e53a66ab06e6d04cdff96f686e8b88959ef (diff)
Merge tag 'regulator-v5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown: "The biggest chunk of the regulator changes for this release outside of the new drivers is the conversion of the fixed regulator to use the GPIO descriptor API, there's a small addition to the GPIO API plus a bunch of updates to board files to implement it. This is some really welcome work from Linus Walleij that's had a bunch of review and has been sitting in -next for a while so I'm fairly happy there's no major issues. - Helpers for overlapping linear ranges. - Display opmode and consumer requested load in the regualtor_summary file in debugfs, plus a fix there. - Support for the fun and entertaining power off mechanism that the pfuze100 hardware implements. - Conversion of the fixed regulator API to use GPIO descriptors, including pulling in a bunch of patches to a bunch of board files. - New drivers for Cirrus Logic Lochnagar, Qualcomm PMS405, Rohm BD71847, ST PMIC1, and TI LM363x devices" * tag 'regulator-v5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (36 commits) regulator: lochnagar: Use a consisent comment style for SPDX header regulator: bd718x7: Remove struct bd718xx_pmic regulator: Fetch enable gpiods nonexclusive regulator/gpio: Allow nonexclusive GPIO access regulator: lochnagar: Add support for the Cirrus Logic Lochnagar regulator: stpmic1: Return REGULATOR_MODE_INVALID for invalid mode regulator: stpmic1: add stpmic1 regulator driver dt-bindings: regulator: document stpmic1 pmic regulators regulator: axp20x: Mark expected switch fall-throughs regulator: bd718xx: fix build warning on x86_64 regulator: fixed: Default enable high on DT regulators regulator: bd718xx: rename bd71837 to 718xx regulator: bd718XX use pickable ranges regulator/mfd: bd718xx: rename bd71837/bd71847 common instances regulator: Support regulators where voltage ranges are selectable mfd: dt bindings: add BD71847 device-tree binding documentation regulator: dt bindings: add BD71847 device-tree binding documentation regulator/mfd: Support ROHM BD71847 power management IC regulator: da905{2,5}: Remove unnecessary array check regulator: qcom: Add PMS405 regulators ...
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig21
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/arizona-ldo1.c2
-rw-r--r--drivers/regulator/axp20x-regulator.c3
-rw-r--r--drivers/regulator/bd71837-regulator.c645
-rw-r--r--drivers/regulator/bd718x7-regulator.c1119
-rw-r--r--drivers/regulator/core.c124
-rw-r--r--drivers/regulator/da9052-regulator.c2
-rw-r--r--drivers/regulator/da9055-regulator.c2
-rw-r--r--drivers/regulator/da9211-regulator.c10
-rw-r--r--drivers/regulator/fixed-helper.c1
-rw-r--r--drivers/regulator/fixed.c57
-rw-r--r--drivers/regulator/helpers.c243
-rw-r--r--drivers/regulator/isl9305.c4
-rw-r--r--drivers/regulator/lm363x-regulator.c6
-rw-r--r--drivers/regulator/lochnagar-regulator.c254
-rw-r--r--drivers/regulator/lp8788-ldo.c7
-rw-r--r--drivers/regulator/max8952.c1
-rw-r--r--drivers/regulator/max8973-regulator.c1
-rw-r--r--drivers/regulator/max8997-regulator.c4
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c2
-rw-r--r--drivers/regulator/of_regulator.c44
-rw-r--r--drivers/regulator/pfuze100-regulator.c91
-rw-r--r--drivers/regulator/qcom-rpmh-regulator.c17
-rw-r--r--drivers/regulator/qcom_smd-regulator.c77
-rw-r--r--drivers/regulator/s5m8767.c25
-rw-r--r--drivers/regulator/stpmic1_regulator.c674
-rw-r--r--drivers/regulator/tps65090-regulator.c1
28 files changed, 2651 insertions, 790 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 329cdd33ed62..926cee0d0b5f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -189,7 +189,7 @@ config REGULATOR_BD718XX
and LDO regulators.
This driver can also be built as a module. If so, the module
- will be called bd71837-regulator.
+ will be called bd718x7-regulator.
config REGULATOR_BD9571MWV
tristate "ROHM BD9571MWV Regulators"
@@ -356,6 +356,13 @@ config REGULATOR_LM363X
One boost output voltage is configurable and always on.
Other LDOs are used for the display module.
+config REGULATOR_LOCHNAGAR
+ tristate "Cirrus Logic Lochnagar regulator driver"
+ depends on MFD_LOCHNAGAR
+ help
+ This enables regulator support on the Cirrus Logic Lochnagar audio
+ development board.
+
config REGULATOR_LP3971
tristate "National Semiconductors LP3971 PMIC regulator driver"
depends on I2C
@@ -803,6 +810,18 @@ config REGULATOR_STM32_VREFBUF
This driver can also be built as a module. If so, the module
will be called stm32-vrefbuf.
+config REGULATOR_STPMIC1
+ tristate "STMicroelectronics STPMIC1 PMIC Regulators"
+ depends on MFD_STPMIC1
+ help
+ This driver supports STMicroelectronics STPMIC1 PMIC voltage
+ regulators and switches. The STPMIC1 regulators supply power to
+ an application processor as well as to external system
+ peripherals such as DDR, Flash memories and system devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called stpmic1_regulator.
+
config REGULATOR_TI_ABB
tristate "TI Adaptive Body Bias on-chip LDO"
depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 801d9a34a203..72488ef11b8a 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -27,7 +27,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
-obj-$(CONFIG_REGULATOR_BD718XX) += bd71837-regulator.o
+obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
@@ -46,6 +46,7 @@ obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
+obj-$(CONFIG_REGULATOR_LOCHNAGAR) += lochnagar-regulator.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
@@ -101,6 +102,7 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
+obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index e976d073f28d..9a72eae4926d 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -260,7 +260,7 @@ static int arizona_ldo1_common_init(struct platform_device *pdev,
* so clean up would happen at the wrong time
*/
config.ena_gpiod = gpiod_get_optional(parent_dev, "wlf,ldoena",
- GPIOD_OUT_LOW);
+ GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
if (IS_ERR(config.ena_gpiod))
return PTR_ERR(config.ena_gpiod);
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 91b8ff8bac15..a3734039a86a 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -509,10 +509,10 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
/*
* AXP803/AXP813 DCDC work frequency setting has the same
* range and step as AXP22X, but at a different register.
- * Fall through to the check below.
* (See include/linux/mfd/axp20x.h)
*/
reg = AXP803_DCDC_FREQ_CTRL;
+ /* Fall through to the check below.*/
case AXP806_ID:
/*
* AXP806 also have DCDC work frequency setting register at a
@@ -520,6 +520,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
*/
if (axp20x->variant == AXP806_ID)
reg = AXP806_DCDC_FREQ_CTRL;
+ /* Fall through */
case AXP221_ID:
case AXP223_ID:
case AXP809_ID:
diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c
deleted file mode 100644
index a1bd8aaf4d98..000000000000
--- a/drivers/regulator/bd71837-regulator.c
+++ /dev/null
@@ -1,645 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2018 ROHM Semiconductors
-// bd71837-regulator.c ROHM BD71837MWV regulator driver
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/mfd/rohm-bd718x7.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/of_regulator.h>
-#include <linux/slab.h>
-
-struct bd71837_pmic {
- struct regulator_desc descs[BD71837_REGULATOR_CNT];
- struct bd71837 *mfd;
- struct platform_device *pdev;
- struct regulator_dev *rdev[BD71837_REGULATOR_CNT];
-};
-
-/*
- * BUCK1/2/3/4
- * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
- * 00: 10.00mV/usec 10mV 1uS
- * 01: 5.00mV/usec 10mV 2uS
- * 10: 2.50mV/usec 10mV 4uS
- * 11: 1.25mV/usec 10mV 8uS
- */
-static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev,
- int ramp_delay)
-{
- struct bd71837_pmic *pmic = rdev_get_drvdata(rdev);
- struct bd71837 *mfd = pmic->mfd;
- int id = rdev->desc->id;
- unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
-
- dev_dbg(&pmic->pdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
- ramp_delay);
- switch (ramp_delay) {
- case 1 ... 1250:
- ramp_value = BUCK_RAMPRATE_1P25MV;
- break;
- case 1251 ... 2500:
- ramp_value = BUCK_RAMPRATE_2P50MV;
- break;
- case 2501 ... 5000:
- ramp_value = BUCK_RAMPRATE_5P00MV;
- break;
- case 5001 ... 10000:
- ramp_value = BUCK_RAMPRATE_10P00MV;
- break;
- default:
- ramp_value = BUCK_RAMPRATE_10P00MV;
- dev_err(&pmic->pdev->dev,
- "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
- rdev->desc->name, ramp_delay);
- }
-
- return regmap_update_bits(mfd->regmap, BD71837_REG_BUCK1_CTRL + id,
- BUCK_RAMPRATE_MASK, ramp_value << 6);
-}
-
-/* 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.
- */
-static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev,
- unsigned int sel)
-{
- if (regulator_is_enabled_regmap(rdev))
- return -EBUSY;
-
- return regulator_set_voltage_sel_regmap(rdev, sel);
-}
-
-static struct regulator_ops bd71837_ldo_regulator_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_linear_range,
- .set_voltage_sel = bd71837_set_voltage_sel_restricted,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
-
-static struct regulator_ops bd71837_ldo_regulator_nolinear_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_table,
- .set_voltage_sel = bd71837_set_voltage_sel_restricted,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
-
-static struct regulator_ops bd71837_buck_regulator_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_linear_range,
- .set_voltage_sel = bd71837_set_voltage_sel_restricted,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static struct regulator_ops bd71837_buck_regulator_nolinear_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_table,
- .set_voltage_sel = bd71837_set_voltage_sel_restricted,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static struct regulator_ops bd71837_buck1234_regulator_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
- .list_voltage = regulator_list_voltage_linear_range,
- .set_voltage_sel = regulator_set_voltage_sel_regmap,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_ramp_delay = bd71837_buck1234_set_ramp_delay,
-};
-
-/*
- * BUCK1/2/3/4
- * 0.70 to 1.30V (10mV step)
- */
-static const struct regulator_linear_range bd71837_buck1234_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
- REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
-};
-
-/*
- * BUCK5
- * 0.9V to 1.35V ()
- */
-static const struct regulator_linear_range bd71837_buck5_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
- REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
- REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
-};
-
-/*
- * BUCK6
- * 3.0V to 3.3V (step 100mV)
- */
-static const struct regulator_linear_range bd71837_buck6_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
-};
-
-/*
- * BUCK7
- * 000 = 1.605V
- * 001 = 1.695V
- * 010 = 1.755V
- * 011 = 1.8V (Initial)
- * 100 = 1.845V
- * 101 = 1.905V
- * 110 = 1.95V
- * 111 = 1.995V
- */
-static const unsigned int buck_7_volts[] = {
- 1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
-};
-
-/*
- * BUCK8
- * 0.8V to 1.40V (step 10mV)
- */
-static const struct regulator_linear_range bd71837_buck8_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
- REGULATOR_LINEAR_RANGE(1400000, 0x3D, 0x3F, 0),
-};
-
-/*
- * LDO1
- * 3.0 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
-};
-
-/*
- * LDO2
- * 0.8 or 0.9V
- */
-static const unsigned int ldo_2_volts[] = {
- 900000, 800000
-};
-
-/*
- * LDO3
- * 1.8 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo3_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
-};
-
-/*
- * LDO4
- * 0.9 to 1.8V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo4_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
- REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
-};
-
-/*
- * LDO5
- * 1.8 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo5_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
-};
-
-/*
- * LDO6
- * 0.9 to 1.8V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo6_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
- REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
-};
-
-/*
- * LDO7
- * 1.8 to 3.3V (100mV step)
- */
-static const struct regulator_linear_range bd71837_ldo7_voltage_ranges[] = {
- REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
-};
-
-static const struct regulator_desc bd71837_regulators[] = {
- {
- .name = "buck1",
- .of_match = of_match_ptr("BUCK1"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK1,
- .ops = &bd71837_buck1234_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK1_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck1234_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK1_VOLT_RUN,
- .vsel_mask = BUCK1_RUN_MASK,
- .enable_reg = BD71837_REG_BUCK1_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck2",
- .of_match = of_match_ptr("BUCK2"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK2,
- .ops = &bd71837_buck1234_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK2_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck1234_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK2_VOLT_RUN,
- .vsel_mask = BUCK2_RUN_MASK,
- .enable_reg = BD71837_REG_BUCK2_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck3",
- .of_match = of_match_ptr("BUCK3"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK3,
- .ops = &bd71837_buck1234_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK3_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck1234_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
- .vsel_mask = BUCK3_RUN_MASK,
- .enable_reg = BD71837_REG_BUCK3_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck4",
- .of_match = of_match_ptr("BUCK4"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK4,
- .ops = &bd71837_buck1234_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK4_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck1234_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
- .vsel_mask = BUCK4_RUN_MASK,
- .enable_reg = BD71837_REG_BUCK4_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck5",
- .of_match = of_match_ptr("BUCK5"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK5,
- .ops = &bd71837_buck_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck5_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck5_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK5_VOLT,
- .vsel_mask = BUCK5_MASK,
- .enable_reg = BD71837_REG_BUCK5_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck6",
- .of_match = of_match_ptr("BUCK6"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK6,
- .ops = &bd71837_buck_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck6_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck6_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK6_VOLT,
- .vsel_mask = BUCK6_MASK,
- .enable_reg = BD71837_REG_BUCK6_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck7",
- .of_match = of_match_ptr("BUCK7"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK7,
- .ops = &bd71837_buck_regulator_nolinear_ops,
- .type = REGULATOR_VOLTAGE,
- .volt_table = &buck_7_volts[0],
- .n_voltages = ARRAY_SIZE(buck_7_volts),
- .vsel_reg = BD71837_REG_BUCK7_VOLT,
- .vsel_mask = BUCK7_MASK,
- .enable_reg = BD71837_REG_BUCK7_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "buck8",
- .of_match = of_match_ptr("BUCK8"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_BUCK8,
- .ops = &bd71837_buck_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_BUCK8_VOLTAGE_NUM,
- .linear_ranges = bd71837_buck8_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_buck8_voltage_ranges),
- .vsel_reg = BD71837_REG_BUCK8_VOLT,
- .vsel_mask = BUCK8_MASK,
- .enable_reg = BD71837_REG_BUCK8_CTRL,
- .enable_mask = BD71837_BUCK_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo1",
- .of_match = of_match_ptr("LDO1"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO1,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO1_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo1_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo1_voltage_ranges),
- .vsel_reg = BD71837_REG_LDO1_VOLT,
- .vsel_mask = LDO1_MASK,
- .enable_reg = BD71837_REG_LDO1_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo2",
- .of_match = of_match_ptr("LDO2"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO2,
- .ops = &bd71837_ldo_regulator_nolinear_ops,
- .type = REGULATOR_VOLTAGE,
- .volt_table = &ldo_2_volts[0],
- .vsel_reg = BD71837_REG_LDO2_VOLT,
- .vsel_mask = LDO2_MASK,
- .n_voltages = ARRAY_SIZE(ldo_2_volts),
- .n_voltages = BD71837_LDO2_VOLTAGE_NUM,
- .enable_reg = BD71837_REG_LDO2_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo3",
- .of_match = of_match_ptr("LDO3"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO3,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO3_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo3_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo3_voltage_ranges),
- .vsel_reg = BD71837_REG_LDO3_VOLT,
- .vsel_mask = LDO3_MASK,
- .enable_reg = BD71837_REG_LDO3_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo4",
- .of_match = of_match_ptr("LDO4"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO4,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO4_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo4_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo4_voltage_ranges),
- .vsel_reg = BD71837_REG_LDO4_VOLT,
- .vsel_mask = LDO4_MASK,
- .enable_reg = BD71837_REG_LDO4_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo5",
- .of_match = of_match_ptr("LDO5"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO5,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO5_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo5_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_voltage_ranges),
- /* LDO5 is supplied by buck6 */
- .supply_name = "buck6",
- .vsel_reg = BD71837_REG_LDO5_VOLT,
- .vsel_mask = LDO5_MASK,
- .enable_reg = BD71837_REG_LDO5_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo6",
- .of_match = of_match_ptr("LDO6"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO6,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO6_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo6_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo6_voltage_ranges),
- /* LDO6 is supplied by buck7 */
- .supply_name = "buck7",
- .vsel_reg = BD71837_REG_LDO6_VOLT,
- .vsel_mask = LDO6_MASK,
- .enable_reg = BD71837_REG_LDO6_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
- {
- .name = "ldo7",
- .of_match = of_match_ptr("LDO7"),
- .regulators_node = of_match_ptr("regulators"),
- .id = BD71837_LDO7,
- .ops = &bd71837_ldo_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .n_voltages = BD71837_LDO7_VOLTAGE_NUM,
- .linear_ranges = bd71837_ldo7_voltage_ranges,
- .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_voltage_ranges),
- .vsel_reg = BD71837_REG_LDO7_VOLT,
- .vsel_mask = LDO7_MASK,
- .enable_reg = BD71837_REG_LDO7_VOLT,
- .enable_mask = BD71837_LDO_EN,
- .owner = THIS_MODULE,
- },
-};
-
-struct reg_init {
- unsigned int reg;
- unsigned int mask;
-};
-
-static int bd71837_probe(struct platform_device *pdev)
-{
- struct bd71837_pmic *pmic;
- struct regulator_config config = { 0 };
- struct reg_init pmic_regulator_inits[] = {
- {
- .reg = BD71837_REG_BUCK1_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK2_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK3_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK4_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK5_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK6_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK7_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_BUCK8_CTRL,
- .mask = BD71837_BUCK_SEL,
- }, {
- .reg = BD71837_REG_LDO1_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO2_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO3_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO4_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO5_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO6_VOLT,
- .mask = BD71837_LDO_SEL,
- }, {
- .reg = BD71837_REG_LDO7_VOLT,
- .mask = BD71837_LDO_SEL,
- }
- };
-
- int i, err;
-
- pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
- if (!pmic)
- return -ENOMEM;
-
- memcpy(pmic->descs, bd71837_regulators, sizeof(pmic->descs));
-
- pmic->pdev = pdev;
- pmic->mfd = dev_get_drvdata(pdev->dev.parent);
-
- if (!pmic->mfd) {
- dev_err(&pdev->dev, "No MFD driver data\n");
- err = -EINVAL;
- goto err;
- }
- platform_set_drvdata(pdev, pmic);
-
- /* Register LOCK release */
- err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK,
- (REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
- if (err) {
- dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err);
- goto err;
- } else {
- dev_dbg(&pmic->pdev->dev, "Unlocked lock register 0x%x\n",
- BD71837_REG_REGLOCK);
- }
-
- /*
- * There is a HW quirk in BD71837. The shutdown sequence timings for
- * bucks/LDOs which are controlled via register interface are changed.
- * At PMIC poweroff the voltage for BUCK6/7 is cut immediately at the
- * beginning of shut-down sequence. As bucks 6 and 7 are parent
- * supplies for LDO5 and LDO6 - this causes LDO5/6 voltage
- * monitoring to errorneously detect under voltage and force PMIC to
- * emergency state instead of poweroff. In order to avoid this we
- * disable voltage monitoring for LDO5 and LDO6
- */
- err = regmap_update_bits(pmic->mfd->regmap, BD718XX_REG_MVRFLTMASK2,
- BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80,
- BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80);
- if (err) {
- dev_err(&pmic->pdev->dev,
- "Failed to disable voltage monitoring\n");
- goto err;
- }
-
- for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) {
-
- struct regulator_desc *desc;
- struct regulator_dev *rdev;
-
- desc = &pmic->descs[i];
-
- config.dev = pdev->dev.parent;
- config.driver_data = pmic;
- config.regmap = pmic->mfd->regmap;
-
- rdev = devm_regulator_register(&pdev->dev, desc, &config);
- if (IS_ERR(rdev)) {
- dev_err(pmic->mfd->dev,
- "failed to register %s regulator\n",
- desc->name);
- err = PTR_ERR(rdev);
- goto err;
- }
- /* Regulator register gets the regulator constraints and
- * applies them (set_machine_constraints). This should have
- * turned the control register(s) to correct values and we
- * can now switch the control from PMIC state machine to the
- * register interface
- */
- err = regmap_update_bits(pmic->mfd->regmap,
- pmic_regulator_inits[i].reg,
- pmic_regulator_inits[i].mask,
- 0xFFFFFFFF);
- if (err) {
- dev_err(&pmic->pdev->dev,
- "Failed to write BUCK/LDO SEL bit for (%s)\n",
- desc->name);
- goto err;
- }
-
- pmic->rdev[i] = rdev;
- }
-
-err:
- return err;
-}
-
-static struct platform_driver bd71837_regulator = {
- .driver = {
- .name = "bd71837-pmic",
- },
- .probe = bd71837_probe,
-};
-
-module_platform_driver(bd71837_regulator);
-
-MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD71837 voltage regulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
new file mode 100644
index 000000000000..3a47e0372e77
--- /dev/null
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -0,0 +1,1119 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 ROHM Semiconductors
+// bd71837-regulator.c ROHM BD71837MWV/BD71847MWV regulator driver
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/rohm-bd718x7.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+/*
+ * BUCK1/2/3/4
+ * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
+ * 00: 10.00mV/usec 10mV 1uS
+ * 01: 5.00mV/usec 10mV 2uS
+ * 10: 2.50mV/usec 10mV 4uS
+ * 11: 1.25mV/usec 10mV 8uS
+ */
+static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev,
+ int ramp_delay)
+{
+ int id = rdev->desc->id;
+ unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
+
+ dev_dbg(&rdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
+ ramp_delay);
+ switch (ramp_delay) {
+ case 1 ... 1250:
+ ramp_value = BUCK_RAMPRATE_1P25MV;
+ break;
+ case 1251 ... 2500:
+ ramp_value = BUCK_RAMPRATE_2P50MV;
+ break;
+ case 2501 ... 5000:
+ ramp_value = BUCK_RAMPRATE_5P00MV;
+ break;
+ case 5001 ... 10000:
+ ramp_value = BUCK_RAMPRATE_10P00MV;
+ break;
+ default:
+ ramp_value = BUCK_RAMPRATE_10P00MV;
+ dev_err(&rdev->dev,
+ "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
+ rdev->desc->name, ramp_delay);
+ }
+
+ return regmap_update_bits(rdev->regmap, BD718XX_REG_BUCK1_CTRL + id,
+ BUCK_RAMPRATE_MASK, ramp_value << 6);
+}
+
+/* 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.
+ */
+static int bd718xx_set_voltage_sel_restricted(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ if (regulator_is_enabled_regmap(rdev))
+ return -EBUSY;
+
+ return regulator_set_voltage_sel_regmap(rdev, sel);
+}
+
+static int bd718xx_set_voltage_sel_pickable_restricted(
+ struct regulator_dev *rdev, unsigned int sel)
+{
+ if (regulator_is_enabled_regmap(rdev))
+ return -EBUSY;
+
+ return regulator_set_voltage_sel_pickable_regmap(rdev, sel);
+}
+
+static struct regulator_ops bd718xx_pickable_range_ldo_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+};
+
+static struct regulator_ops bd718xx_pickable_range_buck_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd718xx_ldo_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd718xx_ldo_regulator_nolinear_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd718xx_buck_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd718xx_buck_regulator_nolinear_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = bd718xx_set_voltage_sel_restricted,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd718xx_dvs_buck_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = bd718xx_buck1234_set_ramp_delay,
+};
+
+/*
+ * BD71837 BUCK1/2/3/4
+ * BD71847 BUCK1/2
+ * 0.70 to 1.30V (10mV step)
+ */
+static const struct regulator_linear_range bd718xx_dvs_buck_volts[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
+};
+
+/*
+ * BD71837 BUCK5
+ * 0.7V to 1.35V (range 0)
+ * and
+ * 0.675 to 1.325 (range 1)
+ */
+static const struct regulator_linear_range bd71837_buck5_volts[] = {
+ /* Ranges when VOLT_SEL bit is 0 */
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+ REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+ /* Ranges when VOLT_SEL bit is 1 */
+ REGULATOR_LINEAR_RANGE(675000, 0x0, 0x3, 100000),
+ REGULATOR_LINEAR_RANGE(1025000, 0x4, 0x5, 50000),
+ REGULATOR_LINEAR_RANGE(1175000, 0x6, 0x7, 150000),
+};
+
+/*
+ * Range selector for first 3 linear ranges is 0x0
+ * and 0x1 for last 3 ranges.
+ */
+static const unsigned int bd71837_buck5_volt_range_sel[] = {
+ 0x0, 0x0, 0x0, 0x80, 0x80, 0x80
+};
+
+/*
+ * BD71847 BUCK3
+ */
+static const struct regulator_linear_range bd71847_buck3_volts[] = {
+ /* Ranges when VOLT_SEL bits are 00 */
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+ REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+ /* Ranges when VOLT_SEL bits are 01 */
+ REGULATOR_LINEAR_RANGE(550000, 0x0, 0x7, 50000),
+ /* Ranges when VOLT_SEL bits are 11 */
+ REGULATOR_LINEAR_RANGE(675000, 0x0, 0x3, 100000),
+ REGULATOR_LINEAR_RANGE(1025000, 0x4, 0x5, 50000),
+ REGULATOR_LINEAR_RANGE(1175000, 0x6, 0x7, 150000),
+};
+
+static const unsigned int bd71847_buck3_volt_range_sel[] = {
+ 0x0, 0x0, 0x0, 0x40, 0x80, 0x80, 0x80
+};
+
+static const struct regulator_linear_range bd71847_buck4_volts[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(2600000, 0x00, 0x03, 100000),
+};
+
+static const unsigned int bd71847_buck4_volt_range_sel[] = { 0x0, 0x40 };
+
+/*
+ * BUCK6
+ * 3.0V to 3.3V (step 100mV)
+ */
+static const struct regulator_linear_range bd71837_buck6_volts[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+/*
+ * BD71837 BUCK7
+ * BD71847 BUCK5
+ * 000 = 1.605V
+ * 001 = 1.695V
+ * 010 = 1.755V
+ * 011 = 1.8V (Initial)
+ * 100 = 1.845V
+ * 101 = 1.905V
+ * 110 = 1.95V
+ * 111 = 1.995V
+ */
+static const unsigned int bd718xx_3rd_nodvs_buck_volts[] = {
+ 1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
+};
+
+/*
+ * BUCK8
+ * 0.8V to 1.40V (step 10mV)
+ */
+static const struct regulator_linear_range bd718xx_4th_nodvs_buck_volts[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
+};
+
+/*
+ * LDO1
+ * 3.0 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo1_volts[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(1600000, 0x00, 0x03, 100000),
+};
+
+static const unsigned int bd718xx_ldo1_volt_range_sel[] = { 0x0, 0x20 };
+
+/*
+ * LDO2
+ * 0.8 or 0.9V
+ */
+static const unsigned int ldo_2_volts[] = {
+ 900000, 800000
+};
+
+/*
+ * LDO3
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo3_volts[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO4
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo4_volts[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+};
+
+/*
+ * LDO5 for BD71837
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo5_volts[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO5 for BD71837
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71847_ldo5_volts[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x0F, 100000),
+};
+
+static const unsigned int bd71847_ldo5_volt_range_sel[] = { 0x0, 0x20 };
+
+/*
+ * LDO6
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd718xx_ldo6_volts[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+};
+
+/*
+ * LDO7
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo7_volts[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+struct reg_init {
+ unsigned int reg;
+ unsigned int mask;
+ unsigned int val;
+};
+struct bd718xx_regulator_data {
+ struct regulator_desc desc;
+ const struct reg_init init;
+ const struct reg_init *additional_inits;
+ int additional_init_amnt;
+};
+
+/*
+ * There is a HW quirk in BD71837. The shutdown sequence timings for
+ * bucks/LDOs which are controlled via register interface are changed.
+ * At PMIC poweroff the voltage for BUCK6/7 is cut immediately at the
+ * beginning of shut-down sequence. As bucks 6 and 7 are parent
+ * supplies for LDO5 and LDO6 - this causes LDO5/6 voltage
+ * monitoring to errorneously detect under voltage and force PMIC to
+ * emergency state instead of poweroff. In order to avoid this we
+ * disable voltage monitoring for LDO5 and LDO6
+ */
+static const struct reg_init bd71837_ldo5_inits[] = {
+ {
+ .reg = BD718XX_REG_MVRFLTMASK2,
+ .mask = BD718XX_LDO5_VRMON80,
+ .val = BD718XX_LDO5_VRMON80,
+ },
+};
+
+static const struct reg_init bd71837_ldo6_inits[] = {
+ {
+ .reg = BD718XX_REG_MVRFLTMASK2,
+ .mask = BD718XX_LDO6_VRMON80,
+ .val = BD718XX_LDO6_VRMON80,
+ },
+};
+
+static const struct bd718xx_regulator_data bd71847_regulators[] = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("BUCK1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK1,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD718XX_REG_BUCK1_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD718XX_REG_BUCK1_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_BUCK1_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("BUCK2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK2,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD718XX_REG_BUCK2_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD718XX_REG_BUCK2_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_BUCK2_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck3",
+ .of_match = of_match_ptr("BUCK3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK3,
+ .ops = &bd718xx_pickable_range_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71847_BUCK3_VOLTAGE_NUM,
+ .linear_ranges = bd71847_buck3_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd71847_buck3_volts),
+ .vsel_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_1ST_NODVS_BUCK_MASK,
+ .vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+ .vsel_range_mask = BD71847_BUCK3_RANGE_MASK,
+ .linear_range_selectors = bd71847_buck3_volt_range_sel,
+ .enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("BUCK4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK4,
+ .ops = &bd718xx_pickable_range_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71847_BUCK4_VOLTAGE_NUM,
+ .linear_ranges = bd71847_buck4_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd71847_buck4_volts),
+ .enable_reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+ .vsel_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+ .vsel_mask = BD71847_BUCK4_MASK,
+ .vsel_range_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+ .vsel_range_mask = BD71847_BUCK4_RANGE_MASK,
+ .linear_range_selectors = bd71847_buck4_volt_range_sel,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck5",
+ .of_match = of_match_ptr("BUCK5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK5,
+ .ops = &bd718xx_buck_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &bd718xx_3rd_nodvs_buck_volts[0],
+ .n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts),
+ .vsel_reg = BD718XX_REG_3RD_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_3RD_NODVS_BUCK_MASK,
+ .enable_reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck6",
+ .of_match = of_match_ptr("BUCK6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK6,
+ .ops = &bd718xx_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_4th_nodvs_buck_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd718xx_4th_nodvs_buck_volts),
+ .vsel_reg = BD718XX_REG_4TH_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_4TH_NODVS_BUCK_MASK,
+ .enable_reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO1,
+ .ops = &bd718xx_pickable_range_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO1_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo1_volts),
+ .vsel_reg = BD718XX_REG_LDO1_VOLT,
+ .vsel_mask = BD718XX_LDO1_MASK,
+ .vsel_range_reg = BD718XX_REG_LDO1_VOLT,
+ .vsel_range_mask = BD718XX_LDO1_RANGE_MASK,
+ .linear_range_selectors = bd718xx_ldo1_volt_range_sel,
+ .enable_reg = BD718XX_REG_LDO1_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO1_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO2,
+ .ops = &bd718xx_ldo_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &ldo_2_volts[0],
+ .vsel_reg = BD718XX_REG_LDO2_VOLT,
+ .vsel_mask = BD718XX_LDO2_MASK,
+ .n_voltages = ARRAY_SIZE(ldo_2_volts),
+ .enable_reg = BD718XX_REG_LDO2_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO2_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo3",
+ .of_match = of_match_ptr("LDO3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO3,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO3_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo3_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo3_volts),
+ .vsel_reg = BD718XX_REG_LDO3_VOLT,
+ .vsel_mask = BD718XX_LDO3_MASK,
+ .enable_reg = BD718XX_REG_LDO3_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO3_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo4",
+ .of_match = of_match_ptr("LDO4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO4,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO4_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo4_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo4_volts),
+ .vsel_reg = BD718XX_REG_LDO4_VOLT,
+ .vsel_mask = BD718XX_LDO4_MASK,
+ .enable_reg = BD718XX_REG_LDO4_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO4_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo5",
+ .of_match = of_match_ptr("LDO5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO5,
+ .ops = &bd718xx_pickable_range_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71847_LDO5_VOLTAGE_NUM,
+ .linear_ranges = bd71847_ldo5_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd71847_ldo5_volts),
+ .vsel_reg = BD718XX_REG_LDO5_VOLT,
+ .vsel_mask = BD71847_LDO5_MASK,
+ .vsel_range_reg = BD718XX_REG_LDO5_VOLT,
+ .vsel_range_mask = BD71847_LDO5_RANGE_MASK,
+ .linear_range_selectors = bd71847_ldo5_volt_range_sel,
+ .enable_reg = BD718XX_REG_LDO5_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO5_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo6",
+ .of_match = of_match_ptr("LDO6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO6,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO6_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo6_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo6_volts),
+ /* LDO6 is supplied by buck5 */
+ .supply_name = "buck5",
+ .vsel_reg = BD718XX_REG_LDO6_VOLT,
+ .vsel_mask = BD718XX_LDO6_MASK,
+ .enable_reg = BD718XX_REG_LDO6_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO6_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+};
+
+static const struct bd718xx_regulator_data bd71837_regulators[] = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("BUCK1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK1,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD718XX_REG_BUCK1_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD718XX_REG_BUCK1_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_BUCK1_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("BUCK2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK2,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD718XX_REG_BUCK2_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD718XX_REG_BUCK2_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_BUCK2_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck3",
+ .of_match = of_match_ptr("BUCK3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK3,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK3_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD71837_REG_BUCK3_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("BUCK4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK4,
+ .ops = &bd718xx_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_dvs_buck_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_dvs_buck_volts),
+ .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
+ .vsel_mask = DVS_BUCK_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK4_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD71837_REG_BUCK4_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck5",
+ .of_match = of_match_ptr("BUCK5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK5,
+ .ops = &bd718xx_pickable_range_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck5_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd71837_buck5_volts),
+ .vsel_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+ .vsel_mask = BD71837_BUCK5_MASK,
+ .vsel_range_reg = BD718XX_REG_1ST_NODVS_BUCK_VOLT,
+ .vsel_range_mask = BD71837_BUCK5_RANGE_MASK,
+ .linear_range_selectors = bd71837_buck5_volt_range_sel,
+ .enable_reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_1ST_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck6",
+ .of_match = of_match_ptr("BUCK6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK6,
+ .ops = &bd718xx_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck6_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd71837_buck6_volts),
+ .vsel_reg = BD718XX_REG_2ND_NODVS_BUCK_VOLT,
+ .vsel_mask = BD71837_BUCK6_MASK,
+ .enable_reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_2ND_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck7",
+ .of_match = of_match_ptr("BUCK7"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK7,
+ .ops = &bd718xx_buck_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &bd718xx_3rd_nodvs_buck_volts[0],
+ .n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts),
+ .vsel_reg = BD718XX_REG_3RD_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_3RD_NODVS_BUCK_MASK,
+ .enable_reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_3RD_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck8",
+ .of_match = of_match_ptr("BUCK8"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_BUCK8,
+ .ops = &bd718xx_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_4th_nodvs_buck_volts,
+ .n_linear_ranges =
+ ARRAY_SIZE(bd718xx_4th_nodvs_buck_volts),
+ .vsel_reg = BD718XX_REG_4TH_NODVS_BUCK_VOLT,
+ .vsel_mask = BD718XX_4TH_NODVS_BUCK_MASK,
+ .enable_reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+ .enable_mask = BD718XX_BUCK_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_4TH_NODVS_BUCK_CTRL,
+ .mask = BD718XX_BUCK_SEL,
+ .val = BD718XX_BUCK_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO1,
+ .ops = &bd718xx_pickable_range_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO1_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo1_volts),
+ .vsel_reg = BD718XX_REG_LDO1_VOLT,
+ .vsel_mask = BD718XX_LDO1_MASK,
+ .vsel_range_reg = BD718XX_REG_LDO1_VOLT,
+ .vsel_range_mask = BD718XX_LDO1_RANGE_MASK,
+ .linear_range_selectors = bd718xx_ldo1_volt_range_sel,
+ .enable_reg = BD718XX_REG_LDO1_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO1_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO2,
+ .ops = &bd718xx_ldo_regulator_nolinear_ops,
+ .type = REGULATOR_VOLTAGE,
+ .volt_table = &ldo_2_volts[0],
+ .vsel_reg = BD718XX_REG_LDO2_VOLT,
+ .vsel_mask = BD718XX_LDO2_MASK,
+ .n_voltages = ARRAY_SIZE(ldo_2_volts),
+ .enable_reg = BD718XX_REG_LDO2_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO2_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo3",
+ .of_match = of_match_ptr("LDO3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO3,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO3_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo3_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo3_volts),
+ .vsel_reg = BD718XX_REG_LDO3_VOLT,
+ .vsel_mask = BD718XX_LDO3_MASK,
+ .enable_reg = BD718XX_REG_LDO3_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO3_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo4",
+ .of_match = of_match_ptr("LDO4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO4,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO4_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo4_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo4_volts),
+ .vsel_reg = BD718XX_REG_LDO4_VOLT,
+ .vsel_mask = BD718XX_LDO4_MASK,
+ .enable_reg = BD718XX_REG_LDO4_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO4_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo5",
+ .of_match = of_match_ptr("LDO5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO5,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO5_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo5_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_volts),
+ /* LDO5 is supplied by buck6 */
+ .supply_name = "buck6",
+ .vsel_reg = BD718XX_REG_LDO5_VOLT,
+ .vsel_mask = BD71837_LDO5_MASK,
+ .enable_reg = BD718XX_REG_LDO5_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO5_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ .additional_inits = bd71837_ldo5_inits,
+ .additional_init_amnt = ARRAY_SIZE(bd71837_ldo5_inits),
+ },
+ {
+ .desc = {
+ .name = "ldo6",
+ .of_match = of_match_ptr("LDO6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO6,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD718XX_LDO6_VOLTAGE_NUM,
+ .linear_ranges = bd718xx_ldo6_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd718xx_ldo6_volts),
+ /* LDO6 is supplied by buck7 */
+ .supply_name = "buck7",
+ .vsel_reg = BD718XX_REG_LDO6_VOLT,
+ .vsel_mask = BD718XX_LDO6_MASK,
+ .enable_reg = BD718XX_REG_LDO6_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD718XX_REG_LDO6_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ .additional_inits = bd71837_ldo6_inits,
+ .additional_init_amnt = ARRAY_SIZE(bd71837_ldo6_inits),
+ },
+ {
+ .desc = {
+ .name = "ldo7",
+ .of_match = of_match_ptr("LDO7"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD718XX_LDO7,
+ .ops = &bd718xx_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO7_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo7_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_volts),
+ .vsel_reg = BD71837_REG_LDO7_VOLT,
+ .vsel_mask = BD71837_LDO7_MASK,
+ .enable_reg = BD71837_REG_LDO7_VOLT,
+ .enable_mask = BD718XX_LDO_EN,
+ .owner = THIS_MODULE,
+ },
+ .init = {
+ .reg = BD71837_REG_LDO7_VOLT,
+ .mask = BD718XX_LDO_SEL,
+ .val = BD718XX_LDO_SEL,
+ },
+ },
+};
+
+struct bd718xx_pmic_inits {
+ const struct bd718xx_regulator_data (*r_datas)[];
+ unsigned int r_amount;
+};
+
+static int bd718xx_probe(struct platform_device *pdev)
+{
+ struct bd718xx *mfd;
+ struct regulator_config config = { 0 };
+ struct bd718xx_pmic_inits pmic_regulators[] = {
+ [BD718XX_TYPE_BD71837] = {
+ .r_datas = &bd71837_regulators,
+ .r_amount = ARRAY_SIZE(bd71837_regulators),
+ },
+ [BD718XX_TYPE_BD71847] = {
+ .r_datas = &bd71847_regulators,
+ .r_amount = ARRAY_SIZE(bd71847_regulators),
+ },
+ };
+
+ int i, j, err;
+
+ mfd = dev_get_drvdata(pdev->dev.parent);
+ if (!mfd) {
+ dev_err(&pdev->dev, "No MFD driver data\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ if (mfd->chip_type >= BD718XX_TYPE_AMOUNT ||
+ !pmic_regulators[mfd->chip_type].r_datas) {
+ dev_err(&pdev->dev, "Unsupported chip type\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ /* Register LOCK release */
+ err = regmap_update_bits(mfd->regmap, BD718XX_REG_REGLOCK,
+ (REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to unlock PMIC (%d)\n", err);
+ goto err;
+ } else {
+ dev_dbg(&pdev->dev, "Unlocked lock register 0x%x\n",
+ BD718XX_REG_REGLOCK);
+ }
+
+ for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) {
+
+ const struct regulator_desc *desc;
+ struct regulator_dev *rdev;
+ const struct bd718xx_regulator_data *r;
+
+ r = &(*pmic_regulators[mfd->chip_type].r_datas)[i];
+ desc = &r->desc;
+
+ config.dev = pdev->dev.parent;
+ config.regmap = mfd->regmap;
+
+ rdev = devm_regulator_register(&pdev->dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
+ "failed to register %s regulator\n",
+ desc->name);
+ err = PTR_ERR(rdev);
+ goto err;
+ }
+ /* Regulator register gets the regulator constraints and
+ * applies them (set_machine_constraints). This should have
+ * turned the control register(s) to correct values and we
+ * can now switch the control from PMIC state machine to the
+ * register interface
+ */
+ err = regmap_update_bits(mfd->regmap, r->init.reg,
+ r->init.mask, r->init.val);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to write BUCK/LDO SEL bit for (%s)\n",
+ desc->name);
+ goto err;
+ }
+ for (j = 0; j < r->additional_init_amnt; j++) {
+ err = regmap_update_bits(mfd->regmap,
+ r->additional_inits[j].reg,
+ r->additional_inits[j].mask,
+ r->additional_inits[j].val);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Buck (%s) initialization failed\n",
+ desc->name);
+ goto err;
+ }
+ }
+ }
+
+err:
+ return err;
+}
+
+static struct platform_driver bd718xx_regulator = {
+ .driver = {
+ .name = "bd718xx-pmic",
+ },
+ .probe = bd718xx_probe,
+};
+
+module_platform_driver(bd718xx_regulator);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("BD71837/BD71847 voltage regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9577d8941846..2c66b528aede 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -426,19 +426,24 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(name);
-static ssize_t regulator_print_opmode(char *buf, int mode)
+static const char *regulator_opmode_to_str(int mode)
{
switch (mode) {
case REGULATOR_MODE_FAST:
- return sprintf(buf, "fast\n");
+ return "fast";
case REGULATOR_MODE_NORMAL:
- return sprintf(buf, "normal\n");
+ return "normal";
case REGULATOR_MODE_IDLE:
- return sprintf(buf, "idle\n");
+ return "idle";
case REGULATOR_MODE_STANDBY:
- return sprintf(buf, "standby\n");
+ return "standby";
}
- return sprintf(buf, "unknown\n");
+ return "unknown";
+}
+
+static ssize_t regulator_print_opmode(char *buf, int mode)
+{
+ return sprintf(buf, "%s\n", regulator_opmode_to_str(mode));
}
static ssize_t regulator_opmode_show(struct device *dev,
@@ -2783,6 +2788,11 @@ static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
if (desc->ops->list_voltage == regulator_list_voltage_linear_range)
return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
+ if (desc->ops->list_voltage ==
+ regulator_list_voltage_pickable_linear_range)
+ return regulator_map_voltage_pickable_linear_range(rdev,
+ min_uV, max_uV);
+
return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
}
@@ -3470,21 +3480,23 @@ out:
}
EXPORT_SYMBOL_GPL(regulator_set_current_limit);
+static int _regulator_get_current_limit_unlocked(struct regulator_dev *rdev)
+{
+ /* sanity check */
+ if (!rdev->desc->ops->get_current_limit)
+ return -EINVAL;
+
+ return rdev->desc->ops->get_current_limit(rdev);
+}
+
static int _regulator_get_current_limit(struct regulator_dev *rdev)
{
int ret;
regulator_lock(rdev);
-
- /* sanity check */
- if (!rdev->desc->ops->get_current_limit) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = rdev->desc->ops->get_current_limit(rdev);
-out:
+ ret = _regulator_get_current_limit_unlocked(rdev);
regulator_unlock(rdev);
+
return ret;
}
@@ -3549,21 +3561,23 @@ out:
}
EXPORT_SYMBOL_GPL(regulator_set_mode);
+static unsigned int _regulator_get_mode_unlocked(struct regulator_dev *rdev)
+{
+ /* sanity check */
+ if (!rdev->desc->ops->get_mode)
+ return -EINVAL;
+
+ return rdev->desc->ops->get_mode(rdev);
+}
+
static unsigned int _regulator_get_mode(struct regulator_dev *rdev)
{
int ret;
regulator_lock(rdev);
-
- /* sanity check */
- if (!rdev->desc->ops->get_mode) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = rdev->desc->ops->get_mode(rdev);
-out:
+ ret = _regulator_get_mode_unlocked(rdev);
regulator_unlock(rdev);
+
return ret;
}
@@ -4455,41 +4469,33 @@ void regulator_unregister(struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(regulator_unregister);
#ifdef CONFIG_SUSPEND
-static int _regulator_suspend(struct device *dev, void *data)
-{
- struct regulator_dev *rdev = dev_to_rdev(dev);
- suspend_state_t *state = data;
- int ret;
-
- regulator_lock(rdev);
- ret = suspend_set_state(rdev, *state);
- regulator_unlock(rdev);
-
- return ret;
-}
-
/**
* regulator_suspend - prepare regulators for system wide suspend
- * @state: system suspend state
+ * @dev: ``&struct device`` pointer that is passed to _regulator_suspend()
*
* Configure each regulator with it's suspend operating parameters for state.
*/
static int regulator_suspend(struct device *dev)
{
+ struct regulator_dev *rdev = dev_to_rdev(dev);
suspend_state_t state = pm_suspend_target_state;
+ int ret;
+
+ regulator_lock(rdev);
+ ret = suspend_set_state(rdev, state);
+ regulator_unlock(rdev);
- return class_for_each_device(&regulator_class, NULL, &state,
- _regulator_suspend);
+ return ret;
}
-static int _regulator_resume(struct device *dev, void *data)
+static int regulator_resume(struct device *dev)
{
- int ret = 0;
+ suspend_state_t state = pm_suspend_target_state;
struct regulator_dev *rdev = dev_to_rdev(dev);
- suspend_state_t *state = data;
struct regulator_state *rstate;
+ int ret = 0;
- rstate = regulator_get_suspend_state(rdev, *state);
+ rstate = regulator_get_suspend_state(rdev, state);
if (rstate == NULL)
return 0;
@@ -4504,15 +4510,6 @@ static int _regulator_resume(struct device *dev, void *data)
return ret;
}
-
-static int regulator_resume(struct device *dev)
-{
- suspend_state_t state = pm_suspend_target_state;
-
- return class_for_each_device(&regulator_class, NULL, &state,
- _regulator_resume);
-}
-
#else /* !CONFIG_SUSPEND */
#define regulator_suspend NULL
@@ -4670,17 +4667,23 @@ static void regulator_summary_show_subtree(struct seq_file *s,
struct regulation_constraints *c;
struct regulator *consumer;
struct summary_data summary_data;
+ unsigned int opmode;
if (!rdev)
return;
- seq_printf(s, "%*s%-*s %3d %4d %6d ",
+ regulator_lock_nested(rdev, level);
+
+ opmode = _regulator_get_mode_unlocked(rdev);
+ seq_printf(s, "%*s%-*s %3d %4d %6d %7s ",
level * 3 + 1, "",
30 - level * 3, rdev_get_name(rdev),
- rdev->use_count, rdev->open_count, rdev->bypass_count);
+ rdev->use_count, rdev->open_count, rdev->bypass_count,
+ regulator_opmode_to_str(opmode));
seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000);
- seq_printf(s, "%5dmA ", _regulator_get_current_limit(rdev) / 1000);
+ seq_printf(s, "%5dmA ",
+ _regulator_get_current_limit_unlocked(rdev) / 1000);
c = rdev->constraints;
if (c) {
@@ -4709,7 +4712,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
switch (rdev->desc->type) {
case REGULATOR_VOLTAGE:
- seq_printf(s, "%37dmV %5dmV",
+ seq_printf(s, "%37dmA %5dmV %5dmV",
+ consumer->uA_load / 1000,
consumer->voltage[PM_SUSPEND_ON].min_uV / 1000,
consumer->voltage[PM_SUSPEND_ON].max_uV / 1000);
break;
@@ -4726,6 +4730,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
class_for_each_device(&regulator_class, NULL, &summary_data,
regulator_summary_show_children);
+
+ regulator_unlock(rdev);
}
static int regulator_summary_show_roots(struct device *dev, void *data)
@@ -4741,8 +4747,8 @@ static int regulator_summary_show_roots(struct device *dev, void *data)
static int regulator_summary_show(struct seq_file *s, void *data)
{
- seq_puts(s, " regulator use open bypass voltage current min max\n");
- seq_puts(s, "-------------------------------------------------------------------------------\n");
+ seq_puts(s, " regulator use open bypass opmode voltage current min max\n");
+ seq_puts(s, "---------------------------------------------------------------------------------------\n");
class_for_each_device(&regulator_class, NULL, s,
regulator_summary_show_roots);
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 9ececfef42d6..37e4025203e3 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -420,7 +420,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
config.dev = &pdev->dev;
config.driver_data = regulator;
config.regmap = da9052->regmap;
- if (pdata && pdata->regulators) {
+ if (pdata) {
config.init_data = pdata->regulators[cell->id];
} else {
#ifdef CONFIG_OF
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index f40c3b8644ae..588c3d2445cf 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -612,7 +612,7 @@ static int da9055_regulator_probe(struct platform_device *pdev)
config.driver_data = regulator;
config.regmap = da9055->regmap;
- if (pdata && pdata->regulators) {
+ if (pdata) {
config.init_data = pdata->regulators[pdev->id];
} else {
ret = da9055_regulator_dt_init(pdev, regulator, &config,
diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c
index 6c122b3df5d0..8f68c7a05d27 100644
--- a/drivers/regulator/da9211-regulator.c
+++ b/drivers/regulator/da9211-regulator.c
@@ -294,11 +294,11 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
pdata->init_data[n] = da9211_matches[i].init_data;
pdata->reg_node[n] = da9211_matches[i].of_node;
pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev,
- da9211_matches[i].of_node,
- "enable",
- 0,
- GPIOD_OUT_HIGH,
- "da9211-enable");
+ da9211_matches[i].of_node,
+ "enable",
+ 0,
+ GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+ "da9211-enable");
n++;
}
diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c
index 777fac6fb4cb..2c6098e6f4bc 100644
--- a/drivers/regulator/fixed-helper.c
+++ b/drivers/regulator/fixed-helper.c
@@ -43,7 +43,6 @@ struct platform_device *regulator_register_always_on(int id, const char *name,
}
data->cfg.microvolts = uv;
- data->cfg.gpio = -EINVAL;
data->cfg.enabled_at_boot = 1;
data->cfg.init_data = &data->init_data;
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 988a7472c2ab..ccc29038f19a 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -24,10 +24,9 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
@@ -78,15 +77,16 @@ of_get_fixed_voltage_config(struct device *dev,
if (init_data->constraints.boot_on)
config->enabled_at_boot = true;
- config->gpio = of_get_named_gpio(np, "gpio", 0);
- if ((config->gpio < 0) && (config->gpio != -ENOENT))
- return ERR_PTR(config->gpio);
-
of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
- config->enable_high = of_property_read_bool(np, "enable-active-high");
- config->gpio_is_open_drain = of_property_read_bool(np,
- "gpio-open-drain");
+ /*
+ * FIXME: we pulled active low/high and open drain handling into
+ * gpiolib so it will be handled there. Delete this in the second
+ * step when we also remove the custom inversion handling for all
+ * legacy boardfiles.
+ */
+ config->enable_high = 1;
+ config->gpio_is_open_drain = 0;
if (of_find_property(np, "vin-supply", NULL))
config->input_supply = "vin";
@@ -102,6 +102,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
struct fixed_voltage_config *config;
struct fixed_voltage_data *drvdata;
struct regulator_config cfg = { };
+ enum gpiod_flags gflags;
int ret;
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
@@ -150,25 +151,41 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.fixed_uV = config->microvolts;
- if (gpio_is_valid(config->gpio)) {
- cfg.ena_gpio = config->gpio;
- if (pdev->dev.of_node)
- cfg.ena_gpio_initialized = true;
- }
cfg.ena_gpio_invert = !config->enable_high;
if (config->enabled_at_boot) {
if (config->enable_high)
- cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+ gflags = GPIOD_OUT_HIGH;
else
- cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+ gflags = GPIOD_OUT_LOW;
} else {
if (config->enable_high)
- cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+ gflags = GPIOD_OUT_LOW;
else
- cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+ gflags = GPIOD_OUT_HIGH;
}
- if (config->gpio_is_open_drain)
- cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN;
+ if (config->gpio_is_open_drain) {
+ if (gflags == GPIOD_OUT_HIGH)
+ gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
+ else
+ gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
+ }
+
+ /*
+ * Some fixed regulators share the enable line between two
+ * regulators which makes it necessary to get a handle on the
+ * same descriptor for two different consumers. This will get
+ * the GPIO descriptor, but only the first call will initialize
+ * it so any flags such as inversion or open drain will only
+ * be set up by the first caller and assumed identical on the
+ * next caller.
+ *
+ * FIXME: find a better way to deal with this.
+ */
+ gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
+
+ cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags);
+ if (IS_ERR(cfg.ena_gpiod))
+ return PTR_ERR(cfg.ena_gpiod);
cfg.dev = &pdev->dev;
cfg.init_data = config->init_data;
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index 2ae7c3ac5940..5686a1335bd3 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -103,6 +103,128 @@ int regulator_disable_regmap(struct regulator_dev *rdev)
}
EXPORT_SYMBOL_GPL(regulator_disable_regmap);
+static int regulator_range_selector_to_index(struct regulator_dev *rdev,
+ unsigned int rval)
+{
+ int i;
+
+ if (!rdev->desc->linear_range_selectors)
+ return -EINVAL;
+
+ rval &= rdev->desc->vsel_range_mask;
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ if (rdev->desc->linear_range_selectors[i] == rval)
+ return i;
+ }
+ return -EINVAL;
+}
+
+/**
+ * regulator_get_voltage_sel_pickable_regmap - pickable range get_voltage_sel
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O and use pickable
+ * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
+ * fields in their descriptor and then use this as their get_voltage_vsel
+ * operation, saving some code.
+ */
+int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev)
+{
+ unsigned int r_val;
+ int range;
+ unsigned int val;
+ int ret, i;
+ unsigned int voltages_in_range = 0;
+
+ if (!rdev->desc->linear_ranges)
+ return -EINVAL;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+ if (ret != 0)
+ return ret;
+
+ ret = regmap_read(rdev->regmap, rdev->desc->vsel_range_reg, &r_val);
+ if (ret != 0)
+ return ret;
+
+ val &= rdev->desc->vsel_mask;
+ val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+ range = regulator_range_selector_to_index(rdev, r_val);
+ if (range < 0)
+ return -EINVAL;
+
+ for (i = 0; i < range; i++)
+ voltages_in_range += (rdev->desc->linear_ranges[i].max_sel -
+ rdev->desc->linear_ranges[i].min_sel) + 1;
+
+ return val + voltages_in_range;
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap);
+
+/**
+ * regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O and use pickable
+ * ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
+ * fields in their descriptor and then use this as their set_voltage_vsel
+ * operation, saving some code.
+ */
+int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
+ unsigned int sel)
+{
+ unsigned int range;
+ int ret, i;
+ unsigned int voltages_in_range = 0;
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ voltages_in_range = (rdev->desc->linear_ranges[i].max_sel -
+ rdev->desc->linear_ranges[i].min_sel) + 1;
+ if (sel < voltages_in_range)
+ break;
+ sel -= voltages_in_range;
+ }
+
+ if (i == rdev->desc->n_linear_ranges)
+ return -EINVAL;
+
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+ sel += rdev->desc->linear_ranges[i].min_sel;
+
+ range = rdev->desc->linear_range_selectors[i];
+
+ if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) {
+ ret = regmap_update_bits(rdev->regmap,
+ rdev->desc->vsel_reg,
+ rdev->desc->vsel_range_mask |
+ rdev->desc->vsel_mask, sel | range);
+ } else {
+ ret = regmap_update_bits(rdev->regmap,
+ rdev->desc->vsel_range_reg,
+ rdev->desc->vsel_range_mask, range);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+ rdev->desc->vsel_mask, sel);
+ }
+
+ if (ret)
+ return ret;
+
+ if (rdev->desc->apply_bit)
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+ rdev->desc->apply_bit,
+ rdev->desc->apply_bit);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_pickable_regmap);
+
/**
* regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
*
@@ -321,20 +443,91 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
ret += range->min_sel;
- break;
+ /*
+ * Map back into a voltage to verify we're still in bounds.
+ * If we are not, then continue checking rest of the ranges.
+ */
+ voltage = rdev->desc->ops->list_voltage(rdev, ret);
+ if (voltage >= min_uV && voltage <= max_uV)
+ break;
}
if (i == rdev->desc->n_linear_ranges)
return -EINVAL;
- /* Map back into a voltage to verify we're still in bounds */
- voltage = rdev->desc->ops->list_voltage(rdev, ret);
- if (voltage < min_uV || voltage > max_uV)
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
+
+/**
+ * regulator_map_voltage_pickable_linear_range - map_voltage, pickable ranges
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing pickable linear_ranges in their descriptor can use
+ * this as their map_voltage() callback.
+ */
+int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ const struct regulator_linear_range *range;
+ int ret = -EINVAL;
+ int voltage, i;
+ unsigned int selector = 0;
+
+ if (!rdev->desc->n_linear_ranges) {
+ BUG_ON(!rdev->desc->n_linear_ranges);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ int linear_max_uV;
+
+ range = &rdev->desc->linear_ranges[i];
+ linear_max_uV = range->min_uV +
+ (range->max_sel - range->min_sel) * range->uV_step;
+
+ if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) {
+ selector += (range->max_sel - range->min_sel + 1);
+ continue;
+ }
+
+ if (min_uV <= range->min_uV)
+ min_uV = range->min_uV;
+
+ /* range->uV_step == 0 means fixed voltage range */
+ if (range->uV_step == 0) {
+ ret = 0;
+ } else {
+ ret = DIV_ROUND_UP(min_uV - range->min_uV,
+ range->uV_step);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret += selector;
+
+ voltage = rdev->desc->ops->list_voltage(rdev, ret);
+
+ /*
+ * Map back into a voltage to verify we're still in bounds.
+ * We may have overlapping voltage ranges. Hence we don't
+ * exit but retry until we have checked all ranges.
+ */
+ if (voltage < min_uV || voltage > max_uV)
+ selector += (range->max_sel - range->min_sel + 1);
+ else
+ break;
+ }
+
+ if (i == rdev->desc->n_linear_ranges)
return -EINVAL;
return ret;
}
-EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
+EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
/**
* regulator_list_voltage_linear - List voltages with simple calculation
@@ -361,6 +554,46 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
/**
+ * regulator_list_voltage_pickable_linear_range - pickable range list voltages
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * list_voltage() operation, intended to be used by drivers utilizing pickable
+ * ranges helpers.
+ */
+int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ const struct regulator_linear_range *range;
+ int i;
+ unsigned int all_sels = 0;
+
+ if (!rdev->desc->n_linear_ranges) {
+ BUG_ON(!rdev->desc->n_linear_ranges);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+ unsigned int sels_in_range;
+
+ range = &rdev->desc->linear_ranges[i];
+
+ sels_in_range = range->max_sel - range->min_sel;
+
+ if (all_sels + sels_in_range >= selector) {
+ selector -= all_sels;
+ return range->min_uV + (range->uV_step * selector);
+ }
+
+ all_sels += (sels_in_range + 1);
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_pickable_linear_range);
+
+/**
* regulator_list_voltage_linear_range - List voltages for linear ranges
*
* @rdev: Regulator device
diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c
index 257c1943e753..9c2607e912cf 100644
--- a/drivers/regulator/isl9305.c
+++ b/drivers/regulator/isl9305.c
@@ -84,6 +84,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_DCD1_EN,
.supply_name = "VINDCD1",
.ops = &isl9305_ops,
+ .owner = THIS_MODULE,
},
[ISL9305_DCD2] = {
.name = "DCD2",
@@ -98,6 +99,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_DCD2_EN,
.supply_name = "VINDCD2",
.ops = &isl9305_ops,
+ .owner = THIS_MODULE,
},
[ISL9305_LDO1] = {
.name = "LDO1",
@@ -112,6 +114,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_LDO1_EN,
.supply_name = "VINLDO1",
.ops = &isl9305_ops,
+ .owner = THIS_MODULE,
},
[ISL9305_LDO2] = {
.name = "LDO2",
@@ -126,6 +129,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_LDO2_EN,
.supply_name = "VINLDO2",
.ops = &isl9305_ops,
+ .owner = THIS_MODULE,
},
};
diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c
index b615a413ca9f..bbedb08d257b 100644
--- a/drivers/regulator/lm363x-regulator.c
+++ b/drivers/regulator/lm363x-regulator.c
@@ -227,9 +227,11 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev,
*/
switch (id) {
case LM3632_LDO_POS:
- return devm_gpiod_get_index_optional(dev, "enable", 0, GPIOD_OUT_LOW);
+ return devm_gpiod_get_index_optional(dev, "enable", 0,
+ GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
case LM3632_LDO_NEG:
- return devm_gpiod_get_index_optional(dev, "enable", 1, GPIOD_OUT_LOW);
+ return devm_gpiod_get_index_optional(dev, "enable", 1,
+ GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
default:
return NULL;
}
diff --git a/drivers/regulator/lochnagar-regulator.c b/drivers/regulator/lochnagar-regulator.c
new file mode 100644
index 000000000000..2b5073b9ff86
--- /dev/null
+++ b/drivers/regulator/lochnagar-regulator.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Lochnagar regulator driver
+//
+// Copyright (c) 2017-2018 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+//
+// Author: Charles Keepax <ckeepax@opensource.cirrus.com>
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#include <linux/mfd/lochnagar.h>
+
+static const struct regulator_ops lochnagar_micvdd_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_linear_range lochnagar_micvdd_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0, 0xC, 50000),
+ REGULATOR_LINEAR_RANGE(1700000, 0xD, 0x1F, 100000),
+};
+
+static int lochnagar_micbias_enable(struct regulator_dev *rdev)
+{
+ struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
+ int ret;
+
+ mutex_lock(&lochnagar->analogue_config_lock);
+
+ ret = regulator_enable_regmap(rdev);
+ if (ret < 0)
+ goto err;
+
+ ret = lochnagar_update_config(lochnagar);
+
+err:
+ mutex_unlock(&lochnagar->analogue_config_lock);
+
+ return ret;
+}
+
+static int lochnagar_micbias_disable(struct regulator_dev *rdev)
+{
+ struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
+ int ret;
+
+ mutex_lock(&lochnagar->analogue_config_lock);
+
+ ret = regulator_disable_regmap(rdev);
+ if (ret < 0)
+ goto err;
+
+ ret = lochnagar_update_config(lochnagar);
+
+err:
+ mutex_unlock(&lochnagar->analogue_config_lock);
+
+ return ret;
+}
+
+static const struct regulator_ops lochnagar_micbias_ops = {
+ .enable = lochnagar_micbias_enable,
+ .disable = lochnagar_micbias_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_ops lochnagar_vddcore_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_linear_range lochnagar_vddcore_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x8, 0x41, 12500),
+};
+
+enum lochnagar_regulators {
+ LOCHNAGAR_MICVDD,
+ LOCHNAGAR_MIC1VDD,
+ LOCHNAGAR_MIC2VDD,
+ LOCHNAGAR_VDDCORE,
+};
+
+static int lochnagar_micbias_of_parse(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ struct lochnagar *lochnagar = config->driver_data;
+ int shift = (desc->id - LOCHNAGAR_MIC1VDD) *
+ LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
+ int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
+ unsigned int val;
+ int ret;
+
+ ret = of_property_read_u32(np, "cirrus,micbias-input", &val);
+ if (ret >= 0) {
+ mutex_lock(&lochnagar->analogue_config_lock);
+ ret = regmap_update_bits(lochnagar->regmap,
+ LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
+ mask, val << shift);
+ mutex_unlock(&lochnagar->analogue_config_lock);
+ if (ret < 0) {
+ dev_err(lochnagar->dev,
+ "Failed to update micbias source: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct regulator_desc lochnagar_regulators[] = {
+ [LOCHNAGAR_MICVDD] = {
+ .name = "MICVDD",
+ .supply_name = "SYSVDD",
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 32,
+ .ops = &lochnagar_micvdd_ops,
+
+ .id = LOCHNAGAR_MICVDD,
+ .of_match = of_match_ptr("MICVDD"),
+
+ .enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
+ .enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
+ .vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
+ .vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
+
+ .linear_ranges = lochnagar_micvdd_ranges,
+ .n_linear_ranges = ARRAY_SIZE(lochnagar_micvdd_ranges),
+
+ .enable_time = 3000,
+ .ramp_delay = 1000,
+
+ .owner = THIS_MODULE,
+ },
+ [LOCHNAGAR_MIC1VDD] = {
+ .name = "MIC1VDD",
+ .supply_name = "MICBIAS1",
+ .type = REGULATOR_VOLTAGE,
+ .ops = &lochnagar_micbias_ops,
+
+ .id = LOCHNAGAR_MIC1VDD,
+ .of_match = of_match_ptr("MIC1VDD"),
+ .of_parse_cb = lochnagar_micbias_of_parse,
+
+ .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
+ .enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
+
+ .owner = THIS_MODULE,
+ },
+ [LOCHNAGAR_MIC2VDD] = {
+ .name = "MIC2VDD",
+ .supply_name = "MICBIAS2",
+ .type = REGULATOR_VOLTAGE,
+ .ops = &lochnagar_micbias_ops,
+
+ .id = LOCHNAGAR_MIC2VDD,
+ .of_match = of_match_ptr("MIC2VDD"),
+ .of_parse_cb = lochnagar_micbias_of_parse,
+
+ .enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
+ .enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
+
+ .owner = THIS_MODULE,
+ },
+ [LOCHNAGAR_VDDCORE] = {
+ .name = "VDDCORE",
+ .supply_name = "SYSVDD",
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 57,
+ .ops = &lochnagar_vddcore_ops,
+
+ .id = LOCHNAGAR_VDDCORE,
+ .of_match = of_match_ptr("VDDCORE"),
+
+ .enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
+ .enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
+ .vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
+ .vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
+
+ .linear_ranges = lochnagar_vddcore_ranges,
+ .n_linear_ranges = ARRAY_SIZE(lochnagar_vddcore_ranges),
+
+ .enable_time = 3000,
+ .ramp_delay = 1000,
+
+ .owner = THIS_MODULE,
+ },
+};
+
+static int lochnagar_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
+ struct regulator_config config = { };
+ struct regulator_dev *rdev;
+ int ret, i;
+
+ config.dev = lochnagar->dev;
+ config.regmap = lochnagar->regmap;
+ config.driver_data = lochnagar;
+
+ for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) {
+ const struct regulator_desc *desc = &lochnagar_regulators[i];
+
+ rdev = devm_regulator_register(dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "Failed to register %s regulator: %d\n",
+ desc->name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver lochnagar_regulator_driver = {
+ .driver = {
+ .name = "lochnagar-regulator",
+ },
+
+ .probe = lochnagar_regulator_probe,
+};
+module_platform_driver(lochnagar_regulator_driver);
+
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
+MODULE_DESCRIPTION("Regulator driver for Cirrus Logic Lochnagar Board");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lochnagar-regulator");
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c
index f2347474a106..553b4790050f 100644
--- a/drivers/regulator/lp8788-ldo.c
+++ b/drivers/regulator/lp8788-ldo.c
@@ -503,9 +503,10 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
/* FIXME: check default mode for GPIO here: high or low? */
ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev,
- "enable",
- enable_id,
- GPIOD_OUT_HIGH);
+ "enable",
+ enable_id,
+ GPIOD_OUT_HIGH |
+ GPIOD_FLAGS_BIT_NONEXCLUSIVE);
if (IS_ERR(ldo->ena_gpiod))
return PTR_ERR(ldo->ena_gpiod);
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index f1e77ed5dfec..6c39fff73b8a 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -230,6 +230,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_LOW;
+ gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
gpiod = devm_gpiod_get_optional(&client->dev,
"max8952,en",
gflags);
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index 7cd493ec6315..e7a58b509032 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -758,6 +758,7 @@ static int max8973_probe(struct i2c_client *client,
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_LOW;
+ gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
gpiod = devm_gpiod_get_optional(&client->dev,
"maxim,enable",
gflags);
diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c
index ad0c806b0737..3bf5ddfaaea8 100644
--- a/drivers/regulator/max8997-regulator.c
+++ b/drivers/regulator/max8997-regulator.c
@@ -929,8 +929,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
break;
if (i == ARRAY_SIZE(regulators)) {
- dev_warn(&pdev->dev, "don't know how to configure regulator %s\n",
- reg_np->name);
+ dev_warn(&pdev->dev, "don't know how to configure regulator %pOFn\n",
+ reg_np);
continue;
}
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index da4fb9824757..65eb1e0350cf 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -203,7 +203,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
if (!found)
dev_warn(&pdev->dev,
- "Unknown regulator: %s\n", child->name);
+ "Unknown regulator: %pOFn\n", child);
}
of_node_put(parent);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 210fc20f7de7..c4223b3e0dff 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -95,8 +95,8 @@ static void of_get_regulation_constraints(struct device_node *np,
if (!ret)
constraints->settling_time_up = pval;
if (constraints->settling_time_up && constraints->settling_time) {
- pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
- np->name);
+ pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
+ np);
constraints->settling_time_up = 0;
}
@@ -105,8 +105,8 @@ static void of_get_regulation_constraints(struct device_node *np,
if (!ret)
constraints->settling_time_down = pval;
if (constraints->settling_time_down && constraints->settling_time) {
- pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
- np->name);
+ pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
+ np);
constraints->settling_time_down = 0;
}
@@ -127,12 +127,12 @@ static void of_get_regulation_constraints(struct device_node *np,
if (desc && desc->of_map_mode) {
mode = desc->of_map_mode(pval);
if (mode == REGULATOR_MODE_INVALID)
- pr_err("%s: invalid mode %u\n", np->name, pval);
+ pr_err("%pOFn: invalid mode %u\n", np, pval);
else
constraints->initial_mode = mode;
} else {
- pr_warn("%s: mapping for mode %d not defined\n",
- np->name, pval);
+ pr_warn("%pOFn: mapping for mode %d not defined\n",
+ np, pval);
}
}
@@ -144,14 +144,14 @@ static void of_get_regulation_constraints(struct device_node *np,
ret = of_property_read_u32_index(np,
"regulator-allowed-modes", i, &pval);
if (ret) {
- pr_err("%s: couldn't read allowed modes index %d, ret=%d\n",
- np->name, i, ret);
+ pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d\n",
+ np, i, ret);
break;
}
mode = desc->of_map_mode(pval);
if (mode == REGULATOR_MODE_INVALID)
- pr_err("%s: invalid regulator-allowed-modes element %u\n",
- np->name, pval);
+ pr_err("%pOFn: invalid regulator-allowed-modes element %u\n",
+ np, pval);
else
constraints->valid_modes_mask |= mode;
}
@@ -159,7 +159,7 @@ static void of_get_regulation_constraints(struct device_node *np,
constraints->valid_ops_mask
|= REGULATOR_CHANGE_MODE;
} else {
- pr_warn("%s: mode mapping not defined\n", np->name);
+ pr_warn("%pOFn: mode mapping not defined\n", np);
}
}
@@ -197,13 +197,13 @@ static void of_get_regulation_constraints(struct device_node *np,
if (desc && desc->of_map_mode) {
mode = desc->of_map_mode(pval);
if (mode == REGULATOR_MODE_INVALID)
- pr_err("%s: invalid mode %u\n",
- np->name, pval);
+ pr_err("%pOFn: invalid mode %u\n",
+ np, pval);
else
suspend_state->mode = mode;
} else {
- pr_warn("%s: mapping for mode %d not defined\n",
- np->name, pval);
+ pr_warn("%pOFn: mapping for mode %d not defined\n",
+ np, pval);
}
}
@@ -349,8 +349,8 @@ int of_regulator_match(struct device *dev, struct device_node *node,
match->desc);
if (!match->init_data) {
dev_err(dev,
- "failed to parse DT for regulator %s\n",
- child->name);
+ "failed to parse DT for regulator %pOFn\n",
+ child);
of_node_put(child);
return -EINVAL;
}
@@ -399,16 +399,16 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
init_data = of_get_regulator_init_data(dev, child, desc);
if (!init_data) {
dev_err(dev,
- "failed to parse DT for regulator %s\n",
- child->name);
+ "failed to parse DT for regulator %pOFn\n",
+ child);
break;
}
if (desc->of_parse_cb) {
if (desc->of_parse_cb(child, desc, config)) {
dev_err(dev,
- "driver callback failed to parse DT for regulator %s\n",
- child->name);
+ "driver callback failed to parse DT for regulator %pOFn\n",
+ child);
init_data = NULL;
break;
}
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 31c3a236120a..dd41a9bb3f5c 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -31,11 +31,17 @@
#define PFUZE100_COINVOL 0x1a
#define PFUZE100_SW1ABVOL 0x20
+#define PFUZE100_SW1ABMODE 0x23
#define PFUZE100_SW1CVOL 0x2e
+#define PFUZE100_SW1CMODE 0x31
#define PFUZE100_SW2VOL 0x35
+#define PFUZE100_SW2MODE 0x38
#define PFUZE100_SW3AVOL 0x3c
+#define PFUZE100_SW3AMODE 0x3f
#define PFUZE100_SW3BVOL 0x43
+#define PFUZE100_SW3BMODE 0x46
#define PFUZE100_SW4VOL 0x4a
+#define PFUZE100_SW4MODE 0x4d
#define PFUZE100_SWBSTCON1 0x66
#define PFUZE100_VREFDDRCON 0x6a
#define PFUZE100_VSNVSVOL 0x6b
@@ -46,6 +52,13 @@
#define PFUZE100_VGEN5VOL 0x70
#define PFUZE100_VGEN6VOL 0x71
+#define PFUZE100_SWxMODE_MASK 0xf
+#define PFUZE100_SWxMODE_APS_APS 0x8
+#define PFUZE100_SWxMODE_APS_OFF 0x4
+
+#define PFUZE100_VGENxLPWR BIT(6)
+#define PFUZE100_VGENxSTBY BIT(5)
+
enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, };
struct pfuze_regulator {
@@ -559,6 +572,69 @@ static inline struct device_node *match_of_node(int index)
}
#endif
+static struct pfuze_chip *syspm_pfuze_chip;
+
+static void pfuze_power_off_prepare(void)
+{
+ dev_info(syspm_pfuze_chip->dev, "Configure standby mode for power off");
+
+ /* Switch from default mode: APS/APS to APS/Off */
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1ABMODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1CMODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW2MODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3AMODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3BMODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW4MODE,
+ PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN1VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN2VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN3VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN4VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN5VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+ regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL,
+ PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+ PFUZE100_VGENxSTBY);
+}
+
+static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
+{
+ if (pfuze_chip->chip_id != PFUZE100) {
+ dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n");
+ return -ENODEV;
+ }
+
+ if (pm_power_off_prepare) {
+ dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already registered.\n");
+ return -EBUSY;
+ }
+
+ if (syspm_pfuze_chip) {
+ dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n");
+ return -EBUSY;
+ }
+
+ syspm_pfuze_chip = pfuze_chip;
+ pm_power_off_prepare = pfuze_power_off_prepare;
+
+ return 0;
+}
+
static int pfuze_identify(struct pfuze_chip *pfuze_chip)
{
unsigned int value;
@@ -753,6 +829,20 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
}
}
+ if (of_property_read_bool(client->dev.of_node,
+ "fsl,pmic-stby-poweroff"))
+ return pfuze_power_off_prepare_init(pfuze_chip);
+
+ return 0;
+}
+
+static int pfuze100_regulator_remove(struct i2c_client *client)
+{
+ if (syspm_pfuze_chip) {
+ syspm_pfuze_chip = NULL;
+ pm_power_off_prepare = NULL;
+ }
+
return 0;
}
@@ -763,6 +853,7 @@ static struct i2c_driver pfuze_driver = {
.of_match_table = pfuze_dt_ids,
},
.probe = pfuze100_regulator_probe,
+ .remove = pfuze100_regulator_remove,
};
module_i2c_driver(pfuze_driver);
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
index 9f27daebd8c8..39ccf53fdeb3 100644
--- a/drivers/regulator/qcom-rpmh-regulator.c
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -414,7 +414,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
break;
if (!rpmh_data->name) {
- dev_err(dev, "Unknown regulator %s\n", node->name);
+ dev_err(dev, "Unknown regulator %pOFn\n", node);
return -EINVAL;
}
@@ -423,8 +423,8 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
vreg->addr = cmd_db_read_addr(rpmh_resource_name);
if (!vreg->addr) {
- dev_err(dev, "%s: could not find RPMh address for resource %s\n",
- node->name, rpmh_resource_name);
+ dev_err(dev, "%pOFn: could not find RPMh address for resource %s\n",
+ node, rpmh_resource_name);
return -ENODEV;
}
@@ -469,13 +469,13 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
rdev = devm_regulator_register(dev, &vreg->rdesc, &reg_config);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
- dev_err(dev, "%s: devm_regulator_register() failed, ret=%d\n",
- node->name, ret);
+ dev_err(dev, "%pOFn: devm_regulator_register() failed, ret=%d\n",
+ node, ret);
return ret;
}
- dev_dbg(dev, "%s regulator registered for RPMh resource %s @ 0x%05X\n",
- node->name, rpmh_resource_name, vreg->addr);
+ dev_dbg(dev, "%pOFn regulator registered for RPMh resource %s @ 0x%05X\n",
+ node, rpmh_resource_name, vreg->addr);
return 0;
}
@@ -504,6 +504,7 @@ static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
break;
default:
mode = REGULATOR_MODE_INVALID;
+ break;
}
return mode;
@@ -537,6 +538,7 @@ rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode)
break;
default:
mode = REGULATOR_MODE_INVALID;
+ break;
}
return mode;
@@ -566,6 +568,7 @@ static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode)
break;
default:
mode = REGULATOR_MODE_INVALID;
+ break;
}
return mode;
diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c
index fe2fb36803e0..f5bca77d67c1 100644
--- a/drivers/regulator/qcom_smd-regulator.c
+++ b/drivers/regulator/qcom_smd-regulator.c
@@ -420,6 +420,60 @@ static const struct regulator_desc pmi8998_bob = {
.ops = &rpm_bob_ops,
};
+static const struct regulator_desc pms405_hfsmps3 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 216,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_nldo300 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 128,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_nldo1200 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 128,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_pldo50 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 129,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_pldo150 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 129,
+ .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pms405_pldo600 = {
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1256000, 0, 98, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 99,
+ .ops = &rpm_smps_ldo_ops,
+};
+
struct rpm_regulator_data {
const char *name;
u32 type;
@@ -661,6 +715,28 @@ static const struct rpm_regulator_data rpm_pmi8998_regulators[] = {
{}
};
+static const struct rpm_regulator_data rpm_pms405_regulators[] = {
+ { "s1", QCOM_SMD_RPM_SMPA, 1, &pms405_hfsmps3, "vdd_s1" },
+ { "s2", QCOM_SMD_RPM_SMPA, 2, &pms405_hfsmps3, "vdd_s2" },
+ { "s3", QCOM_SMD_RPM_SMPA, 3, &pms405_hfsmps3, "vdd_s3" },
+ { "s4", QCOM_SMD_RPM_SMPA, 4, &pms405_hfsmps3, "vdd_s4" },
+ { "s5", QCOM_SMD_RPM_SMPA, 5, &pms405_hfsmps3, "vdd_s5" },
+ { "l1", QCOM_SMD_RPM_LDOA, 1, &pms405_nldo1200, "vdd_l1_l2" },
+ { "l2", QCOM_SMD_RPM_LDOA, 2, &pms405_nldo1200, "vdd_l1_l2" },
+ { "l3", QCOM_SMD_RPM_LDOA, 3, &pms405_nldo1200, "vdd_l3_l8" },
+ { "l4", QCOM_SMD_RPM_LDOA, 4, &pms405_nldo300, "vdd_l4" },
+ { "l5", QCOM_SMD_RPM_LDOA, 5, &pms405_pldo600, "vdd_l5_l6" },
+ { "l6", QCOM_SMD_RPM_LDOA, 6, &pms405_pldo600, "vdd_l5_l6" },
+ { "l7", QCOM_SMD_RPM_LDOA, 7, &pms405_pldo150, "vdd_l7" },
+ { "l8", QCOM_SMD_RPM_LDOA, 8, &pms405_nldo1200, "vdd_l3_l8" },
+ { "l9", QCOM_SMD_RPM_LDOA, 9, &pms405_nldo1200, "vdd_l9" },
+ { "l10", QCOM_SMD_RPM_LDOA, 10, &pms405_pldo50, "vdd_l10_l11_l12_l13" },
+ { "l11", QCOM_SMD_RPM_LDOA, 11, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
+ { "l12", QCOM_SMD_RPM_LDOA, 12, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
+ { "l13", QCOM_SMD_RPM_LDOA, 13, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
+ {}
+};
+
static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
{ .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
@@ -669,6 +745,7 @@ static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8998-regulators", .data = &rpm_pm8998_regulators },
{ .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
{ .compatible = "qcom,rpm-pmi8998-regulators", .data = &rpm_pmi8998_regulators },
+ { .compatible = "qcom,rpm-pms405-regulators", .data = &rpm_pms405_regulators },
{}
};
MODULE_DEVICE_TABLE(of, rpm_of_match);
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 667d16dc83ce..219b9afda0cb 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -447,15 +447,15 @@ static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
}
if (mode != S5M8767_ENCTRL_USE_GPIO) {
dev_warn(s5m8767->dev,
- "ext-control for %s: mismatched op_mode (%x), ignoring\n",
- rdata->reg_node->name, mode);
+ "ext-control for %pOFn: mismatched op_mode (%x), ignoring\n",
+ rdata->reg_node, mode);
return;
}
if (!rdata->ext_control_gpiod) {
dev_warn(s5m8767->dev,
- "ext-control for %s: GPIO not valid, ignoring\n",
- rdata->reg_node->name);
+ "ext-control for %pOFn: GPIO not valid, ignoring\n",
+ rdata->reg_node);
return;
}
@@ -566,17 +566,18 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
if (i == ARRAY_SIZE(regulators)) {
dev_warn(iodev->dev,
- "don't know how to configure regulator %s\n",
- reg_np->name);
+ "don't know how to configure regulator %pOFn\n",
+ reg_np);
continue;
}
- rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(&pdev->dev,
- reg_np,
- "s5m8767,pmic-ext-control-gpios",
- 0,
- GPIOD_OUT_HIGH,
- "s5m8767");
+ rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(
+ &pdev->dev,
+ reg_np,
+ "s5m8767,pmic-ext-control-gpios",
+ 0,
+ GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+ "s5m8767");
if (IS_ERR(rdata->ext_control_gpiod))
return PTR_ERR(rdata->ext_control_gpiod);
diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c
new file mode 100644
index 000000000000..e15634edb8ce
--- /dev/null
+++ b/drivers/regulator/stpmic1_regulator.c
@@ -0,0 +1,674 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2018
+// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+
+#include <linux/interrupt.h>
+#include <linux/mfd/stpmic1.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+/**
+ * stpmic1 regulator description
+ * @desc: regulator framework description
+ * @mask_reset_reg: mask reset register address
+ * @mask_reset_mask: mask rank and mask reset register mask
+ * @icc_reg: icc register address
+ * @icc_mask: icc register mask
+ */
+struct stpmic1_regulator_cfg {
+ struct regulator_desc desc;
+ u8 mask_reset_reg;
+ u8 mask_reset_mask;
+ u8 icc_reg;
+ u8 icc_mask;
+};
+
+/**
+ * stpmic1 regulator data: this structure is used as driver data
+ * @regul_id: regulator id
+ * @reg_node: DT node of regulator (unused on non-DT platforms)
+ * @cfg: stpmic specific regulator description
+ * @mask_reset: mask_reset bit value
+ * @irq_curlim: current limit interrupt number
+ * @regmap: point to parent regmap structure
+ */
+struct stpmic1_regulator {
+ unsigned int regul_id;
+ struct device_node *reg_node;
+ struct stpmic1_regulator_cfg *cfg;
+ u8 mask_reset;
+ int irq_curlim;
+ struct regmap *regmap;
+};
+
+static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode);
+static unsigned int stpmic1_get_mode(struct regulator_dev *rdev);
+static int stpmic1_set_icc(struct regulator_dev *rdev);
+static int stpmic1_regulator_parse_dt(void *driver_data);
+static unsigned int stpmic1_map_mode(unsigned int mode);
+
+enum {
+ STPMIC1_BUCK1 = 0,
+ STPMIC1_BUCK2 = 1,
+ STPMIC1_BUCK3 = 2,
+ STPMIC1_BUCK4 = 3,
+ STPMIC1_LDO1 = 4,
+ STPMIC1_LDO2 = 5,
+ STPMIC1_LDO3 = 6,
+ STPMIC1_LDO4 = 7,
+ STPMIC1_LDO5 = 8,
+ STPMIC1_LDO6 = 9,
+ STPMIC1_VREF_DDR = 10,
+ STPMIC1_BOOST = 11,
+ STPMIC1_VBUS_OTG = 12,
+ STPMIC1_SW_OUT = 13,
+};
+
+/* Enable time worst case is 5000mV/(2250uV/uS) */
+#define PMIC_ENABLE_TIME_US 2200
+
+#define STPMIC1_BUCK_MODE_NORMAL 0
+#define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK
+
+struct regulator_linear_range buck1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0, 30, 25000),
+ REGULATOR_LINEAR_RANGE(1350000, 31, 63, 0),
+};
+
+struct regulator_linear_range buck2_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0, 17, 0),
+ REGULATOR_LINEAR_RANGE(1050000, 18, 19, 0),
+ REGULATOR_LINEAR_RANGE(1100000, 20, 21, 0),
+ REGULATOR_LINEAR_RANGE(1150000, 22, 23, 0),
+ REGULATOR_LINEAR_RANGE(1200000, 24, 25, 0),
+ REGULATOR_LINEAR_RANGE(1250000, 26, 27, 0),
+ REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0),
+ REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0),
+ REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0),
+ REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 36, 63, 0),
+};
+
+struct regulator_linear_range buck3_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0, 19, 0),
+ REGULATOR_LINEAR_RANGE(1100000, 20, 23, 0),
+ REGULATOR_LINEAR_RANGE(1200000, 24, 27, 0),
+ REGULATOR_LINEAR_RANGE(1300000, 28, 31, 0),
+ REGULATOR_LINEAR_RANGE(1400000, 32, 35, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 36, 55, 100000),
+ REGULATOR_LINEAR_RANGE(3400000, 56, 63, 0),
+
+};
+
+struct regulator_linear_range buck4_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0, 27, 25000),
+ REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0),
+ REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0),
+ REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0),
+ REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0),
+ REGULATOR_LINEAR_RANGE(1500000, 36, 60, 100000),
+ REGULATOR_LINEAR_RANGE(3900000, 61, 63, 0),
+
+};
+
+struct regulator_linear_range ldo1_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+ REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
+ REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0),
+
+};
+
+struct regulator_linear_range ldo2_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+ REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
+ REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0),
+
+};
+
+struct regulator_linear_range ldo3_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+ REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
+ REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0),
+ /* with index 31 LDO3 is in DDR mode */
+ REGULATOR_LINEAR_RANGE(500000, 31, 31, 0),
+};
+
+struct regulator_linear_range ldo5_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
+ REGULATOR_LINEAR_RANGE(1700000, 8, 30, 100000),
+ REGULATOR_LINEAR_RANGE(3900000, 31, 31, 0),
+};
+
+struct regulator_linear_range ldo6_ranges[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0, 24, 100000),
+ REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0),
+};
+
+static struct regulator_ops stpmic1_ldo_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_pull_down = regulator_set_pull_down_regmap,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_ldo3_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_iterate,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_pull_down = regulator_set_pull_down_regmap,
+ .get_bypass = regulator_get_bypass_regmap,
+ .set_bypass = regulator_set_bypass_regmap,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_pull_down = regulator_set_pull_down_regmap,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_buck_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_pull_down = regulator_set_pull_down_regmap,
+ .set_mode = stpmic1_set_mode,
+ .get_mode = stpmic1_get_mode,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+static struct regulator_ops stpmic1_vref_ddr_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_pull_down = regulator_set_pull_down_regmap,
+};
+
+static struct regulator_ops stpmic1_switch_regul_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .set_over_current_protection = stpmic1_set_icc,
+};
+
+#define REG_LDO(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 32, \
+ .ops = &stpmic1_ldo_ops, \
+ .linear_ranges = base ## _ranges, \
+ .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = ids##_ACTIVE_CR, \
+ .vsel_mask = LDO_VOLTAGE_MASK, \
+ .enable_reg = ids##_ACTIVE_CR, \
+ .enable_mask = LDO_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_LDO3(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 32, \
+ .ops = &stpmic1_ldo3_ops, \
+ .linear_ranges = ldo3_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(ldo3_ranges), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = LDO3_ACTIVE_CR, \
+ .vsel_mask = LDO_VOLTAGE_MASK, \
+ .enable_reg = LDO3_ACTIVE_CR, \
+ .enable_mask = LDO_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .bypass_reg = LDO3_ACTIVE_CR, \
+ .bypass_mask = LDO_BYPASS_MASK, \
+ .bypass_val_on = LDO_BYPASS_MASK, \
+ .bypass_val_off = 0, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_LDO4(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 1, \
+ .ops = &stpmic1_ldo4_fixed_regul_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 3300000, \
+ .fixed_uV = 3300000, \
+ .enable_reg = LDO4_ACTIVE_CR, \
+ .enable_mask = LDO_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_BUCK(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .ops = &stpmic1_buck_ops, \
+ .n_voltages = 64, \
+ .linear_ranges = base ## _ranges, \
+ .n_linear_ranges = ARRAY_SIZE(base ## _ranges), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = ids##_ACTIVE_CR, \
+ .vsel_mask = BUCK_VOLTAGE_MASK, \
+ .enable_reg = ids##_ACTIVE_CR, \
+ .enable_mask = BUCK_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .of_map_mode = stpmic1_map_mode, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_VREF_DDR(ids, base) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 1, \
+ .ops = &stpmic1_vref_ddr_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 500000, \
+ .fixed_uV = 500000, \
+ .enable_reg = VREF_DDR_ACTIVE_CR, \
+ .enable_mask = BUCK_ENABLE_MASK, \
+ .enable_val = 1, \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .pull_down_reg = ids##_PULL_DOWN_REG, \
+ .pull_down_mask = ids##_PULL_DOWN_MASK, \
+ .supply_name = #base, \
+}
+
+#define REG_SWITCH(ids, base, reg, mask, val) { \
+ .name = #ids, \
+ .id = STPMIC1_##ids, \
+ .n_voltages = 1, \
+ .ops = &stpmic1_switch_regul_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = 0, \
+ .fixed_uV = 5000000, \
+ .enable_reg = (reg), \
+ .enable_mask = (mask), \
+ .enable_val = (val), \
+ .disable_val = 0, \
+ .enable_time = PMIC_ENABLE_TIME_US, \
+ .supply_name = #base, \
+}
+
+struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = {
+ [STPMIC1_BUCK1] = {
+ .desc = REG_BUCK(BUCK1, buck1),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(0),
+ .mask_reset_reg = BUCKS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(0),
+ },
+ [STPMIC1_BUCK2] = {
+ .desc = REG_BUCK(BUCK2, buck2),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(1),
+ .mask_reset_reg = BUCKS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(1),
+ },
+ [STPMIC1_BUCK3] = {
+ .desc = REG_BUCK(BUCK3, buck3),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(2),
+ .mask_reset_reg = BUCKS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(2),
+ },
+ [STPMIC1_BUCK4] = {
+ .desc = REG_BUCK(BUCK4, buck4),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(3),
+ .mask_reset_reg = BUCKS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(3),
+ },
+ [STPMIC1_LDO1] = {
+ .desc = REG_LDO(LDO1, ldo1),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(0),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(0),
+ },
+ [STPMIC1_LDO2] = {
+ .desc = REG_LDO(LDO2, ldo2),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(1),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(1),
+ },
+ [STPMIC1_LDO3] = {
+ .desc = REG_LDO3(LDO3, ldo3),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(2),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(2),
+ },
+ [STPMIC1_LDO4] = {
+ .desc = REG_LDO4(LDO4, ldo4),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(3),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(3),
+ },
+ [STPMIC1_LDO5] = {
+ .desc = REG_LDO(LDO5, ldo5),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(4),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(4),
+ },
+ [STPMIC1_LDO6] = {
+ .desc = REG_LDO(LDO6, ldo6),
+ .icc_reg = LDOS_ICCTO_CR,
+ .icc_mask = BIT(5),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(5),
+ },
+ [STPMIC1_VREF_DDR] = {
+ .desc = REG_VREF_DDR(VREF_DDR, vref_ddr),
+ .mask_reset_reg = LDOS_MASK_RESET_CR,
+ .mask_reset_mask = BIT(6),
+ },
+ [STPMIC1_BOOST] = {
+ .desc = REG_SWITCH(BOOST, boost, BST_SW_CR,
+ BOOST_ENABLED,
+ BOOST_ENABLED),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(6),
+ },
+ [STPMIC1_VBUS_OTG] = {
+ .desc = REG_SWITCH(VBUS_OTG, pwr_sw1, BST_SW_CR,
+ USBSW_OTG_SWITCH_ENABLED,
+ USBSW_OTG_SWITCH_ENABLED),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(4),
+ },
+ [STPMIC1_SW_OUT] = {
+ .desc = REG_SWITCH(SW_OUT, pwr_sw2, BST_SW_CR,
+ SWIN_SWOUT_ENABLED,
+ SWIN_SWOUT_ENABLED),
+ .icc_reg = BUCKS_ICCTO_CR,
+ .icc_mask = BIT(5),
+ },
+};
+
+static unsigned int stpmic1_map_mode(unsigned int mode)
+{
+ switch (mode) {
+ case STPMIC1_BUCK_MODE_NORMAL:
+ return REGULATOR_MODE_NORMAL;
+ case STPMIC1_BUCK_MODE_LP:
+ return REGULATOR_MODE_STANDBY;
+ default:
+ return REGULATOR_MODE_INVALID;
+ }
+}
+
+static unsigned int stpmic1_get_mode(struct regulator_dev *rdev)
+{
+ int value;
+
+ regmap_read(rdev->regmap, rdev->desc->enable_reg, &value);
+
+ if (value & STPMIC1_BUCK_MODE_LP)
+ return REGULATOR_MODE_STANDBY;
+
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ int value;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ value = STPMIC1_BUCK_MODE_NORMAL;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ value = STPMIC1_BUCK_MODE_LP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ STPMIC1_BUCK_MODE_LP, value);
+}
+
+static int stpmic1_set_icc(struct regulator_dev *rdev)
+{
+ struct stpmic1_regulator *regul = rdev_get_drvdata(rdev);
+
+ /* enable switch off in case of over current */
+ return regmap_update_bits(regul->regmap, regul->cfg->icc_reg,
+ regul->cfg->icc_mask, regul->cfg->icc_mask);
+}
+
+static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data)
+{
+ struct regulator_dev *rdev = (struct regulator_dev *)data;
+
+ mutex_lock(&rdev->mutex);
+
+ /* Send an overcurrent notification */
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_OVER_CURRENT,
+ NULL);
+
+ mutex_unlock(&rdev->mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int stpmic1_regulator_init(struct platform_device *pdev,
+ struct regulator_dev *rdev)
+{
+ struct stpmic1_regulator *regul = rdev_get_drvdata(rdev);
+ int ret = 0;
+
+ /* set mask reset */
+ if (regul->mask_reset && regul->cfg->mask_reset_reg != 0) {
+ ret = regmap_update_bits(regul->regmap,
+ regul->cfg->mask_reset_reg,
+ regul->cfg->mask_reset_mask,
+ regul->cfg->mask_reset_mask);
+ if (ret) {
+ dev_err(&pdev->dev, "set mask reset failed\n");
+ return ret;
+ }
+ }
+
+ /* setup an irq handler for over-current detection */
+ if (regul->irq_curlim > 0) {
+ ret = devm_request_threaded_irq(&pdev->dev,
+ regul->irq_curlim, NULL,
+ stpmic1_curlim_irq_handler,
+ IRQF_ONESHOT | IRQF_SHARED,
+ pdev->name, rdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Request IRQ failed\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+#define MATCH(_name, _id) \
+ [STPMIC1_##_id] = { \
+ .name = #_name, \
+ .desc = &stpmic1_regulator_cfgs[STPMIC1_##_id].desc, \
+ }
+
+static struct of_regulator_match stpmic1_regulators_matches[] = {
+ MATCH(buck1, BUCK1),
+ MATCH(buck2, BUCK2),
+ MATCH(buck3, BUCK3),
+ MATCH(buck4, BUCK4),
+ MATCH(ldo1, LDO1),
+ MATCH(ldo2, LDO2),
+ MATCH(ldo3, LDO3),
+ MATCH(ldo4, LDO4),
+ MATCH(ldo5, LDO5),
+ MATCH(ldo6, LDO6),
+ MATCH(vref_ddr, VREF_DDR),
+ MATCH(boost, BOOST),
+ MATCH(pwr_sw1, VBUS_OTG),
+ MATCH(pwr_sw2, SW_OUT),
+};
+
+static int stpmic1_regulator_parse_dt(void *driver_data)
+{
+ struct stpmic1_regulator *regul =
+ (struct stpmic1_regulator *)driver_data;
+
+ if (!regul)
+ return -EINVAL;
+
+ if (of_get_property(regul->reg_node, "st,mask-reset", NULL))
+ regul->mask_reset = 1;
+
+ regul->irq_curlim = of_irq_get(regul->reg_node, 0);
+
+ return 0;
+}
+
+static struct
+regulator_dev *stpmic1_regulator_register(struct platform_device *pdev, int id,
+ struct regulator_init_data *init_data,
+ struct stpmic1_regulator *regul)
+{
+ struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_dev *rdev;
+ struct regulator_config config = {};
+
+ config.dev = &pdev->dev;
+ config.init_data = init_data;
+ config.of_node = stpmic1_regulators_matches[id].of_node;
+ config.regmap = pmic_dev->regmap;
+ config.driver_data = regul;
+
+ regul->regul_id = id;
+ regul->reg_node = config.of_node;
+ regul->cfg = &stpmic1_regulator_cfgs[id];
+ regul->regmap = pmic_dev->regmap;
+
+ rdev = devm_regulator_register(&pdev->dev, &regul->cfg->desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register %s regulator\n",
+ regul->cfg->desc.name);
+ }
+
+ return rdev;
+}
+
+static int stpmic1_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev;
+ struct stpmic1_regulator *regul;
+ struct regulator_init_data *init_data;
+ struct device_node *np;
+ int i, ret;
+
+ np = pdev->dev.of_node;
+
+ ret = of_regulator_match(&pdev->dev, np,
+ stpmic1_regulators_matches,
+ ARRAY_SIZE(stpmic1_regulators_matches));
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Error in PMIC regulator device tree node");
+ return ret;
+ }
+
+ regul = devm_kzalloc(&pdev->dev, ARRAY_SIZE(stpmic1_regulator_cfgs) *
+ sizeof(struct stpmic1_regulator),
+ GFP_KERNEL);
+ if (!regul)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) {
+ /* Parse DT & find regulators to register */
+ init_data = stpmic1_regulators_matches[i].init_data;
+ if (init_data)
+ init_data->regulator_init = &stpmic1_regulator_parse_dt;
+
+ rdev = stpmic1_regulator_register(pdev, i, init_data, regul);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ ret = stpmic1_regulator_init(pdev, rdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to initialize regulator %d\n", ret);
+ return ret;
+ }
+
+ regul++;
+ }
+
+ dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n");
+
+ return 0;
+}
+
+static const struct of_device_id of_pmic_regulator_match[] = {
+ { .compatible = "st,stpmic1-regulators" },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, of_pmic_regulator_match);
+
+static struct platform_driver stpmic1_regulator_driver = {
+ .driver = {
+ .name = "stpmic1-regulator",
+ .of_match_table = of_match_ptr(of_pmic_regulator_match),
+ },
+ .probe = stpmic1_regulator_probe,
+};
+
+module_platform_driver(stpmic1_regulator_driver);
+
+MODULE_DESCRIPTION("STPMIC1 PMIC voltage regulator driver");
+MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index edaef9e4dc74..db714d5edafc 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -374,6 +374,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_LOW;
+ gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
rpdata->gpiod = devm_gpiod_get_from_of_node(&pdev->dev,
tps65090_matches[idx].of_node,