diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-23 01:54:44 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-23 01:54:44 +0100 |
commit | ca9eb48fe01fa7fa60ff9f2196b1bd0d84dc81af (patch) | |
tree | 587767dc1d9a4211a54430f0b9058397cd749617 /drivers/regulator | |
parent | b537149a2fb45ef9936b7a55aa801fbab8ea2a8a (diff) | |
parent | f35b1e53a66ab06e6d04cdff96f686e8b88959ef (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')
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(®ulator_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(®ulator_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(®ulator_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(®ulator_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, ®_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, ®ul->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, |