diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-06-28 11:06:10 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-06-28 11:06:10 -0700 |
commit | c10383b3fb10286dfeac7754ca964ec992f6fe78 (patch) | |
tree | 9e01e12562d948848891eeb2c5bf0c775aac4765 /drivers | |
parent | 52f8cf8b0b540a8e4ebba52fe5ee3f57c2682f92 (diff) | |
parent | 7fb593cbd88cf4df01c096d4dc320f027dfa2560 (diff) |
Merge tag 'regulator-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown:
"The main core change this release is generic support for handling of
hardware errors from Matti Vaittinen, including some small updates to
the reboot and thermal code so we can share support for powering off
the system if things are going wrong enough.
Otherwise this release we've mainly seen the addition of new drivers,
including MT6359 which has pulled in some small changes from the MFD
tree for build dependencies.
- Support for controlling the trigger points for hardware error
detection, and shared handlers for this.
- Support for Maxim MAX8993, Mediatek MT6359 and MT6359P, Qualcomm
PM8226 and SA8115P-ADP, and Sylergy TCS4526"
* tag 'regulator-v5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (91 commits)
regulator: bd9576: Fix uninitializes variable may_have_irqs
regulator: max8893: Select REGMAP_I2C to fix build error
regulator: da9052: Ensure enough delay time for .set_voltage_time_sel
regulator: mt6358: Fix vdram2 .vsel_mask
regulator: hi6421v600: Fix setting wrong driver_data
MAINTAINERS: Add reviewer for regulator irq_helpers
regulator: bd9576: Fix the driver name in id table
regulator: bd9576: Support error reporting
regulator: bd9576 add FET ON-resistance for OCW
regulator: add property parsing and callbacks to set protection limits
regulator: IRQ based event/error notification helpers
regulator: move rdev_print helpers to internal.h
regulator: add warning flags
thermal: Use generic HW-protection shutdown API
reboot: Add hardware protection power-off
regulator: Add protection limit properties
regulator: hi6421v600: Fix setting idle mode
regulator: Add MAX8893 bindings
regulator: max8893: add regulator driver
regulator: hi6421: Use correct variable type for regmap api val argument
...
Diffstat (limited to 'drivers')
47 files changed, 4245 insertions, 1209 deletions
diff --git a/drivers/mfd/mt6358-irq.c b/drivers/mfd/mt6358-irq.c index db734f2831ff..83f3ffbdbb4c 100644 --- a/drivers/mfd/mt6358-irq.c +++ b/drivers/mfd/mt6358-irq.c @@ -5,6 +5,8 @@ #include <linux/interrupt.h> #include <linux/mfd/mt6358/core.h> #include <linux/mfd/mt6358/registers.h> +#include <linux/mfd/mt6359/core.h> +#include <linux/mfd/mt6359/registers.h> #include <linux/mfd/mt6397/core.h> #include <linux/module.h> #include <linux/of.h> @@ -13,7 +15,9 @@ #include <linux/platform_device.h> #include <linux/regmap.h> -static struct irq_top_t mt6358_ints[] = { +#define MTK_PMIC_REG_WIDTH 16 + +static const struct irq_top_t mt6358_ints[] = { MT6358_TOP_GEN(BUCK), MT6358_TOP_GEN(LDO), MT6358_TOP_GEN(PSC), @@ -24,6 +28,31 @@ static struct irq_top_t mt6358_ints[] = { MT6358_TOP_GEN(MISC), }; +static const struct irq_top_t mt6359_ints[] = { + MT6359_TOP_GEN(BUCK), + MT6359_TOP_GEN(LDO), + MT6359_TOP_GEN(PSC), + MT6359_TOP_GEN(SCK), + MT6359_TOP_GEN(BM), + MT6359_TOP_GEN(HK), + MT6359_TOP_GEN(AUD), + MT6359_TOP_GEN(MISC), +}; + +static struct pmic_irq_data mt6358_irqd = { + .num_top = ARRAY_SIZE(mt6358_ints), + .num_pmic_irqs = MT6358_IRQ_NR, + .top_int_status_reg = MT6358_TOP_INT_STATUS0, + .pmic_ints = mt6358_ints, +}; + +static struct pmic_irq_data mt6359_irqd = { + .num_top = ARRAY_SIZE(mt6359_ints), + .num_pmic_irqs = MT6359_IRQ_NR, + .top_int_status_reg = MT6359_TOP_INT_STATUS0, + .pmic_ints = mt6359_ints, +}; + static void pmic_irq_enable(struct irq_data *data) { unsigned int hwirq = irqd_to_hwirq(data); @@ -62,15 +91,15 @@ static void pmic_irq_sync_unlock(struct irq_data *data) /* Find out the IRQ group */ top_gp = 0; while ((top_gp + 1) < irqd->num_top && - i >= mt6358_ints[top_gp + 1].hwirq_base) + i >= irqd->pmic_ints[top_gp + 1].hwirq_base) top_gp++; /* Find the IRQ registers */ - gp_offset = i - mt6358_ints[top_gp].hwirq_base; - int_regs = gp_offset / MT6358_REG_WIDTH; - shift = gp_offset % MT6358_REG_WIDTH; - en_reg = mt6358_ints[top_gp].en_reg + - (mt6358_ints[top_gp].en_reg_shift * int_regs); + gp_offset = i - irqd->pmic_ints[top_gp].hwirq_base; + int_regs = gp_offset / MTK_PMIC_REG_WIDTH; + shift = gp_offset % MTK_PMIC_REG_WIDTH; + en_reg = irqd->pmic_ints[top_gp].en_reg + + (irqd->pmic_ints[top_gp].en_reg_shift * int_regs); regmap_update_bits(chip->regmap, en_reg, BIT(shift), irqd->enable_hwirq[i] << shift); @@ -95,10 +124,11 @@ static void mt6358_irq_sp_handler(struct mt6397_chip *chip, unsigned int irq_status, sta_reg, status; unsigned int hwirq, virq; int i, j, ret; + struct pmic_irq_data *irqd = chip->irq_data; - for (i = 0; i < mt6358_ints[top_gp].num_int_regs; i++) { - sta_reg = mt6358_ints[top_gp].sta_reg + - mt6358_ints[top_gp].sta_reg_shift * i; + for (i = 0; i < irqd->pmic_ints[top_gp].num_int_regs; i++) { + sta_reg = irqd->pmic_ints[top_gp].sta_reg + + irqd->pmic_ints[top_gp].sta_reg_shift * i; ret = regmap_read(chip->regmap, sta_reg, &irq_status); if (ret) { @@ -114,8 +144,8 @@ static void mt6358_irq_sp_handler(struct mt6397_chip *chip, do { j = __ffs(status); - hwirq = mt6358_ints[top_gp].hwirq_base + - MT6358_REG_WIDTH * i + j; + hwirq = irqd->pmic_ints[top_gp].hwirq_base + + MTK_PMIC_REG_WIDTH * i + j; virq = irq_find_mapping(chip->irq_domain, hwirq); if (virq) @@ -131,12 +161,12 @@ static void mt6358_irq_sp_handler(struct mt6397_chip *chip, static irqreturn_t mt6358_irq_handler(int irq, void *data) { struct mt6397_chip *chip = data; - struct pmic_irq_data *mt6358_irq_data = chip->irq_data; + struct pmic_irq_data *irqd = chip->irq_data; unsigned int bit, i, top_irq_status = 0; int ret; ret = regmap_read(chip->regmap, - mt6358_irq_data->top_int_status_reg, + irqd->top_int_status_reg, &top_irq_status); if (ret) { dev_err(chip->dev, @@ -144,8 +174,8 @@ static irqreturn_t mt6358_irq_handler(int irq, void *data) return IRQ_NONE; } - for (i = 0; i < mt6358_irq_data->num_top; i++) { - bit = BIT(mt6358_ints[i].top_offset); + for (i = 0; i < irqd->num_top; i++) { + bit = BIT(irqd->pmic_ints[i].top_offset); if (top_irq_status & bit) { mt6358_irq_sp_handler(chip, i); top_irq_status &= ~bit; @@ -180,17 +210,22 @@ int mt6358_irq_init(struct mt6397_chip *chip) int i, j, ret; struct pmic_irq_data *irqd; - irqd = devm_kzalloc(chip->dev, sizeof(*irqd), GFP_KERNEL); - if (!irqd) - return -ENOMEM; + switch (chip->chip_id) { + case MT6358_CHIP_ID: + chip->irq_data = &mt6358_irqd; + break; - chip->irq_data = irqd; + case MT6359_CHIP_ID: + chip->irq_data = &mt6359_irqd; + break; - mutex_init(&chip->irqlock); - irqd->top_int_status_reg = MT6358_TOP_INT_STATUS0; - irqd->num_pmic_irqs = MT6358_IRQ_NR; - irqd->num_top = ARRAY_SIZE(mt6358_ints); + default: + dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id); + return -ENODEV; + } + mutex_init(&chip->irqlock); + irqd = chip->irq_data; irqd->enable_hwirq = devm_kcalloc(chip->dev, irqd->num_pmic_irqs, sizeof(*irqd->enable_hwirq), @@ -207,10 +242,10 @@ int mt6358_irq_init(struct mt6397_chip *chip) /* Disable all interrupts for initializing */ for (i = 0; i < irqd->num_top; i++) { - for (j = 0; j < mt6358_ints[i].num_int_regs; j++) + for (j = 0; j < irqd->pmic_ints[i].num_int_regs; j++) regmap_write(chip->regmap, - mt6358_ints[i].en_reg + - mt6358_ints[i].en_reg_shift * j, 0); + irqd->pmic_ints[i].en_reg + + irqd->pmic_ints[i].en_reg_shift * j, 0); } chip->irq_domain = irq_domain_add_linear(chip->dev->of_node, diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index 7518d74c3b4c..9a615f75fbde 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c @@ -13,9 +13,11 @@ #include <linux/mfd/core.h> #include <linux/mfd/mt6323/core.h> #include <linux/mfd/mt6358/core.h> +#include <linux/mfd/mt6359/core.h> #include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6323/registers.h> #include <linux/mfd/mt6358/registers.h> +#include <linux/mfd/mt6359/registers.h> #include <linux/mfd/mt6397/registers.h> #define MT6323_RTC_BASE 0x8000 @@ -99,6 +101,17 @@ static const struct mfd_cell mt6358_devs[] = { }, }; +static const struct mfd_cell mt6359_devs[] = { + { .name = "mt6359-regulator", }, + { + .name = "mt6359-rtc", + .num_resources = ARRAY_SIZE(mt6358_rtc_resources), + .resources = mt6358_rtc_resources, + .of_compatible = "mediatek,mt6358-rtc", + }, + { .name = "mt6359-sound", }, +}; + static const struct mfd_cell mt6397_devs[] = { { .name = "mt6397-rtc", @@ -149,6 +162,14 @@ static const struct chip_data mt6358_core = { .irq_init = mt6358_irq_init, }; +static const struct chip_data mt6359_core = { + .cid_addr = MT6359_SWCID, + .cid_shift = 8, + .cells = mt6359_devs, + .cell_size = ARRAY_SIZE(mt6359_devs), + .irq_init = mt6358_irq_init, +}; + static const struct chip_data mt6397_core = { .cid_addr = MT6397_CID, .cid_shift = 0, @@ -219,6 +240,9 @@ static const struct of_device_id mt6397_of_match[] = { .compatible = "mediatek,mt6358", .data = &mt6358_core, }, { + .compatible = "mediatek,mt6359", + .data = &mt6359_core, + }, { .compatible = "mediatek,mt6397", .data = &mt6397_core, }, { diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 3e7a38525cb3..24ce9a17ab4f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -193,20 +193,10 @@ config REGULATOR_BCM590XX BCM590xx PMUs. This will enable support for the software controllable LDO/Switching regulators. -config REGULATOR_BD70528 - tristate "ROHM BD70528 Power Regulator" - depends on MFD_ROHM_BD70528 - help - This driver supports voltage regulators on ROHM BD70528 PMIC. - This will enable support for the software controllable buck - and LDO regulators. - - This driver can also be built as a module. If so, the module - will be called bd70528-regulator. - config REGULATOR_BD71815 tristate "ROHM BD71815 Power Regulator" depends on MFD_ROHM_BD71828 + select REGULATOR_ROHM help This driver supports voltage regulators on ROHM BD71815 PMIC. This will enable support for the software controllable buck @@ -588,6 +578,14 @@ config REGULATOR_MAX8660 This driver controls a Maxim 8660/8661 voltage output regulator via I2C bus. +config REGULATOR_MAX8893 + tristate "Maxim 8893 voltage regulator" + depends on I2C + select REGMAP_I2C + help + This driver controls a Maxim 8893 voltage output + regulator via I2C bus. + config REGULATOR_MAX8907 tristate "Maxim 8907 voltage regulator" depends on MFD_MAX8907 || COMPILE_TEST @@ -779,6 +777,15 @@ config REGULATOR_MT6358 This driver supports the control of different power rails of device through regulator interface. +config REGULATOR_MT6359 + tristate "MediaTek MT6359 PMIC" + depends on MFD_MT6397 + help + Say y here to select this option to enable the power regulator of + MediaTek MT6359 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_MT6360 tristate "MT6360 SubPMIC Regulator" depends on MFD_MT6360 @@ -1030,6 +1037,26 @@ config REGULATOR_RT5033 RT5033 PMIC. The device supports multiple regulators like current source, LDO and Buck. +config REGULATOR_RT6160 + tristate "Richtek RT6160 BuckBoost voltage regulator" + depends on I2C + select REGMAP_I2C + help + This adds support for voltage regulator in Richtek RT6160. + This device automatically change voltage output mode from + Buck or Boost. The mode transistion depend on the input source voltage. + The wide output range is from 2025mV to 5200mV and can be used on most + common application scenario. + +config REGULATOR_RT6245 + tristate "Richtek RT6245 voltage regulator" + depends on I2C + select REGMAP_I2C + help + This adds supprot for Richtek RT6245 voltage regulator. + It can support up to 14A output current and adjustable output voltage + from 0.4375V to 1.3875V, per step 12.5mV. + config REGULATOR_RTMV20 tristate "Richtek RTMV20 Laser Diode Regulator" depends on I2C @@ -1150,6 +1177,12 @@ config REGULATOR_STW481X_VMMC This driver supports the internal VMMC regulator in the STw481x PMIC chips. +config REGULATOR_SY7636A + tristate "Silergy SY7636A voltage regulator" + depends on MFD_SY7636A + help + This driver supports Silergy SY3686A voltage regulator. + config REGULATOR_SY8106A tristate "Silergy SY8106A regulator" depends on I2C && (OF || COMPILE_TEST) diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 580b015296ea..8c2f82206b94 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -4,7 +4,7 @@ # -obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o +obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o irq_helpers.o obj-$(CONFIG_OF) += of_regulator.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o @@ -29,7 +29,6 @@ obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o -obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o obj-$(CONFIG_REGULATOR_BD71815) += bd71815-regulator.o obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o @@ -72,6 +71,7 @@ obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o obj-$(CONFIG_REGULATOR_MAX77650) += max77650-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o +obj-$(CONFIG_REGULATOR_MAX8893) += max8893.o obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o @@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6315) += mt6315-regulator.o obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o +obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o @@ -124,6 +125,8 @@ obj-$(CONFIG_REGULATOR_ROHM) += rohm-regulator.o obj-$(CONFIG_REGULATOR_RT4801) += rt4801-regulator.o obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o +obj-$(CONFIG_REGULATOR_RT6160) += rt6160-regulator.o +obj-$(CONFIG_REGULATOR_RT6245) += rt6245-regulator.o obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o @@ -136,6 +139,7 @@ obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o +obj-$(CONFIG_REGULATOR_SY7636A) += sy7636a-regulator.o obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o obj-$(CONFIG_REGULATOR_SY8824X) += sy8824x.o obj-$(CONFIG_REGULATOR_SY8827N) += sy8827n.o diff --git a/drivers/regulator/bd70528-regulator.c b/drivers/regulator/bd70528-regulator.c deleted file mode 100644 index 1f5f9482b209..000000000000 --- a/drivers/regulator/bd70528-regulator.c +++ /dev/null @@ -1,283 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2018 ROHM Semiconductors -// bd70528-regulator.c ROHM BD70528MWV regulator driver - -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/mfd/rohm-bd70528.h> -#include <linux/module.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/slab.h> - -#define BUCK_RAMPRATE_250MV 0 -#define BUCK_RAMPRATE_125MV 1 -#define BUCK_RAMP_MAX 250 - -static const struct linear_range bd70528_buck1_volts[] = { - REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x1, 600000), - REGULATOR_LINEAR_RANGE(2750000, 0x2, 0xf, 50000), -}; -static const struct linear_range bd70528_buck2_volts[] = { - REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x1, 300000), - REGULATOR_LINEAR_RANGE(1550000, 0x2, 0xd, 50000), - REGULATOR_LINEAR_RANGE(3000000, 0xe, 0xf, 300000), -}; -static const struct linear_range bd70528_buck3_volts[] = { - REGULATOR_LINEAR_RANGE(800000, 0x00, 0xd, 50000), - REGULATOR_LINEAR_RANGE(1800000, 0xe, 0xf, 0), -}; - -/* All LDOs have same voltage ranges */ -static const struct linear_range bd70528_ldo_volts[] = { - REGULATOR_LINEAR_RANGE(1650000, 0x0, 0x07, 50000), - REGULATOR_LINEAR_RANGE(2100000, 0x8, 0x0f, 100000), - REGULATOR_LINEAR_RANGE(2850000, 0x10, 0x19, 50000), - REGULATOR_LINEAR_RANGE(3300000, 0x19, 0x1f, 0), -}; - -/* Also both LEDs support same voltages */ -static const unsigned int led_volts[] = { - 20000, 30000 -}; - -static int bd70528_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) -{ - if (ramp_delay > 0 && ramp_delay <= BUCK_RAMP_MAX) { - unsigned int ramp_value = BUCK_RAMPRATE_250MV; - - if (ramp_delay <= 125) - ramp_value = BUCK_RAMPRATE_125MV; - - return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, - BD70528_MASK_BUCK_RAMP, - ramp_value << BD70528_SIFT_BUCK_RAMP); - } - dev_err(&rdev->dev, "%s: ramp_delay: %d not supported\n", - rdev->desc->name, ramp_delay); - return -EINVAL; -} - -static int bd70528_led_set_voltage_sel(struct regulator_dev *rdev, - unsigned int sel) -{ - int ret; - - ret = regulator_is_enabled_regmap(rdev); - if (ret < 0) - return ret; - - if (ret == 0) - return regulator_set_voltage_sel_regmap(rdev, sel); - - dev_err(&rdev->dev, - "LED voltage change not allowed when led is enabled\n"); - - return -EBUSY; -} - -static const struct regulator_ops bd70528_buck_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 = bd70528_set_ramp_delay, -}; - -static const struct regulator_ops bd70528_ldo_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, -}; - -static const struct regulator_ops bd70528_led_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .list_voltage = regulator_list_voltage_table, - .set_voltage_sel = bd70528_led_set_voltage_sel, - .get_voltage_sel = regulator_get_voltage_sel_regmap, -}; - -static const struct regulator_desc bd70528_desc[] = { - { - .name = "buck1", - .of_match = of_match_ptr("BUCK1"), - .regulators_node = of_match_ptr("regulators"), - .id = BD70528_BUCK1, - .ops = &bd70528_buck_ops, - .type = REGULATOR_VOLTAGE, - .linear_ranges = bd70528_buck1_volts, - .n_linear_ranges = ARRAY_SIZE(bd70528_buck1_volts), - .n_voltages = BD70528_BUCK_VOLTS, - .enable_reg = BD70528_REG_BUCK1_EN, - .enable_mask = BD70528_MASK_RUN_EN, - .vsel_reg = BD70528_REG_BUCK1_VOLT, - .vsel_mask = BD70528_MASK_BUCK_VOLT, - .owner = THIS_MODULE, - }, - { - .name = "buck2", - .of_match = of_match_ptr("BUCK2"), - .regulators_node = of_match_ptr("regulators"), - .id = BD70528_BUCK2, - .ops = &bd70528_buck_ops, - .type = REGULATOR_VOLTAGE, - .linear_ranges = bd70528_buck2_volts, - .n_linear_ranges = ARRAY_SIZE(bd70528_buck2_volts), - .n_voltages = BD70528_BUCK_VOLTS, - .enable_reg = BD70528_REG_BUCK2_EN, - .enable_mask = BD70528_MASK_RUN_EN, - .vsel_reg = BD70528_REG_BUCK2_VOLT, - .vsel_mask = BD70528_MASK_BUCK_VOLT, - .owner = THIS_MODULE, - }, - { - .name = "buck3", - .of_match = of_match_ptr("BUCK3"), - .regulators_node = of_match_ptr("regulators"), - .id = BD70528_BUCK3, - .ops = &bd70528_buck_ops, - .type = REGULATOR_VOLTAGE, - .linear_ranges = bd70528_buck3_volts, - .n_linear_ranges = ARRAY_SIZE(bd70528_buck3_volts), - .n_voltages = BD70528_BUCK_VOLTS, - .enable_reg = BD70528_REG_BUCK3_EN, - .enable_mask = BD70528_MASK_RUN_EN, - .vsel_reg = BD70528_REG_BUCK3_VOLT, - .vsel_mask = BD70528_MASK_BUCK_VOLT, - .owner = THIS_MODULE, - }, - { - .name = "ldo1", - .of_match = of_match_ptr("LDO1"), - .regulators_node = of_match_ptr("regulators"), - .id = BD70528_LDO1, - .ops = &bd70528_ldo_ops, - .type = REGULATOR_VOLTAGE, - .linear_ranges = bd70528_ldo_volts, - .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts), - .n_voltages = BD70528_LDO_VOLTS, - .enable_reg = BD70528_REG_LDO1_EN, - .enable_mask = BD70528_MASK_RUN_EN, - .vsel_reg = BD70528_REG_LDO1_VOLT, - .vsel_mask = BD70528_MASK_LDO_VOLT, - .owner = THIS_MODULE, - }, - { - .name = "ldo2", - .of_match = of_match_ptr("LDO2"), - .regulators_node = of_match_ptr("regulators"), - .id = BD70528_LDO2, - .ops = &bd70528_ldo_ops, - .type = REGULATOR_VOLTAGE, - .linear_ranges = bd70528_ldo_volts, - .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts), - .n_voltages = BD70528_LDO_VOLTS, - .enable_reg = BD70528_REG_LDO2_EN, - .enable_mask = BD70528_MASK_RUN_EN, - .vsel_reg = BD70528_REG_LDO2_VOLT, - .vsel_mask = BD70528_MASK_LDO_VOLT, - .owner = THIS_MODULE, - }, - { - .name = "ldo3", - .of_match = of_match_ptr("LDO3"), - .regulators_node = of_match_ptr("regulators"), - .id = BD70528_LDO3, - .ops = &bd70528_ldo_ops, - .type = REGULATOR_VOLTAGE, - .linear_ranges = bd70528_ldo_volts, - .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts), - .n_voltages = BD70528_LDO_VOLTS, - .enable_reg = BD70528_REG_LDO3_EN, - .enable_mask = BD70528_MASK_RUN_EN, - .vsel_reg = BD70528_REG_LDO3_VOLT, - .vsel_mask = BD70528_MASK_LDO_VOLT, - .owner = THIS_MODULE, - }, - { - .name = "ldo_led1", - .of_match = of_match_ptr("LDO_LED1"), - .regulators_node = of_match_ptr("regulators"), - .id = BD70528_LED1, - .ops = &bd70528_led_ops, - .type = REGULATOR_VOLTAGE, - .volt_table = &led_volts[0], - .n_voltages = ARRAY_SIZE(led_volts), - .enable_reg = BD70528_REG_LED_EN, - .enable_mask = BD70528_MASK_LED1_EN, - .vsel_reg = BD70528_REG_LED_VOLT, - .vsel_mask = BD70528_MASK_LED1_VOLT, - .owner = THIS_MODULE, - }, - { - .name = "ldo_led2", - .of_match = of_match_ptr("LDO_LED2"), - .regulators_node = of_match_ptr("regulators"), - .id = BD70528_LED2, - .ops = &bd70528_led_ops, - .type = REGULATOR_VOLTAGE, - .volt_table = &led_volts[0], - .n_voltages = ARRAY_SIZE(led_volts), - .enable_reg = BD70528_REG_LED_EN, - .enable_mask = BD70528_MASK_LED2_EN, - .vsel_reg = BD70528_REG_LED_VOLT, - .vsel_mask = BD70528_MASK_LED2_VOLT, - .owner = THIS_MODULE, - }, - -}; - -static int bd70528_probe(struct platform_device *pdev) -{ - int i; - struct regulator_config config = { - .dev = pdev->dev.parent, - }; - - config.regmap = dev_get_regmap(pdev->dev.parent, NULL); - if (!config.regmap) - return -ENODEV; - - for (i = 0; i < ARRAY_SIZE(bd70528_desc); i++) { - struct regulator_dev *rdev; - - rdev = devm_regulator_register(&pdev->dev, &bd70528_desc[i], - &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, - "failed to register %s regulator\n", - bd70528_desc[i].name); - return PTR_ERR(rdev); - } - } - return 0; -} - -static struct platform_driver bd70528_regulator = { - .driver = { - .name = "bd70528-pmic" - }, - .probe = bd70528_probe, -}; - -module_platform_driver(bd70528_regulator); - -MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); -MODULE_DESCRIPTION("BD70528 voltage regulator driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:bd70528-pmic"); diff --git a/drivers/regulator/bd71815-regulator.c b/drivers/regulator/bd71815-regulator.c index a4e8d5e36b40..16edd9062ca9 100644 --- a/drivers/regulator/bd71815-regulator.c +++ b/drivers/regulator/bd71815-regulator.c @@ -13,6 +13,8 @@ #include <linux/init.h> #include <linux/err.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/gpio/consumer.h> #include <linux/regulator/driver.h> #include <linux/delay.h> #include <linux/slab.h> @@ -26,14 +28,6 @@ struct bd71815_regulator { const struct rohm_dvs_config *dvs; }; -struct bd71815_pmic { - struct bd71815_regulator descs[BD71815_REGULATOR_CNT]; - struct regmap *regmap; - struct device *dev; - struct gpio_descs *gps; - struct regulator_dev *rdev[BD71815_REGULATOR_CNT]; -}; - static const int bd7181x_wled_currents[] = { 10, 20, 30, 50, 70, 100, 200, 300, 500, 700, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000, @@ -300,14 +294,13 @@ static int bd7181x_led_set_current_limit(struct regulator_dev *rdev, static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev) { - struct bd71815_pmic *pmic = rdev_get_drvdata(rdev); int rid = rdev_get_id(rdev); int ret, regh, regl, val; regh = BD71815_REG_BUCK1_VOLT_H + rid * 0x2; regl = BD71815_REG_BUCK1_VOLT_L + rid * 0x2; - ret = regmap_read(pmic->regmap, regh, &val); + ret = regmap_read(rdev->regmap, regh, &val); if (ret) return ret; @@ -319,7 +312,7 @@ static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev) * by BD71815_BUCK_DVSSEL bit */ if ((!(val & BD71815_BUCK_STBY_DVS)) && (!(val & BD71815_BUCK_DVSSEL))) - ret = regmap_read(pmic->regmap, regl, &val); + ret = regmap_read(rdev->regmap, regl, &val); if (ret) return ret; @@ -333,14 +326,13 @@ static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev) static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) { - struct bd71815_pmic *pmic = rdev_get_drvdata(rdev); int rid = rdev_get_id(rdev); int ret, val, reg, regh, regl; regh = BD71815_REG_BUCK1_VOLT_H + rid*0x2; regl = BD71815_REG_BUCK1_VOLT_L + rid*0x2; - ret = regmap_read(pmic->regmap, regh, &val); + ret = regmap_read(rdev->regmap, regh, &val); if (ret) return ret; @@ -350,7 +342,7 @@ static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev, * voltages at runtime is not supported by this driver. */ if (((val & BD71815_BUCK_STBY_DVS))) { - return regmap_update_bits(pmic->regmap, regh, BD71815_VOLT_MASK, + return regmap_update_bits(rdev->regmap, regh, BD71815_VOLT_MASK, sel); } /* Update new voltage to the register which is not selected now */ @@ -359,12 +351,13 @@ static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev, else reg = regh; - ret = regmap_update_bits(pmic->regmap, reg, BD71815_VOLT_MASK, sel); + ret = regmap_update_bits(rdev->regmap, reg, BD71815_VOLT_MASK, sel); if (ret) return ret; /* Select the other DVS register to be used */ - return regmap_update_bits(pmic->regmap, regh, BD71815_BUCK_DVSSEL, ~val); + return regmap_update_bits(rdev->regmap, regh, BD71815_BUCK_DVSSEL, + ~val); } static const struct regulator_ops bd7181x_ldo_regulator_ops = { @@ -522,7 +515,7 @@ static const struct regulator_ops bd7181x_led_regulator_ops = { .dvs = (_dvs), \ } -static struct bd71815_regulator bd71815_regulators[] = { +static const struct bd71815_regulator bd71815_regulators[] = { BD71815_BUCK12_REG(buck1, BD71815_BUCK1, BD71815_REG_BUCK1_VOLT_H, BD71815_REG_BUCK1_MODE, 800000, 2000000, 25000, &buck1_dvs), @@ -568,24 +561,16 @@ static struct bd71815_regulator bd71815_regulators[] = { static int bd7181x_probe(struct platform_device *pdev) { - struct bd71815_pmic *pmic; struct regulator_config config = {}; int i, ret; struct gpio_desc *ldo4_en; + struct regmap *regmap; - pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); - if (!pmic) - return -ENOMEM; - - memcpy(pmic->descs, bd71815_regulators, sizeof(pmic->descs)); - - pmic->dev = &pdev->dev; - pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL); - if (!pmic->regmap) { - dev_err(pmic->dev, "No parent regmap\n"); + regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!regmap) { + dev_err(&pdev->dev, "No parent regmap\n"); return -ENODEV; } - platform_set_drvdata(pdev, pmic); ldo4_en = devm_gpiod_get_from_of_node(&pdev->dev, pdev->dev.parent->of_node, "rohm,vsel-gpios", 0, @@ -599,23 +584,23 @@ static int bd7181x_probe(struct platform_device *pdev) } /* Disable to go to ship-mode */ - ret = regmap_update_bits(pmic->regmap, BD71815_REG_PWRCTRL, - RESTARTEN, 0); + ret = regmap_update_bits(regmap, BD71815_REG_PWRCTRL, RESTARTEN, 0); if (ret) return ret; config.dev = pdev->dev.parent; - config.regmap = pmic->regmap; + config.regmap = regmap; for (i = 0; i < BD71815_REGULATOR_CNT; i++) { - struct regulator_desc *desc; + const struct regulator_desc *desc; struct regulator_dev *rdev; - desc = &pmic->descs[i].desc; + desc = &bd71815_regulators[i].desc; + if (i == BD71815_LDO4) config.ena_gpiod = ldo4_en; - - config.driver_data = pmic; + else + config.ena_gpiod = NULL; rdev = devm_regulator_register(&pdev->dev, desc, &config); if (IS_ERR(rdev)) { @@ -624,8 +609,6 @@ static int bd7181x_probe(struct platform_device *pdev) desc->name); return PTR_ERR(rdev); } - config.ena_gpiod = NULL; - pmic->rdev[i] = rdev; } return 0; } @@ -639,7 +622,6 @@ MODULE_DEVICE_TABLE(platform, bd7181x_pmic_id); static struct platform_driver bd7181x_regulator = { .driver = { .name = "bd7181x-pmic", - .owner = THIS_MODULE, }, .probe = bd7181x_probe, .id_table = bd7181x_pmic_id, diff --git a/drivers/regulator/bd9576-regulator.c b/drivers/regulator/bd9576-regulator.c index 204a2da054f5..e16c3727db7a 100644 --- a/drivers/regulator/bd9576-regulator.c +++ b/drivers/regulator/bd9576-regulator.c @@ -2,10 +2,10 @@ // Copyright (C) 2020 ROHM Semiconductors // ROHM BD9576MUF/BD9573MUF regulator driver -#include <linux/delay.h> #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/interrupt.h> +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/mfd/rohm-bd957x.h> #include <linux/mfd/rohm-generic.h> @@ -16,29 +16,118 @@ #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> #define BD957X_VOUTS1_VOLT 3300000 #define BD957X_VOUTS4_BASE_VOLT 1030000 #define BD957X_VOUTS34_NUM_VOLT 32 -static int vout1_volt_table[] = {5000000, 4900000, 4800000, 4700000, 4600000, - 4500000, 4500000, 4500000, 5000000, 5100000, - 5200000, 5300000, 5400000, 5500000, 5500000, - 5500000}; +#define BD9576_THERM_IRQ_MASK_TW BIT(5) +#define BD9576_xVD_IRQ_MASK_VOUTL1 BIT(5) +#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6) +#define BD9576_xVD_IRQ_MASK_VOUT1TO4 0x0F -static int vout2_volt_table[] = {1800000, 1780000, 1760000, 1740000, 1720000, - 1700000, 1680000, 1660000, 1800000, 1820000, - 1840000, 1860000, 1880000, 1900000, 1920000, - 1940000}; +static const unsigned int vout1_volt_table[] = { + 5000000, 4900000, 4800000, 4700000, 4600000, + 4500000, 4500000, 4500000, 5000000, 5100000, + 5200000, 5300000, 5400000, 5500000, 5500000, + 5500000 +}; + +static const unsigned int vout2_volt_table[] = { + 1800000, 1780000, 1760000, 1740000, 1720000, + 1700000, 1680000, 1660000, 1800000, 1820000, + 1840000, 1860000, 1880000, 1900000, 1920000, + 1940000 +}; + +static const unsigned int voutl1_volt_table[] = { + 2500000, 2540000, 2580000, 2620000, 2660000, + 2700000, 2740000, 2780000, 2500000, 2460000, + 2420000, 2380000, 2340000, 2300000, 2260000, + 2220000 +}; + +static const struct linear_range vout1_xvd_ranges[] = { + REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0), + REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000), + REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0), +}; + +static const struct linear_range vout234_xvd_ranges[] = { + REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0), + REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000), + REGULATOR_LINEAR_RANGE(110000, 0x6e, 0x7f, 0), +}; + +static const struct linear_range voutL1_xvd_ranges[] = { + REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0), + REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000), + REGULATOR_LINEAR_RANGE(220000, 0x6e, 0x7f, 0), +}; + +static struct linear_range voutS1_ocw_ranges_internal[] = { + REGULATOR_LINEAR_RANGE(200000, 0x01, 0x04, 0), + REGULATOR_LINEAR_RANGE(250000, 0x05, 0x18, 50000), + REGULATOR_LINEAR_RANGE(1200000, 0x19, 0x3f, 0), +}; + +static struct linear_range voutS1_ocw_ranges[] = { + REGULATOR_LINEAR_RANGE(50000, 0x01, 0x04, 0), + REGULATOR_LINEAR_RANGE(60000, 0x05, 0x18, 10000), + REGULATOR_LINEAR_RANGE(250000, 0x19, 0x3f, 0), +}; + +static struct linear_range voutS1_ocp_ranges_internal[] = { + REGULATOR_LINEAR_RANGE(300000, 0x01, 0x06, 0), + REGULATOR_LINEAR_RANGE(350000, 0x7, 0x1b, 50000), + REGULATOR_LINEAR_RANGE(1350000, 0x1c, 0x3f, 0), +}; -static int voutl1_volt_table[] = {2500000, 2540000, 2580000, 2620000, 2660000, - 2700000, 2740000, 2780000, 2500000, 2460000, - 2420000, 2380000, 2340000, 2300000, 2260000, - 2220000}; +static struct linear_range voutS1_ocp_ranges[] = { + REGULATOR_LINEAR_RANGE(70000, 0x01, 0x06, 0), + REGULATOR_LINEAR_RANGE(80000, 0x7, 0x1b, 10000), + REGULATOR_LINEAR_RANGE(280000, 0x1c, 0x3f, 0), +}; struct bd957x_regulator_data { struct regulator_desc desc; int base_voltage; + struct regulator_dev *rdev; + int ovd_notif; + int uvd_notif; + int temp_notif; + int ovd_err; + int uvd_err; + int temp_err; + const struct linear_range *xvd_ranges; + int num_xvd_ranges; + bool oc_supported; + unsigned int ovd_reg; + unsigned int uvd_reg; + unsigned int xvd_mask; + unsigned int ocp_reg; + unsigned int ocp_mask; + unsigned int ocw_reg; + unsigned int ocw_mask; + unsigned int ocw_rfet; +}; + +#define BD9576_NUM_REGULATORS 6 +#define BD9576_NUM_OVD_REGULATORS 5 + +struct bd957x_data { + struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS]; + struct regmap *regmap; + struct delayed_work therm_irq_suppress; + struct delayed_work ovd_irq_suppress; + struct delayed_work uvd_irq_suppress; + unsigned int therm_irq; + unsigned int ovd_irq; + unsigned int uvd_irq; + spinlock_t err_lock; + int regulator_global_err; }; static int bd957x_vout34_list_voltage(struct regulator_dev *rdev, @@ -72,151 +161,784 @@ static int bd957x_list_voltage(struct regulator_dev *rdev, return desc->volt_table[index]; } -static const struct regulator_ops bd957x_vout34_ops = { +static void bd9576_fill_ovd_flags(struct bd957x_regulator_data *data, + bool warn) +{ + if (warn) { + data->ovd_notif = REGULATOR_EVENT_OVER_VOLTAGE_WARN; + data->ovd_err = REGULATOR_ERROR_OVER_VOLTAGE_WARN; + } else { + data->ovd_notif = REGULATOR_EVENT_REGULATION_OUT; + data->ovd_err = REGULATOR_ERROR_REGULATION_OUT; + } +} + +static void bd9576_fill_ocp_flags(struct bd957x_regulator_data *data, + bool warn) +{ + if (warn) { + data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT_WARN; + data->uvd_err = REGULATOR_ERROR_OVER_CURRENT_WARN; + } else { + data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT; + data->uvd_err = REGULATOR_ERROR_OVER_CURRENT; + } +} + +static void bd9576_fill_uvd_flags(struct bd957x_regulator_data *data, + bool warn) +{ + if (warn) { + data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE_WARN; + data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE_WARN; + } else { + data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE; + data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE; + } +} + +static void bd9576_fill_temp_flags(struct bd957x_regulator_data *data, + bool enable, bool warn) +{ + if (!enable) { + data->temp_notif = 0; + data->temp_err = 0; + } else if (warn) { + data->temp_notif = REGULATOR_EVENT_OVER_TEMP_WARN; + data->temp_err = REGULATOR_ERROR_OVER_TEMP_WARN; + } else { + data->temp_notif = REGULATOR_EVENT_OVER_TEMP; + data->temp_err = REGULATOR_ERROR_OVER_TEMP; + } +} + +static int bd9576_set_limit(const struct linear_range *r, int num_ranges, + struct regmap *regmap, int reg, int mask, int lim) +{ + int ret; + bool found; + int sel = 0; + + if (lim) { + + ret = linear_range_get_selector_low_array(r, num_ranges, + lim, &sel, &found); + if (ret) + return ret; + + if (!found) + dev_warn(regmap_get_device(regmap), + "limit %d out of range. Setting lower\n", + lim); + } + + return regmap_update_bits(regmap, reg, mask, sel); +} + +static bool check_ocp_flag_mismatch(struct regulator_dev *rdev, int severity, + struct bd957x_regulator_data *r) +{ + if ((severity == REGULATOR_SEVERITY_ERR && + r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT) || + (severity == REGULATOR_SEVERITY_WARN && + r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT_WARN)) { + dev_warn(rdev_get_dev(rdev), + "Can't support both OCP WARN and ERR\n"); + /* Do not overwrite ERR config with WARN */ + if (severity == REGULATOR_SEVERITY_WARN) + return true; + + bd9576_fill_ocp_flags(r, 0); + } + + return false; +} + +static bool check_uvd_flag_mismatch(struct regulator_dev *rdev, int severity, + struct bd957x_regulator_data *r) +{ + if ((severity == REGULATOR_SEVERITY_ERR && + r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE) || + (severity == REGULATOR_SEVERITY_WARN && + r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE_WARN)) { + dev_warn(rdev_get_dev(rdev), + "Can't support both UVD WARN and ERR\n"); + if (severity == REGULATOR_SEVERITY_WARN) + return true; + + bd9576_fill_uvd_flags(r, 0); + } + + return false; +} + +static bool check_ovd_flag_mismatch(struct regulator_dev *rdev, int severity, + struct bd957x_regulator_data *r) +{ + if ((severity == REGULATOR_SEVERITY_ERR && + r->ovd_notif != REGULATOR_EVENT_REGULATION_OUT) || + (severity == REGULATOR_SEVERITY_WARN && + r->ovd_notif != REGULATOR_EVENT_OVER_VOLTAGE_WARN)) { + dev_warn(rdev_get_dev(rdev), + "Can't support both OVD WARN and ERR\n"); + if (severity == REGULATOR_SEVERITY_WARN) + return true; + + bd9576_fill_ovd_flags(r, 0); + } + + return false; +} + +static bool check_temp_flag_mismatch(struct regulator_dev *rdev, int severity, + struct bd957x_regulator_data *r) +{ + if ((severity == REGULATOR_SEVERITY_ERR && + r->ovd_notif != REGULATOR_EVENT_OVER_TEMP) || + (severity == REGULATOR_SEVERITY_WARN && + r->ovd_notif != REGULATOR_EVENT_OVER_TEMP_WARN)) { + dev_warn(rdev_get_dev(rdev), + "Can't support both thermal WARN and ERR\n"); + if (severity == REGULATOR_SEVERITY_WARN) + return true; + } + + return false; +} + +static int bd9576_set_ocp(struct regulator_dev *rdev, int lim_uA, int severity, + bool enable) +{ + struct bd957x_data *d; + struct bd957x_regulator_data *r; + int reg, mask; + int Vfet, rfet; + const struct linear_range *range; + int num_ranges; + + if ((lim_uA && !enable) || (!lim_uA && enable)) + return -EINVAL; + + r = container_of(rdev->desc, struct bd957x_regulator_data, desc); + if (!r->oc_supported) + return -EINVAL; + + d = rdev_get_drvdata(rdev); + + if (severity == REGULATOR_SEVERITY_PROT) { + reg = r->ocp_reg; + mask = r->ocp_mask; + if (r->ocw_rfet) { + range = voutS1_ocp_ranges; + num_ranges = ARRAY_SIZE(voutS1_ocp_ranges); + rfet = r->ocw_rfet / 1000; + } else { + range = voutS1_ocp_ranges_internal; + num_ranges = ARRAY_SIZE(voutS1_ocp_ranges_internal); + /* Internal values are already micro-amperes */ + rfet = 1000; + } + } else { + reg = r->ocw_reg; + mask = r->ocw_mask; + + if (r->ocw_rfet) { + range = voutS1_ocw_ranges; + num_ranges = ARRAY_SIZE(voutS1_ocw_ranges); + rfet = r->ocw_rfet / 1000; + } else { + range = voutS1_ocw_ranges_internal; + num_ranges = ARRAY_SIZE(voutS1_ocw_ranges_internal); + /* Internal values are already micro-amperes */ + rfet = 1000; + } + + /* We abuse uvd fields for OCW on VoutS1 */ + if (r->uvd_notif) { + /* + * If both warning and error are requested, prioritize + * ERROR configuration + */ + if (check_ocp_flag_mismatch(rdev, severity, r)) + return 0; + } else { + bool warn = severity == REGULATOR_SEVERITY_WARN; + + bd9576_fill_ocp_flags(r, warn); + } + } + + /* + * limits are given in uA, rfet is mOhm + * Divide lim_uA by 1000 to get Vfet in uV. + * (We expect both Rfet and limit uA to be magnitude of hundreds of + * milli Amperes & milli Ohms => we should still have decent accuracy) + */ + Vfet = lim_uA/1000 * rfet; + + return bd9576_set_limit(range, num_ranges, d->regmap, + reg, mask, Vfet); +} + +static int bd9576_set_uvp(struct regulator_dev *rdev, int lim_uV, int severity, + bool enable) +{ + struct bd957x_data *d; + struct bd957x_regulator_data *r; + int mask, reg; + + if (severity == REGULATOR_SEVERITY_PROT) { + if (!enable || lim_uV) + return -EINVAL; + return 0; + } + + /* + * BD9576 has enable control as a special value in limit reg. Can't + * set limit but keep feature disabled or enable W/O given limit. + */ + if ((lim_uV && !enable) || (!lim_uV && enable)) + return -EINVAL; + + r = container_of(rdev->desc, struct bd957x_regulator_data, desc); + d = rdev_get_drvdata(rdev); + + mask = r->xvd_mask; + reg = r->uvd_reg; + /* + * Check that there is no mismatch for what the detection IRQs are to + * be used. + */ + if (r->uvd_notif) { + if (check_uvd_flag_mismatch(rdev, severity, r)) + return 0; + } else { + bd9576_fill_uvd_flags(r, severity == REGULATOR_SEVERITY_WARN); + } + + return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap, + reg, mask, lim_uV); +} + +static int bd9576_set_ovp(struct regulator_dev *rdev, int lim_uV, int severity, + bool enable) +{ + struct bd957x_data *d; + struct bd957x_regulator_data *r; + int mask, reg; + + if (severity == REGULATOR_SEVERITY_PROT) { + if (!enable || lim_uV) + return -EINVAL; + return 0; + } + + /* + * BD9576 has enable control as a special value in limit reg. Can't + * set limit but keep feature disabled or enable W/O given limit. + */ + if ((lim_uV && !enable) || (!lim_uV && enable)) + return -EINVAL; + + r = container_of(rdev->desc, struct bd957x_regulator_data, desc); + d = rdev_get_drvdata(rdev); + + mask = r->xvd_mask; + reg = r->ovd_reg; + /* + * Check that there is no mismatch for what the detection IRQs are to + * be used. + */ + if (r->ovd_notif) { + if (check_ovd_flag_mismatch(rdev, severity, r)) + return 0; + } else { + bd9576_fill_ovd_flags(r, severity == REGULATOR_SEVERITY_WARN); + } + + return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap, + reg, mask, lim_uV); +} + + +static int bd9576_set_tw(struct regulator_dev *rdev, int lim, int severity, + bool enable) +{ + struct bd957x_data *d; + struct bd957x_regulator_data *r; + int i; + + /* + * BD9576MUF has fixed temperature limits + * The detection can only be enabled/disabled + */ + if (lim) + return -EINVAL; + + /* Protection can't be disabled */ + if (severity == REGULATOR_SEVERITY_PROT) { + if (!enable) + return -EINVAL; + else + return 0; + } + + r = container_of(rdev->desc, struct bd957x_regulator_data, desc); + d = rdev_get_drvdata(rdev); + + /* + * Check that there is no mismatch for what the detection IRQs are to + * be used. + */ + if (r->temp_notif) + if (check_temp_flag_mismatch(rdev, severity, r)) + return 0; + + bd9576_fill_temp_flags(r, enable, severity == REGULATOR_SEVERITY_WARN); + + if (enable) + return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK, + BD9576_THERM_IRQ_MASK_TW, 0); + + /* + * If any of the regulators is interested in thermal warning we keep IRQ + * enabled. + */ + for (i = 0; i < BD9576_NUM_REGULATORS; i++) + if (d->regulator_data[i].temp_notif) + return 0; + + return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK, + BD9576_THERM_IRQ_MASK_TW, + BD9576_THERM_IRQ_MASK_TW); +} + +static const struct regulator_ops bd9573_vout34_ops = { .is_enabled = regulator_is_enabled_regmap, .list_voltage = bd957x_vout34_list_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, }; -static const struct regulator_ops bd957X_vouts1_regulator_ops = { +static const struct regulator_ops bd9576_vout34_ops = { + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = bd957x_vout34_list_voltage, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_over_voltage_protection = bd9576_set_ovp, + .set_under_voltage_protection = bd9576_set_uvp, + .set_thermal_protection = bd9576_set_tw, +}; + +static const struct regulator_ops bd9573_vouts1_regulator_ops = { + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_ops bd9576_vouts1_regulator_ops = { .is_enabled = regulator_is_enabled_regmap, + .set_over_current_protection = bd9576_set_ocp, }; -static const struct regulator_ops bd957x_ops = { +static const struct regulator_ops bd9573_ops = { .is_enabled = regulator_is_enabled_regmap, .list_voltage = bd957x_list_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, }; -static struct bd957x_regulator_data bd9576_regulators[] = { - { - .desc = { - .name = "VD50", - .of_match = of_match_ptr("regulator-vd50"), - .regulators_node = of_match_ptr("regulators"), - .id = BD957X_VD50, - .type = REGULATOR_VOLTAGE, - .ops = &bd957x_ops, - .volt_table = &vout1_volt_table[0], - .n_voltages = ARRAY_SIZE(vout1_volt_table), - .vsel_reg = BD957X_REG_VOUT1_TUNE, - .vsel_mask = BD957X_MASK_VOUT1_TUNE, - .enable_reg = BD957X_REG_POW_TRIGGER1, - .enable_mask = BD957X_REGULATOR_EN_MASK, - .enable_val = BD957X_REGULATOR_DIS_VAL, - .enable_is_inverted = true, - .owner = THIS_MODULE, +static const struct regulator_ops bd9576_ops = { + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = bd957x_list_voltage, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_over_voltage_protection = bd9576_set_ovp, + .set_under_voltage_protection = bd9576_set_uvp, + .set_thermal_protection = bd9576_set_tw, +}; + +static const struct regulator_ops *bd9573_ops_arr[] = { + [BD957X_VD50] = &bd9573_ops, + [BD957X_VD18] = &bd9573_ops, + [BD957X_VDDDR] = &bd9573_vout34_ops, + [BD957X_VD10] = &bd9573_vout34_ops, + [BD957X_VOUTL1] = &bd9573_ops, + [BD957X_VOUTS1] = &bd9573_vouts1_regulator_ops, +}; + +static const struct regulator_ops *bd9576_ops_arr[] = { + [BD957X_VD50] = &bd9576_ops, + [BD957X_VD18] = &bd9576_ops, + [BD957X_VDDDR] = &bd9576_vout34_ops, + [BD957X_VD10] = &bd9576_vout34_ops, + [BD957X_VOUTL1] = &bd9576_ops, + [BD957X_VOUTS1] = &bd9576_vouts1_regulator_ops, +}; + +static int vouts1_get_fet_res(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *cfg) +{ + struct bd957x_regulator_data *data; + int ret; + u32 uohms; + + data = container_of(desc, struct bd957x_regulator_data, desc); + + ret = of_property_read_u32(np, "rohm,ocw-fet-ron-micro-ohms", &uohms); + if (ret) { + if (ret != -EINVAL) + return ret; + + return 0; + } + data->ocw_rfet = uohms; + return 0; +} + +static struct bd957x_data bd957x_regulators = { + .regulator_data = { + { + .desc = { + .name = "VD50", + .of_match = of_match_ptr("regulator-vd50"), + .regulators_node = of_match_ptr("regulators"), + .id = BD957X_VD50, + .type = REGULATOR_VOLTAGE, + .volt_table = &vout1_volt_table[0], + .n_voltages = ARRAY_SIZE(vout1_volt_table), + .vsel_reg = BD957X_REG_VOUT1_TUNE, + .vsel_mask = BD957X_MASK_VOUT1_TUNE, + .enable_reg = BD957X_REG_POW_TRIGGER1, + .enable_mask = BD957X_REGULATOR_EN_MASK, + .enable_val = BD957X_REGULATOR_DIS_VAL, + .enable_is_inverted = true, + .owner = THIS_MODULE, + }, + .xvd_ranges = vout1_xvd_ranges, + .num_xvd_ranges = ARRAY_SIZE(vout1_xvd_ranges), + .ovd_reg = BD9576_REG_VOUT1_OVD, + .uvd_reg = BD9576_REG_VOUT1_UVD, + .xvd_mask = BD9576_MASK_XVD, }, - }, - { - .desc = { - .name = "VD18", - .of_match = of_match_ptr("regulator-vd18"), - .regulators_node = of_match_ptr("regulators"), - .id = BD957X_VD18, - .type = REGULATOR_VOLTAGE, - .ops = &bd957x_ops, - .volt_table = &vout2_volt_table[0], - .n_voltages = ARRAY_SIZE(vout2_volt_table), - .vsel_reg = BD957X_REG_VOUT2_TUNE, - .vsel_mask = BD957X_MASK_VOUT2_TUNE, - .enable_reg = BD957X_REG_POW_TRIGGER2, - .enable_mask = BD957X_REGULATOR_EN_MASK, - .enable_val = BD957X_REGULATOR_DIS_VAL, - .enable_is_inverted = true, - .owner = THIS_MODULE, + { + .desc = { + .name = "VD18", + .of_match = of_match_ptr("regulator-vd18"), + .regulators_node = of_match_ptr("regulators"), + .id = BD957X_VD18, + .type = REGULATOR_VOLTAGE, + .volt_table = &vout2_volt_table[0], + .n_voltages = ARRAY_SIZE(vout2_volt_table), + .vsel_reg = BD957X_REG_VOUT2_TUNE, + .vsel_mask = BD957X_MASK_VOUT2_TUNE, + .enable_reg = BD957X_REG_POW_TRIGGER2, + .enable_mask = BD957X_REGULATOR_EN_MASK, + .enable_val = BD957X_REGULATOR_DIS_VAL, + .enable_is_inverted = true, + .owner = THIS_MODULE, + }, + .xvd_ranges = vout234_xvd_ranges, + .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges), + .ovd_reg = BD9576_REG_VOUT2_OVD, + .uvd_reg = BD9576_REG_VOUT2_UVD, + .xvd_mask = BD9576_MASK_XVD, }, - }, - { - .desc = { - .name = "VDDDR", - .of_match = of_match_ptr("regulator-vdddr"), - .regulators_node = of_match_ptr("regulators"), - .id = BD957X_VDDDR, - .ops = &bd957x_vout34_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = BD957X_VOUTS34_NUM_VOLT, - .vsel_reg = BD957X_REG_VOUT3_TUNE, - .vsel_mask = BD957X_MASK_VOUT3_TUNE, - .enable_reg = BD957X_REG_POW_TRIGGER3, - .enable_mask = BD957X_REGULATOR_EN_MASK, - .enable_val = BD957X_REGULATOR_DIS_VAL, - .enable_is_inverted = true, - .owner = THIS_MODULE, + { + .desc = { + .name = "VDDDR", + .of_match = of_match_ptr("regulator-vdddr"), + .regulators_node = of_match_ptr("regulators"), + .id = BD957X_VDDDR, + .type = REGULATOR_VOLTAGE, + .n_voltages = BD957X_VOUTS34_NUM_VOLT, + .vsel_reg = BD957X_REG_VOUT3_TUNE, + .vsel_mask = BD957X_MASK_VOUT3_TUNE, + .enable_reg = BD957X_REG_POW_TRIGGER3, + .enable_mask = BD957X_REGULATOR_EN_MASK, + .enable_val = BD957X_REGULATOR_DIS_VAL, + .enable_is_inverted = true, + .owner = THIS_MODULE, + }, + .ovd_reg = BD9576_REG_VOUT3_OVD, + .uvd_reg = BD9576_REG_VOUT3_UVD, + .xvd_mask = BD9576_MASK_XVD, + .xvd_ranges = vout234_xvd_ranges, + .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges), }, - }, - { - .desc = { - .name = "VD10", - .of_match = of_match_ptr("regulator-vd10"), - .regulators_node = of_match_ptr("regulators"), - .id = BD957X_VD10, - .ops = &bd957x_vout34_ops, - .type = REGULATOR_VOLTAGE, - .fixed_uV = BD957X_VOUTS4_BASE_VOLT, - .n_voltages = BD957X_VOUTS34_NUM_VOLT, - .vsel_reg = BD957X_REG_VOUT4_TUNE, - .vsel_mask = BD957X_MASK_VOUT4_TUNE, - .enable_reg = BD957X_REG_POW_TRIGGER4, - .enable_mask = BD957X_REGULATOR_EN_MASK, - .enable_val = BD957X_REGULATOR_DIS_VAL, - .enable_is_inverted = true, - .owner = THIS_MODULE, + { + .desc = { + .name = "VD10", + .of_match = of_match_ptr("regulator-vd10"), + .regulators_node = of_match_ptr("regulators"), + .id = BD957X_VD10, + .type = REGULATOR_VOLTAGE, + .fixed_uV = BD957X_VOUTS4_BASE_VOLT, + .n_voltages = BD957X_VOUTS34_NUM_VOLT, + .vsel_reg = BD957X_REG_VOUT4_TUNE, + .vsel_mask = BD957X_MASK_VOUT4_TUNE, + .enable_reg = BD957X_REG_POW_TRIGGER4, + .enable_mask = BD957X_REGULATOR_EN_MASK, + .enable_val = BD957X_REGULATOR_DIS_VAL, + .enable_is_inverted = true, + .owner = THIS_MODULE, + }, + .xvd_ranges = vout234_xvd_ranges, + .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges), + .ovd_reg = BD9576_REG_VOUT4_OVD, + .uvd_reg = BD9576_REG_VOUT4_UVD, + .xvd_mask = BD9576_MASK_XVD, }, - }, - { - .desc = { - .name = "VOUTL1", - .of_match = of_match_ptr("regulator-voutl1"), - .regulators_node = of_match_ptr("regulators"), - .id = BD957X_VOUTL1, - .ops = &bd957x_ops, - .type = REGULATOR_VOLTAGE, - .volt_table = &voutl1_volt_table[0], - .n_voltages = ARRAY_SIZE(voutl1_volt_table), - .vsel_reg = BD957X_REG_VOUTL1_TUNE, - .vsel_mask = BD957X_MASK_VOUTL1_TUNE, - .enable_reg = BD957X_REG_POW_TRIGGERL1, - .enable_mask = BD957X_REGULATOR_EN_MASK, - .enable_val = BD957X_REGULATOR_DIS_VAL, - .enable_is_inverted = true, - .owner = THIS_MODULE, + { + .desc = { + .name = "VOUTL1", + .of_match = of_match_ptr("regulator-voutl1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD957X_VOUTL1, + .type = REGULATOR_VOLTAGE, + .volt_table = &voutl1_volt_table[0], + .n_voltages = ARRAY_SIZE(voutl1_volt_table), + .vsel_reg = BD957X_REG_VOUTL1_TUNE, + .vsel_mask = BD957X_MASK_VOUTL1_TUNE, + .enable_reg = BD957X_REG_POW_TRIGGERL1, + .enable_mask = BD957X_REGULATOR_EN_MASK, + .enable_val = BD957X_REGULATOR_DIS_VAL, + .enable_is_inverted = true, + .owner = THIS_MODULE, + }, + .xvd_ranges = voutL1_xvd_ranges, + .num_xvd_ranges = ARRAY_SIZE(voutL1_xvd_ranges), + .ovd_reg = BD9576_REG_VOUTL1_OVD, + .uvd_reg = BD9576_REG_VOUTL1_UVD, + .xvd_mask = BD9576_MASK_XVD, }, - }, - { - .desc = { - .name = "VOUTS1", - .of_match = of_match_ptr("regulator-vouts1"), - .regulators_node = of_match_ptr("regulators"), - .id = BD957X_VOUTS1, - .ops = &bd957X_vouts1_regulator_ops, - .type = REGULATOR_VOLTAGE, - .n_voltages = 1, - .fixed_uV = BD957X_VOUTS1_VOLT, - .enable_reg = BD957X_REG_POW_TRIGGERS1, - .enable_mask = BD957X_REGULATOR_EN_MASK, - .enable_val = BD957X_REGULATOR_DIS_VAL, - .enable_is_inverted = true, - .owner = THIS_MODULE, + { + .desc = { + .name = "VOUTS1", + .of_match = of_match_ptr("regulator-vouts1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD957X_VOUTS1, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .fixed_uV = BD957X_VOUTS1_VOLT, + .enable_reg = BD957X_REG_POW_TRIGGERS1, + .enable_mask = BD957X_REGULATOR_EN_MASK, + .enable_val = BD957X_REGULATOR_DIS_VAL, + .enable_is_inverted = true, + .owner = THIS_MODULE, + .of_parse_cb = vouts1_get_fet_res, + }, + .oc_supported = true, + .ocw_reg = BD9576_REG_VOUT1S_OCW, + .ocw_mask = BD9576_MASK_VOUT1S_OCW, + .ocp_reg = BD9576_REG_VOUT1S_OCP, + .ocp_mask = BD9576_MASK_VOUT1S_OCP, }, }, }; +static int bd9576_renable(struct regulator_irq_data *rid, int reg, int mask) +{ + int val, ret; + struct bd957x_data *d = (struct bd957x_data *)rid->data; + + ret = regmap_read(d->regmap, reg, &val); + if (ret) + return REGULATOR_FAILED_RETRY; + + if (rid->opaque && rid->opaque == (val & mask)) { + /* + * It seems we stil have same status. Ack and return + * information that we are still out of limits and core + * should not enable IRQ + */ + regmap_write(d->regmap, reg, mask & val); + return REGULATOR_ERROR_ON; + } + rid->opaque = 0; + /* + * Status was changed. Either prolem was solved or we have new issues. + * Let's re-enable IRQs and be prepared to report problems again + */ + return REGULATOR_ERROR_CLEARED; +} + +static int bd9576_uvd_renable(struct regulator_irq_data *rid) +{ + return bd9576_renable(rid, BD957X_REG_INT_UVD_STAT, UVD_IRQ_VALID_MASK); +} + +static int bd9576_ovd_renable(struct regulator_irq_data *rid) +{ + return bd9576_renable(rid, BD957X_REG_INT_OVD_STAT, OVD_IRQ_VALID_MASK); +} + +static int bd9576_temp_renable(struct regulator_irq_data *rid) +{ + return bd9576_renable(rid, BD957X_REG_INT_THERM_STAT, + BD9576_THERM_IRQ_MASK_TW); +} + +static int bd9576_uvd_handler(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int val, ret, i; + struct bd957x_data *d = (struct bd957x_data *)rid->data; + + ret = regmap_read(d->regmap, BD957X_REG_INT_UVD_STAT, &val); + if (ret) + return REGULATOR_FAILED_RETRY; + + *dev_mask = 0; + + rid->opaque = val & UVD_IRQ_VALID_MASK; + + /* + * Go through the set status bits and report either error or warning + * to the notifier depending on what was flagged in DT + */ + *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4; + /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */ + *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1); + /* + * We (ab)use the uvd for OCW notification. DT parsing should + * have added correct OCW flag to uvd_notif and uvd_err for S1 + */ + *dev_mask |= ((val & BD9576_UVD_IRQ_MASK_VOUTS1_OCW) >> 1); + + for_each_set_bit(i, dev_mask, 6) { + struct bd957x_regulator_data *rdata; + struct regulator_err_state *stat; + + rdata = &d->regulator_data[i]; + stat = &rid->states[i]; + + stat->notifs = rdata->uvd_notif; + stat->errors = rdata->uvd_err; + } + + ret = regmap_write(d->regmap, BD957X_REG_INT_UVD_STAT, + UVD_IRQ_VALID_MASK & val); + + return 0; +} + +static int bd9576_ovd_handler(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int val, ret, i; + struct bd957x_data *d = (struct bd957x_data *)rid->data; + + ret = regmap_read(d->regmap, BD957X_REG_INT_OVD_STAT, &val); + if (ret) + return REGULATOR_FAILED_RETRY; + + rid->opaque = val & OVD_IRQ_VALID_MASK; + *dev_mask = 0; + + if (!(val & OVD_IRQ_VALID_MASK)) + return 0; + + *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4; + /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */ + *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1); + + for_each_set_bit(i, dev_mask, 5) { + struct bd957x_regulator_data *rdata; + struct regulator_err_state *stat; + + rdata = &d->regulator_data[i]; + stat = &rid->states[i]; + + stat->notifs = rdata->ovd_notif; + stat->errors = rdata->ovd_err; + } + + /* Clear the sub-IRQ status */ + regmap_write(d->regmap, BD957X_REG_INT_OVD_STAT, + OVD_IRQ_VALID_MASK & val); + + return 0; +} + +#define BD9576_DEV_MASK_ALL_REGULATORS 0x3F + +static int bd9576_thermal_handler(int irq, struct regulator_irq_data *rid, + unsigned long *dev_mask) +{ + int val, ret, i; + struct bd957x_data *d = (struct bd957x_data *)rid->data; + + ret = regmap_read(d->regmap, BD957X_REG_INT_THERM_STAT, &val); + if (ret) + return REGULATOR_FAILED_RETRY; + + if (!(val & BD9576_THERM_IRQ_MASK_TW)) { + *dev_mask = 0; + return 0; + } + + *dev_mask = BD9576_DEV_MASK_ALL_REGULATORS; + + for (i = 0; i < BD9576_NUM_REGULATORS; i++) { + struct bd957x_regulator_data *rdata; + struct regulator_err_state *stat; + + rdata = &d->regulator_data[i]; + stat = &rid->states[i]; + + stat->notifs = rdata->temp_notif; + stat->errors = rdata->temp_err; + } + + /* Clear the sub-IRQ status */ + regmap_write(d->regmap, BD957X_REG_INT_THERM_STAT, + BD9576_THERM_IRQ_MASK_TW); + + return 0; +} + static int bd957x_probe(struct platform_device *pdev) { + int i; + unsigned int num_reg_data; + bool vout_mode, ddr_sel, may_have_irqs = false; struct regmap *regmap; + struct bd957x_data *ic_data; struct regulator_config config = { 0 }; - int i; - bool vout_mode, ddr_sel; - const struct bd957x_regulator_data *reg_data = &bd9576_regulators[0]; - unsigned int num_reg_data = ARRAY_SIZE(bd9576_regulators); + /* All regulators are related to UVD and thermal IRQs... */ + struct regulator_dev *rdevs[BD9576_NUM_REGULATORS]; + /* ...But VoutS1 is not flagged by OVD IRQ */ + struct regulator_dev *ovd_devs[BD9576_NUM_OVD_REGULATORS]; + static const struct regulator_irq_desc bd9576_notif_uvd = { + .name = "bd9576-uvd", + .irq_off_ms = 1000, + .map_event = bd9576_uvd_handler, + .renable = bd9576_uvd_renable, + .data = &bd957x_regulators, + }; + static const struct regulator_irq_desc bd9576_notif_ovd = { + .name = "bd9576-ovd", + .irq_off_ms = 1000, + .map_event = bd9576_ovd_handler, + .renable = bd9576_ovd_renable, + .data = &bd957x_regulators, + }; + static const struct regulator_irq_desc bd9576_notif_temp = { + .name = "bd9576-temp", + .irq_off_ms = 1000, + .map_event = bd9576_thermal_handler, + .renable = bd9576_temp_renable, + .data = &bd957x_regulators, + }; enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; + num_reg_data = ARRAY_SIZE(bd957x_regulators.regulator_data); + + ic_data = &bd957x_regulators; + regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!regmap) { dev_err(&pdev->dev, "No regmap\n"); return -EINVAL; } + + ic_data->regmap = regmap; vout_mode = of_property_read_bool(pdev->dev.parent->of_node, "rohm,vout1-en-low"); if (vout_mode) { @@ -263,15 +985,17 @@ static int bd957x_probe(struct platform_device *pdev) * bytes and use bd9576_regulators directly for non-constant configs * like DDR voltage selection. */ + platform_set_drvdata(pdev, ic_data); ddr_sel = of_property_read_bool(pdev->dev.parent->of_node, "rohm,ddr-sel-low"); if (ddr_sel) - bd9576_regulators[2].desc.fixed_uV = 1350000; + ic_data->regulator_data[2].desc.fixed_uV = 1350000; else - bd9576_regulators[2].desc.fixed_uV = 1500000; + ic_data->regulator_data[2].desc.fixed_uV = 1500000; switch (chip) { case ROHM_CHIP_TYPE_BD9576: + may_have_irqs = true; dev_dbg(&pdev->dev, "Found BD9576MUF\n"); break; case ROHM_CHIP_TYPE_BD9573: @@ -282,38 +1006,122 @@ static int bd957x_probe(struct platform_device *pdev) return -EINVAL; } + for (i = 0; i < num_reg_data; i++) { + struct regulator_desc *d; + + d = &ic_data->regulator_data[i].desc; + + + if (may_have_irqs) { + if (d->id >= ARRAY_SIZE(bd9576_ops_arr)) + return -EINVAL; + + d->ops = bd9576_ops_arr[d->id]; + } else { + if (d->id >= ARRAY_SIZE(bd9573_ops_arr)) + return -EINVAL; + + d->ops = bd9573_ops_arr[d->id]; + } + } + config.dev = pdev->dev.parent; config.regmap = regmap; + config.driver_data = ic_data; for (i = 0; i < num_reg_data; i++) { - const struct regulator_desc *desc; - struct regulator_dev *rdev; - const struct bd957x_regulator_data *r; - - r = ®_data[i]; - desc = &r->desc; + struct bd957x_regulator_data *r = &ic_data->regulator_data[i]; + const struct regulator_desc *desc = &r->desc; - rdev = devm_regulator_register(&pdev->dev, desc, &config); - if (IS_ERR(rdev)) { + r->rdev = devm_regulator_register(&pdev->dev, desc, + &config); + if (IS_ERR(r->rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", desc->name); - return PTR_ERR(rdev); + return PTR_ERR(r->rdev); } /* * Clear the VOUT1 GPIO setting - rest of the regulators do not * support GPIO control */ config.ena_gpiod = NULL; + + if (!may_have_irqs) + continue; + + rdevs[i] = r->rdev; + if (i < BD957X_VOUTS1) + ovd_devs[i] = r->rdev; } + if (may_have_irqs) { + void *ret; + /* + * We can add both the possible error and warning flags here + * because the core uses these only for status clearing and + * if we use warnings - errors are always clear and the other + * way around. We can also add CURRENT flag for all regulators + * because it is never set if it is not supported. Same applies + * to setting UVD for VoutS1 - it is not accidentally cleared + * as it is never set. + */ + int uvd_errs = REGULATOR_ERROR_UNDER_VOLTAGE | + REGULATOR_ERROR_UNDER_VOLTAGE_WARN | + REGULATOR_ERROR_OVER_CURRENT | + REGULATOR_ERROR_OVER_CURRENT_WARN; + int ovd_errs = REGULATOR_ERROR_OVER_VOLTAGE_WARN | + REGULATOR_ERROR_REGULATION_OUT; + int temp_errs = REGULATOR_ERROR_OVER_TEMP | + REGULATOR_ERROR_OVER_TEMP_WARN; + int irq; + + irq = platform_get_irq_byname(pdev, "bd9576-uvd"); + /* Register notifiers - can fail if IRQ is not given */ + ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_uvd, + irq, 0, uvd_errs, NULL, + &rdevs[0], + BD9576_NUM_REGULATORS); + if (IS_ERR(ret)) { + if (PTR_ERR(ret) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(&pdev->dev, "UVD disabled %pe\n", ret); + } + + irq = platform_get_irq_byname(pdev, "bd9576-ovd"); + + ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_ovd, + irq, 0, ovd_errs, NULL, + &ovd_devs[0], + BD9576_NUM_OVD_REGULATORS); + if (IS_ERR(ret)) { + if (PTR_ERR(ret) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(&pdev->dev, "OVD disabled %pe\n", ret); + } + irq = platform_get_irq_byname(pdev, "bd9576-temp"); + + ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_temp, + irq, 0, temp_errs, NULL, + &rdevs[0], + BD9576_NUM_REGULATORS); + if (IS_ERR(ret)) { + if (PTR_ERR(ret) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + dev_warn(&pdev->dev, "Thermal warning disabled %pe\n", + ret); + } + } return 0; } static const struct platform_device_id bd957x_pmic_id[] = { - { "bd9573-pmic", ROHM_CHIP_TYPE_BD9573 }, - { "bd9576-pmic", ROHM_CHIP_TYPE_BD9576 }, + { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 }, + { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 }, { }, }; MODULE_DEVICE_TABLE(platform, bd957x_pmic_id); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e20e77e4c159..ca6caba8a191 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -33,17 +33,6 @@ #include "dummy.h" #include "internal.h" -#define rdev_crit(rdev, fmt, ...) \ - pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) -#define rdev_err(rdev, fmt, ...) \ - pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) -#define rdev_warn(rdev, fmt, ...) \ - pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) -#define rdev_info(rdev, fmt, ...) \ - pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) -#define rdev_dbg(rdev, fmt, ...) \ - pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) - static DEFINE_WW_CLASS(regulator_ww_class); static DEFINE_MUTEX(regulator_nesting_mutex); static DEFINE_MUTEX(regulator_list_mutex); @@ -117,6 +106,7 @@ const char *rdev_get_name(struct regulator_dev *rdev) else return ""; } +EXPORT_SYMBOL_GPL(rdev_get_name); static bool have_full_constraints(void) { @@ -591,8 +581,8 @@ regulator_get_suspend_state_check(struct regulator_dev *rdev, suspend_state_t st return rstate; } -static ssize_t regulator_uV_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t microvolts_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); int uV; @@ -605,16 +595,16 @@ static ssize_t regulator_uV_show(struct device *dev, return uV; return sprintf(buf, "%d\n", uV); } -static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL); +static DEVICE_ATTR_RO(microvolts); -static ssize_t regulator_uA_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t microamps_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev)); } -static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL); +static DEVICE_ATTR_RO(microamps); static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -645,14 +635,14 @@ 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, - struct device_attribute *attr, char *buf) +static ssize_t opmode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return regulator_print_opmode(buf, _regulator_get_mode(rdev)); } -static DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL); +static DEVICE_ATTR_RO(opmode); static ssize_t regulator_print_state(char *buf, int state) { @@ -664,8 +654,8 @@ static ssize_t regulator_print_state(char *buf, int state) return sprintf(buf, "unknown\n"); } -static ssize_t regulator_state_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t state_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); ssize_t ret; @@ -676,10 +666,10 @@ static ssize_t regulator_state_show(struct device *dev, return ret; } -static DEVICE_ATTR(state, 0444, regulator_state_show, NULL); +static DEVICE_ATTR_RO(state); -static ssize_t regulator_status_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); int status; @@ -723,10 +713,10 @@ static ssize_t regulator_status_show(struct device *dev, return sprintf(buf, "%s\n", label); } -static DEVICE_ATTR(status, 0444, regulator_status_show, NULL); +static DEVICE_ATTR_RO(status); -static ssize_t regulator_min_uA_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t min_microamps_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); @@ -735,10 +725,10 @@ static ssize_t regulator_min_uA_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->min_uA); } -static DEVICE_ATTR(min_microamps, 0444, regulator_min_uA_show, NULL); +static DEVICE_ATTR_RO(min_microamps); -static ssize_t regulator_max_uA_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t max_microamps_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); @@ -747,10 +737,10 @@ static ssize_t regulator_max_uA_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->max_uA); } -static DEVICE_ATTR(max_microamps, 0444, regulator_max_uA_show, NULL); +static DEVICE_ATTR_RO(max_microamps); -static ssize_t regulator_min_uV_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t min_microvolts_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); @@ -759,10 +749,10 @@ static ssize_t regulator_min_uV_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->min_uV); } -static DEVICE_ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL); +static DEVICE_ATTR_RO(min_microvolts); -static ssize_t regulator_max_uV_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t max_microvolts_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); @@ -771,10 +761,10 @@ static ssize_t regulator_max_uV_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->max_uV); } -static DEVICE_ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL); +static DEVICE_ATTR_RO(max_microvolts); -static ssize_t regulator_total_uA_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t requested_microamps_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); struct regulator *regulator; @@ -788,7 +778,7 @@ static ssize_t regulator_total_uA_show(struct device *dev, regulator_unlock(rdev); return sprintf(buf, "%d\n", uA); } -static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL); +static DEVICE_ATTR_RO(requested_microamps); static ssize_t num_users_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -813,104 +803,95 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(type); -static ssize_t regulator_suspend_mem_uV_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t suspend_mem_microvolts_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV); } -static DEVICE_ATTR(suspend_mem_microvolts, 0444, - regulator_suspend_mem_uV_show, NULL); +static DEVICE_ATTR_RO(suspend_mem_microvolts); -static ssize_t regulator_suspend_disk_uV_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t suspend_disk_microvolts_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV); } -static DEVICE_ATTR(suspend_disk_microvolts, 0444, - regulator_suspend_disk_uV_show, NULL); +static DEVICE_ATTR_RO(suspend_disk_microvolts); -static ssize_t regulator_suspend_standby_uV_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t suspend_standby_microvolts_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV); } -static DEVICE_ATTR(suspend_standby_microvolts, 0444, - regulator_suspend_standby_uV_show, NULL); +static DEVICE_ATTR_RO(suspend_standby_microvolts); -static ssize_t regulator_suspend_mem_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t suspend_mem_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return regulator_print_opmode(buf, rdev->constraints->state_mem.mode); } -static DEVICE_ATTR(suspend_mem_mode, 0444, - regulator_suspend_mem_mode_show, NULL); +static DEVICE_ATTR_RO(suspend_mem_mode); -static ssize_t regulator_suspend_disk_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t suspend_disk_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return regulator_print_opmode(buf, rdev->constraints->state_disk.mode); } -static DEVICE_ATTR(suspend_disk_mode, 0444, - regulator_suspend_disk_mode_show, NULL); +static DEVICE_ATTR_RO(suspend_disk_mode); -static ssize_t regulator_suspend_standby_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t suspend_standby_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return regulator_print_opmode(buf, rdev->constraints->state_standby.mode); } -static DEVICE_ATTR(suspend_standby_mode, 0444, - regulator_suspend_standby_mode_show, NULL); +static DEVICE_ATTR_RO(suspend_standby_mode); -static ssize_t regulator_suspend_mem_state_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t suspend_mem_state_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return regulator_print_state(buf, rdev->constraints->state_mem.enabled); } -static DEVICE_ATTR(suspend_mem_state, 0444, - regulator_suspend_mem_state_show, NULL); +static DEVICE_ATTR_RO(suspend_mem_state); -static ssize_t regulator_suspend_disk_state_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t suspend_disk_state_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return regulator_print_state(buf, rdev->constraints->state_disk.enabled); } -static DEVICE_ATTR(suspend_disk_state, 0444, - regulator_suspend_disk_state_show, NULL); +static DEVICE_ATTR_RO(suspend_disk_state); -static ssize_t regulator_suspend_standby_state_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t suspend_standby_state_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); return regulator_print_state(buf, rdev->constraints->state_standby.enabled); } -static DEVICE_ATTR(suspend_standby_state, 0444, - regulator_suspend_standby_state_show, NULL); +static DEVICE_ATTR_RO(suspend_standby_state); -static ssize_t regulator_bypass_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t bypass_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); const char *report; @@ -928,8 +909,7 @@ static ssize_t regulator_bypass_show(struct device *dev, return sprintf(buf, "%s\n", report); } -static DEVICE_ATTR(bypass, 0444, - regulator_bypass_show, NULL); +static DEVICE_ATTR_RO(bypass); /* Calculate the new optimum regulator operating mode based on the new total * consumer load. All locks held by caller @@ -1315,6 +1295,52 @@ static int machine_constraints_current(struct regulator_dev *rdev, static int _regulator_do_enable(struct regulator_dev *rdev); +static int notif_set_limit(struct regulator_dev *rdev, + int (*set)(struct regulator_dev *, int, int, bool), + int limit, int severity) +{ + bool enable; + + if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) { + enable = false; + limit = 0; + } else { + enable = true; + } + + if (limit == REGULATOR_NOTIF_LIMIT_ENABLE) + limit = 0; + + return set(rdev, limit, severity, enable); +} + +static int handle_notify_limits(struct regulator_dev *rdev, + int (*set)(struct regulator_dev *, int, int, bool), + struct notification_limit *limits) +{ + int ret = 0; + + if (!set) + return -EOPNOTSUPP; + + if (limits->prot) + ret = notif_set_limit(rdev, set, limits->prot, + REGULATOR_SEVERITY_PROT); + if (ret) + return ret; + + if (limits->err) + ret = notif_set_limit(rdev, set, limits->err, + REGULATOR_SEVERITY_ERR); + if (ret) + return ret; + + if (limits->warn) + ret = notif_set_limit(rdev, set, limits->warn, + REGULATOR_SEVERITY_WARN); + + return ret; +} /** * set_machine_constraints - sets regulator constraints * @rdev: regulator source @@ -1400,9 +1426,27 @@ static int set_machine_constraints(struct regulator_dev *rdev) } } + /* + * Existing logic does not warn if over_current_protection is given as + * a constraint but driver does not support that. I think we should + * warn about this type of issues as it is possible someone changes + * PMIC on board to another type - and the another PMIC's driver does + * not support setting protection. Board composer may happily believe + * the DT limits are respected - especially if the new PMIC HW also + * supports protection but the driver does not. I won't change the logic + * without hearing more experienced opinion on this though. + * + * If warning is seen as a good idea then we can merge handling the + * over-curret protection and detection and get rid of this special + * handling. + */ if (rdev->constraints->over_current_protection && ops->set_over_current_protection) { - ret = ops->set_over_current_protection(rdev); + int lim = rdev->constraints->over_curr_limits.prot; + + ret = ops->set_over_current_protection(rdev, lim, + REGULATOR_SEVERITY_PROT, + true); if (ret < 0) { rdev_err(rdev, "failed to set over current protection: %pe\n", ERR_PTR(ret)); @@ -1410,6 +1454,62 @@ static int set_machine_constraints(struct regulator_dev *rdev) } } + if (rdev->constraints->over_current_detection) + ret = handle_notify_limits(rdev, + ops->set_over_current_protection, + &rdev->constraints->over_curr_limits); + if (ret) { + if (ret != -EOPNOTSUPP) { + rdev_err(rdev, "failed to set over current limits: %pe\n", + ERR_PTR(ret)); + return ret; + } + rdev_warn(rdev, + "IC does not support requested over-current limits\n"); + } + + if (rdev->constraints->over_voltage_detection) + ret = handle_notify_limits(rdev, + ops->set_over_voltage_protection, + &rdev->constraints->over_voltage_limits); + if (ret) { + if (ret != -EOPNOTSUPP) { + rdev_err(rdev, "failed to set over voltage limits %pe\n", + ERR_PTR(ret)); + return ret; + } + rdev_warn(rdev, + "IC does not support requested over voltage limits\n"); + } + + if (rdev->constraints->under_voltage_detection) + ret = handle_notify_limits(rdev, + ops->set_under_voltage_protection, + &rdev->constraints->under_voltage_limits); + if (ret) { + if (ret != -EOPNOTSUPP) { + rdev_err(rdev, "failed to set under voltage limits %pe\n", + ERR_PTR(ret)); + return ret; + } + rdev_warn(rdev, + "IC does not support requested under voltage limits\n"); + } + + if (rdev->constraints->over_temp_detection) + ret = handle_notify_limits(rdev, + ops->set_thermal_protection, + &rdev->constraints->temp_limits); + if (ret) { + if (ret != -EOPNOTSUPP) { + rdev_err(rdev, "failed to set temperature limits %pe\n", + ERR_PTR(ret)); + return ret; + } + rdev_warn(rdev, + "IC does not support requested temperature limits\n"); + } + if (rdev->constraints->active_discharge && ops->set_active_discharge) { bool ad_state = (rdev->constraints->active_discharge == REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false; @@ -4111,6 +4211,29 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel); +int regulator_sync_voltage_rdev(struct regulator_dev *rdev) +{ + int ret; + + regulator_lock(rdev); + + if (!rdev->desc->ops->set_voltage && + !rdev->desc->ops->set_voltage_sel) { + ret = -EINVAL; + goto out; + } + + /* balance only, if regulator is coupled */ + if (rdev->coupling_desc.n_coupled > 1) + ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); + else + ret = -EOPNOTSUPP; + +out: + regulator_unlock(rdev); + return ret; +} + /** * regulator_sync_voltage - re-apply last regulator output voltage * @regulator: regulator source @@ -4386,22 +4509,36 @@ unsigned int regulator_get_mode(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_get_mode); +static int rdev_get_cached_err_flags(struct regulator_dev *rdev) +{ + int ret = 0; + + if (rdev->use_cached_err) { + spin_lock(&rdev->err_lock); + ret = rdev->cached_err; + spin_unlock(&rdev->err_lock); + } + return ret; +} + static int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) { - int ret; + int cached_flags, ret = 0; regulator_lock(rdev); - /* sanity check */ - if (!rdev->desc->ops->get_error_flags) { + cached_flags = rdev_get_cached_err_flags(rdev); + + if (rdev->desc->ops->get_error_flags) + ret = rdev->desc->ops->get_error_flags(rdev, flags); + else if (!rdev->use_cached_err) ret = -EINVAL; - goto out; - } - ret = rdev->desc->ops->get_error_flags(rdev, flags); -out: + *flags |= cached_flags; + regulator_unlock(rdev); + return ret; } @@ -5234,6 +5371,7 @@ regulator_register(const struct regulator_desc *regulator_desc, goto rinse; } device_initialize(&rdev->dev); + spin_lock_init(&rdev->err_lock); /* * Duplicate the config so the driver could override it after diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index e18d291c7f21..23fa429ebe76 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -250,7 +250,8 @@ static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev, case DA9052_ID_BUCK3: case DA9052_ID_LDO2: case DA9052_ID_LDO3: - ret = (new_sel - old_sel) * info->step_uV / 6250; + ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV, + 6250); break; } diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index 3091210889e3..a8de0aa88bad 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c @@ -481,3 +481,55 @@ void devm_regulator_unregister_notifier(struct regulator *regulator, WARN_ON(rc); } EXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier); + +static void regulator_irq_helper_drop(void *res) +{ + regulator_irq_helper_cancel(&res); +} + +/** + * devm_regulator_irq_helper - resource managed registration of IRQ based + * regulator event/error notifier + * + * @dev: device to which lifetime the helper's lifetime is + * bound. + * @d: IRQ helper descriptor. + * @irq: IRQ used to inform events/errors to be notified. + * @irq_flags: Extra IRQ flags to be OR'ed with the default + * IRQF_ONESHOT when requesting the (threaded) irq. + * @common_errs: Errors which can be flagged by this IRQ for all rdevs. + * When IRQ is re-enabled these errors will be cleared + * from all associated regulators + * @per_rdev_errs: Optional error flag array describing errors specific + * for only some of the regulators. These errors will be + * or'ed with common errors. If this is given the array + * should contain rdev_amount flags. Can be set to NULL + * if there is no regulator specific error flags for this + * IRQ. + * @rdev: Array of pointers to regulators associated with this + * IRQ. + * @rdev_amount: Amount of regulators associated with this IRQ. + * + * Return: handle to irq_helper or an ERR_PTR() encoded error code. + */ +void *devm_regulator_irq_helper(struct device *dev, + const struct regulator_irq_desc *d, int irq, + int irq_flags, int common_errs, + int *per_rdev_errs, + struct regulator_dev **rdev, int rdev_amount) +{ + void *ptr; + int ret; + + ptr = regulator_irq_helper(dev, d, irq, irq_flags, common_errs, + per_rdev_errs, rdev, rdev_amount); + if (IS_ERR(ptr)) + return ptr; + + ret = devm_add_action_or_reset(dev, regulator_irq_helper_drop, ptr); + if (ret) + return ERR_PTR(ret); + + return ptr; +} +EXPORT_SYMBOL_GPL(devm_regulator_irq_helper); diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 26f06f685b1b..dac1fb584fa3 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -56,7 +56,6 @@ #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ #define FAN53526_NVOLTAGES 128 -#define TCS_VSEL_NSEL_MASK 0x7f #define TCS_VSEL0_MODE (1 << 7) #define TCS_VSEL1_MODE (1 << 6) @@ -67,7 +66,7 @@ enum fan53555_vendor { FAN53526_VENDOR_FAIRCHILD = 0, FAN53555_VENDOR_FAIRCHILD, FAN53555_VENDOR_SILERGY, - FAN53555_VENDOR_TCS, + FAN53526_VENDOR_TCS, }; enum { @@ -89,6 +88,14 @@ enum { FAN53555_CHIP_ID_08 = 8, }; +enum { + TCS4525_CHIP_ID_12 = 12, +}; + +enum { + TCS4526_CHIP_ID_00 = 0, +}; + /* IC mask revision */ enum { FAN53555_CHIP_REV_00 = 0x3, @@ -123,7 +130,8 @@ struct fan53555_device_info { /* Slew rate */ unsigned int slew_reg; unsigned int slew_mask; - unsigned int slew_shift; + const unsigned int *ramp_delay_table; + unsigned int n_ramp_values; unsigned int slew_rate; }; @@ -197,7 +205,7 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev) return REGULATOR_MODE_NORMAL; } -static const int slew_rates[] = { +static const unsigned int slew_rates[] = { 64000, 32000, 16000, @@ -208,51 +216,13 @@ static const int slew_rates[] = { 500, }; -static const int tcs_slew_rates[] = { +static const unsigned int tcs_slew_rates[] = { 18700, 9300, 4600, 2300, }; -static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) -{ - struct fan53555_device_info *di = rdev_get_drvdata(rdev); - int regval = -1, i; - const int *slew_rate_t; - int slew_rate_n; - - switch (di->vendor) { - case FAN53526_VENDOR_FAIRCHILD: - case FAN53555_VENDOR_FAIRCHILD: - case FAN53555_VENDOR_SILERGY: - slew_rate_t = slew_rates; - slew_rate_n = ARRAY_SIZE(slew_rates); - break; - case FAN53555_VENDOR_TCS: - slew_rate_t = tcs_slew_rates; - slew_rate_n = ARRAY_SIZE(tcs_slew_rates); - break; - default: - return -EINVAL; - } - - for (i = 0; i < slew_rate_n; i++) { - if (ramp <= slew_rate_t[i]) - regval = i; - else - break; - } - - if (regval < 0) { - dev_err(di->dev, "unsupported ramp value %d\n", ramp); - return -EINVAL; - } - - return regmap_update_bits(rdev->regmap, di->slew_reg, - di->slew_mask, regval << di->slew_shift); -} - static const struct regulator_ops fan53555_regulator_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -265,7 +235,7 @@ static const struct regulator_ops fan53555_regulator_ops = { .is_enabled = regulator_is_enabled_regmap, .set_mode = fan53555_set_mode, .get_mode = fan53555_get_mode, - .set_ramp_delay = fan53555_set_ramp, + .set_ramp_delay = regulator_set_ramp_delay_regmap, .set_suspend_enable = fan53555_set_suspend_enable, .set_suspend_disable = fan53555_set_suspend_disable, }; @@ -293,6 +263,10 @@ static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di) return -EINVAL; } + di->slew_reg = FAN53555_CONTROL; + di->slew_mask = CTL_SLEW_MASK; + di->ramp_delay_table = slew_rates; + di->n_ramp_values = ARRAY_SIZE(slew_rates); di->vsel_count = FAN53526_NVOLTAGES; return 0; @@ -337,7 +311,8 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) } di->slew_reg = FAN53555_CONTROL; di->slew_mask = CTL_SLEW_MASK; - di->slew_shift = CTL_SLEW_SHIFT; + di->ramp_delay_table = slew_rates; + di->n_ramp_values = ARRAY_SIZE(slew_rates); di->vsel_count = FAN53555_NVOLTAGES; return 0; @@ -358,24 +333,33 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) return -EINVAL; } di->slew_reg = FAN53555_CONTROL; - di->slew_reg = FAN53555_CONTROL; di->slew_mask = CTL_SLEW_MASK; - di->slew_shift = CTL_SLEW_SHIFT; + di->ramp_delay_table = slew_rates; + di->n_ramp_values = ARRAY_SIZE(slew_rates); di->vsel_count = FAN53555_NVOLTAGES; return 0; } -static int fan53555_voltages_setup_tcs(struct fan53555_device_info *di) +static int fan53526_voltages_setup_tcs(struct fan53555_device_info *di) { - di->slew_reg = TCS4525_TIME; - di->slew_mask = TCS_SLEW_MASK; - di->slew_shift = TCS_SLEW_MASK; - - /* Init voltage range and step */ - di->vsel_min = 600000; - di->vsel_step = 6250; - di->vsel_count = FAN53526_NVOLTAGES; + switch (di->chip_id) { + case TCS4525_CHIP_ID_12: + case TCS4526_CHIP_ID_00: + di->slew_reg = TCS4525_TIME; + di->slew_mask = TCS_SLEW_MASK; + di->ramp_delay_table = tcs_slew_rates; + di->n_ramp_values = ARRAY_SIZE(tcs_slew_rates); + + /* Init voltage range and step */ + di->vsel_min = 600000; + di->vsel_step = 6250; + di->vsel_count = FAN53526_NVOLTAGES; + break; + default: + dev_err(di->dev, "Chip ID %d not supported!\n", di->chip_id); + return -EINVAL; + } return 0; } @@ -409,7 +393,7 @@ static int fan53555_device_setup(struct fan53555_device_info *di, return -EINVAL; } break; - case FAN53555_VENDOR_TCS: + case FAN53526_VENDOR_TCS: switch (pdata->sleep_vsel_id) { case FAN53555_VSEL_ID_0: di->sleep_reg = TCS4525_VSEL0; @@ -448,7 +432,7 @@ static int fan53555_device_setup(struct fan53555_device_info *di, di->mode_reg = di->vol_reg; di->mode_mask = VSEL_MODE; break; - case FAN53555_VENDOR_TCS: + case FAN53526_VENDOR_TCS: di->mode_reg = TCS4525_COMMAND; switch (pdata->sleep_vsel_id) { @@ -476,8 +460,8 @@ static int fan53555_device_setup(struct fan53555_device_info *di, case FAN53555_VENDOR_SILERGY: ret = fan53555_voltages_setup_silergy(di); break; - case FAN53555_VENDOR_TCS: - ret = fan53555_voltages_setup_tcs(di); + case FAN53526_VENDOR_TCS: + ret = fan53526_voltages_setup_tcs(di); break; default: dev_err(di->dev, "vendor %d not supported!\n", di->vendor); @@ -504,6 +488,10 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, rdesc->uV_step = di->vsel_step; rdesc->vsel_reg = di->vol_reg; rdesc->vsel_mask = di->vsel_count - 1; + rdesc->ramp_reg = di->slew_reg; + rdesc->ramp_mask = di->slew_mask; + rdesc->ramp_delay_table = di->ramp_delay_table; + rdesc->n_ramp_values = di->n_ramp_values; rdesc->owner = THIS_MODULE; rdev = devm_regulator_register(di->dev, &di->desc, config); @@ -552,7 +540,10 @@ static const struct of_device_id __maybe_unused fan53555_dt_ids[] = { .data = (void *)FAN53555_VENDOR_SILERGY, }, { .compatible = "tcs,tcs4525", - .data = (void *)FAN53555_VENDOR_TCS + .data = (void *)FAN53526_VENDOR_TCS + }, { + .compatible = "tcs,tcs4526", + .data = (void *)FAN53526_VENDOR_TCS }, { } }; @@ -660,7 +651,10 @@ static const struct i2c_device_id fan53555_id[] = { .driver_data = FAN53555_VENDOR_SILERGY }, { .name = "tcs4525", - .driver_data = FAN53555_VENDOR_TCS + .driver_data = FAN53526_VENDOR_TCS + }, { + .name = "tcs4526", + .driver_data = FAN53526_VENDOR_TCS }, { }, }; diff --git a/drivers/regulator/fan53880.c b/drivers/regulator/fan53880.c index 1684faf82ed2..8f25930d2769 100644 --- a/drivers/regulator/fan53880.c +++ b/drivers/regulator/fan53880.c @@ -79,7 +79,7 @@ static const struct regulator_desc fan53880_regulators[] = { .n_linear_ranges = 2, .n_voltages = 0xf8, .vsel_reg = FAN53880_BUCKVOUT, - .vsel_mask = 0x7f, + .vsel_mask = 0xff, .enable_reg = FAN53880_ENABLE, .enable_mask = 0x10, .enable_time = 480, @@ -114,8 +114,7 @@ static const struct regmap_config fan53880_regmap = { .max_register = FAN53880_ENABLE_BOOST, }; -static int fan53880_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int fan53880_i2c_probe(struct i2c_client *i2c) { struct regulator_config config = { }; struct regulator_dev *rdev; @@ -177,7 +176,7 @@ static struct i2c_driver fan53880_regulator_driver = { .name = "fan53880", .of_match_table = of_match_ptr(fan53880_dt_ids), }, - .probe = fan53880_i2c_probe, + .probe_new = fan53880_i2c_probe, .id_table = fan53880_i2c_id, }; module_i2c_driver(fan53880_regulator_driver); diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 34e255c235d4..39284610a536 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -276,7 +276,8 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) */ cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags); if (IS_ERR(cfg.ena_gpiod)) - return PTR_ERR(cfg.ena_gpiod); + return dev_err_probe(&pdev->dev, PTR_ERR(cfg.ena_gpiod), + "can't get GPIO\n"); cfg.dev = &pdev->dev; cfg.init_data = config->init_data; diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c index dc631c1a46b4..bff8c515dcde 100644 --- a/drivers/regulator/hi6421-regulator.c +++ b/drivers/regulator/hi6421-regulator.c @@ -386,7 +386,7 @@ static int hi6421_regulator_enable(struct regulator_dev *rdev) static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev) { struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); - u32 reg_val; + unsigned int reg_val; regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val); if (reg_val & info->mode_mask) @@ -398,7 +398,7 @@ static unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev) static unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev) { struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); - u32 reg_val; + unsigned int reg_val; regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val); if (reg_val & info->mode_mask) @@ -411,7 +411,7 @@ static int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); - u32 new_mode; + unsigned int new_mode; switch (mode) { case REGULATOR_MODE_NORMAL: @@ -435,7 +435,7 @@ static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct hi6421_regulator_info *info = rdev_get_drvdata(rdev); - u32 new_mode; + unsigned int new_mode; switch (mode) { case REGULATOR_MODE_NORMAL: diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c index d6340bb49296..9b162c0555c3 100644 --- a/drivers/regulator/hi6421v600-regulator.c +++ b/drivers/regulator/hi6421v600-regulator.c @@ -16,14 +16,15 @@ #include <linux/regulator/driver.h> #include <linux/spmi.h> +struct hi6421_spmi_reg_priv { + /* Serialize regulator enable logic */ + struct mutex enable_mutex; +}; + struct hi6421_spmi_reg_info { struct regulator_desc desc; - struct hi6421_spmi_pmic *pmic; u8 eco_mode_mask; u32 eco_uA; - - /* Serialize regulator enable logic */ - struct mutex enable_mutex; }; static const unsigned int ldo3_voltages[] = { @@ -97,41 +98,31 @@ static const unsigned int ldo34_voltages[] = { static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev) { - struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; + struct hi6421_spmi_reg_priv *priv; int ret; + priv = dev_get_drvdata(rdev->dev.parent); /* cannot enable more than one regulator at one time */ - mutex_lock(&sreg->enable_mutex); + mutex_lock(&priv->enable_mutex); - ret = regmap_update_bits(pmic->regmap, rdev->desc->enable_reg, + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, rdev->desc->enable_mask, rdev->desc->enable_mask); /* Avoid powering up multiple devices at the same time */ usleep_range(rdev->desc->off_on_delay, rdev->desc->off_on_delay + 60); - mutex_unlock(&sreg->enable_mutex); + mutex_unlock(&priv->enable_mutex); return ret; } -static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev) -{ - struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - - return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, 0); -} - static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev) { struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - u32 reg_val; + unsigned int reg_val; - regmap_read(pmic->regmap, rdev->desc->enable_reg, ®_val); + regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val); if (reg_val & sreg->eco_mode_mask) return REGULATOR_MODE_IDLE; @@ -143,21 +134,23 @@ static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct hi6421_spmi_reg_info *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - u32 val; + unsigned int val; switch (mode) { case REGULATOR_MODE_NORMAL: val = 0; break; case REGULATOR_MODE_IDLE: - val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1); + if (!sreg->eco_mode_mask) + return -EINVAL; + + val = sreg->eco_mode_mask; break; default: return -EINVAL; } - return regmap_update_bits(pmic->regmap, rdev->desc->enable_reg, + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, sreg->eco_mode_mask, val); } @@ -177,9 +170,9 @@ hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev, static const struct regulator_ops hi6421_spmi_ldo_rops = { .is_enabled = regulator_is_enabled_regmap, .enable = hi6421_spmi_regulator_enable, - .disable = hi6421_spmi_regulator_disable, + .disable = regulator_disable_regmap, .list_voltage = regulator_list_voltage_table, - .map_voltage = regulator_map_voltage_iterate, + .map_voltage = regulator_map_voltage_ascend, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_mode = hi6421_spmi_regulator_get_mode, @@ -238,7 +231,7 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) { struct device *pmic_dev = pdev->dev.parent; struct regulator_config config = { }; - struct hi6421_spmi_reg_info *sreg; + struct hi6421_spmi_reg_priv *priv; struct hi6421_spmi_reg_info *info; struct device *dev = &pdev->dev; struct hi6421_spmi_pmic *pmic; @@ -254,18 +247,18 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) if (WARN_ON(!pmic)) return -ENODEV; - sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); - if (!sreg) + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - sreg->pmic = pmic; - mutex_init(&sreg->enable_mutex); + mutex_init(&priv->enable_mutex); + platform_set_drvdata(pdev, priv); for (i = 0; i < ARRAY_SIZE(regulator_info); i++) { info = ®ulator_info[i]; config.dev = pdev->dev.parent; - config.driver_data = sreg; + config.driver_data = info; config.regmap = pmic->regmap; rdev = devm_regulator_register(dev, &info->desc, &config); diff --git a/drivers/regulator/hi655x-regulator.c b/drivers/regulator/hi655x-regulator.c index 68cdb173196d..556bb73f3329 100644 --- a/drivers/regulator/hi655x-regulator.c +++ b/drivers/regulator/hi655x-regulator.c @@ -72,7 +72,7 @@ enum hi655x_regulator_id { static int hi655x_is_enabled(struct regulator_dev *rdev) { unsigned int value = 0; - struct hi655x_regulator *regulator = rdev_get_drvdata(rdev); + const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev); regmap_read(rdev->regmap, regulator->status_reg, &value); return (value & rdev->desc->enable_mask); @@ -80,7 +80,7 @@ static int hi655x_is_enabled(struct regulator_dev *rdev) static int hi655x_disable(struct regulator_dev *rdev) { - struct hi655x_regulator *regulator = rdev_get_drvdata(rdev); + const struct hi655x_regulator *regulator = rdev_get_drvdata(rdev); return regmap_write(rdev->regmap, regulator->disable_reg, rdev->desc->enable_mask); @@ -169,7 +169,6 @@ static const struct hi655x_regulator regulators[] = { static int hi655x_regulator_probe(struct platform_device *pdev) { unsigned int i; - struct hi655x_regulator *regulator; struct hi655x_pmic *pmic; struct regulator_config config = { }; struct regulator_dev *rdev; @@ -180,22 +179,17 @@ static int hi655x_regulator_probe(struct platform_device *pdev) return -ENODEV; } - regulator = devm_kzalloc(&pdev->dev, sizeof(*regulator), GFP_KERNEL); - if (!regulator) - return -ENOMEM; - - platform_set_drvdata(pdev, regulator); - config.dev = pdev->dev.parent; config.regmap = pmic->regmap; - config.driver_data = regulator; for (i = 0; i < ARRAY_SIZE(regulators); i++) { + config.driver_data = (void *) ®ulators[i]; + rdev = devm_regulator_register(&pdev->dev, ®ulators[i].rdesc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", - regulator->rdesc.name); + regulators[i].rdesc.name); return PTR_ERR(rdev); } } diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index 2391b565ef11..1e9c71642143 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -15,6 +15,17 @@ #define REGULATOR_STATES_NUM (PM_SUSPEND_MAX + 1) +#define rdev_crit(rdev, fmt, ...) \ + pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_err(rdev, fmt, ...) \ + pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_warn(rdev, fmt, ...) \ + pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_info(rdev, fmt, ...) \ + pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_dbg(rdev, fmt, ...) \ + pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) + struct regulator_voltage { int min_uV; int max_uV; diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c new file mode 100644 index 000000000000..fabe2e53093e --- /dev/null +++ b/drivers/regulator/irq_helpers.c @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2021 ROHM Semiconductors +// regulator IRQ based event notification helpers +// +// Logic has been partially adapted from qcom-labibb driver. +// +// Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/reboot.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/regulator/driver.h> + +#include "internal.h" + +#define REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS 10000 + +struct regulator_irq { + struct regulator_irq_data rdata; + struct regulator_irq_desc desc; + int irq; + int retry_cnt; + struct delayed_work isr_work; +}; + +/* + * Should only be called from threaded handler to prevent potential deadlock + */ +static void rdev_flag_err(struct regulator_dev *rdev, int err) +{ + spin_lock(&rdev->err_lock); + rdev->cached_err |= err; + spin_unlock(&rdev->err_lock); +} + +static void rdev_clear_err(struct regulator_dev *rdev, int err) +{ + spin_lock(&rdev->err_lock); + rdev->cached_err &= ~err; + spin_unlock(&rdev->err_lock); +} + +static void regulator_notifier_isr_work(struct work_struct *work) +{ + struct regulator_irq *h; + struct regulator_irq_desc *d; + struct regulator_irq_data *rid; + int ret = 0; + int tmo, i; + int num_rdevs; + + h = container_of(work, struct regulator_irq, + isr_work.work); + d = &h->desc; + rid = &h->rdata; + num_rdevs = rid->num_states; + +reread: + if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) { + if (!d->die) + return hw_protection_shutdown("Regulator HW failure? - no IC recovery", + REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS); + ret = d->die(rid); + /* + * If the 'last resort' IC recovery failed we will have + * nothing else left to do... + */ + if (ret) + return hw_protection_shutdown("Regulator HW failure. IC recovery failed", + REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS); + + /* + * If h->die() was implemented we assume recovery has been + * attempted (probably regulator was shut down) and we + * just enable IRQ and bail-out. + */ + goto enable_out; + } + if (d->renable) { + ret = d->renable(rid); + + if (ret == REGULATOR_FAILED_RETRY) { + /* Driver could not get current status */ + h->retry_cnt++; + if (!d->reread_ms) + goto reread; + + tmo = d->reread_ms; + goto reschedule; + } + + if (ret) { + /* + * IC status reading succeeded. update error info + * just in case the renable changed it. + */ + for (i = 0; i < num_rdevs; i++) { + struct regulator_err_state *stat; + struct regulator_dev *rdev; + + stat = &rid->states[i]; + rdev = stat->rdev; + rdev_clear_err(rdev, (~stat->errors) & + stat->possible_errs); + } + h->retry_cnt++; + /* + * The IC indicated problem is still ON - no point in + * re-enabling the IRQ. Retry later. + */ + tmo = d->irq_off_ms; + goto reschedule; + } + } + + /* + * Either IC reported problem cleared or no status checker was provided. + * If problems are gone - good. If not - then the IRQ will fire again + * and we'll have a new nice loop. In any case we should clear error + * flags here and re-enable IRQs. + */ + for (i = 0; i < num_rdevs; i++) { + struct regulator_err_state *stat; + struct regulator_dev *rdev; + + stat = &rid->states[i]; + rdev = stat->rdev; + rdev_clear_err(rdev, stat->possible_errs); + } + + /* + * Things have been seemingly successful => zero retry-counter. + */ + h->retry_cnt = 0; + +enable_out: + enable_irq(h->irq); + + return; + +reschedule: + if (!d->high_prio) + mod_delayed_work(system_wq, &h->isr_work, + msecs_to_jiffies(tmo)); + else + mod_delayed_work(system_highpri_wq, &h->isr_work, + msecs_to_jiffies(tmo)); +} + +static irqreturn_t regulator_notifier_isr(int irq, void *data) +{ + struct regulator_irq *h = data; + struct regulator_irq_desc *d; + struct regulator_irq_data *rid; + unsigned long rdev_map = 0; + int num_rdevs; + int ret, i; + + d = &h->desc; + rid = &h->rdata; + num_rdevs = rid->num_states; + + if (d->fatal_cnt) + h->retry_cnt++; + + /* + * we spare a few cycles by not clearing statuses prior to this call. + * The IC driver must initialize the status buffers for rdevs + * which it indicates having active events via rdev_map. + * + * Maybe we should just to be on a safer side(?) + */ + ret = d->map_event(irq, rid, &rdev_map); + + /* + * If status reading fails (which is unlikely) we don't ack/disable + * IRQ but just increase fail count and retry when IRQ fires again. + * If retry_count exceeds the given safety limit we call IC specific die + * handler which can try disabling regulator(s). + * + * If no die handler is given we will just bug() as a last resort. + * + * We could try disabling all associated rdevs - but we might shoot + * ourselves in the head and leave the problematic regulator enabled. So + * if IC has no die-handler populated we just assume the regulator + * can't be disabled. + */ + if (unlikely(ret == REGULATOR_FAILED_RETRY)) + goto fail_out; + + h->retry_cnt = 0; + /* + * Let's not disable IRQ if there were no status bits for us. We'd + * better leave spurious IRQ handling to genirq + */ + if (ret || !rdev_map) + return IRQ_NONE; + + /* + * Some events are bogus if the regulator is disabled. Skip such events + * if all relevant regulators are disabled + */ + if (d->skip_off) { + for_each_set_bit(i, &rdev_map, num_rdevs) { + struct regulator_dev *rdev; + const struct regulator_ops *ops; + + rdev = rid->states[i].rdev; + ops = rdev->desc->ops; + + /* + * If any of the flagged regulators is enabled we do + * handle this + */ + if (ops->is_enabled(rdev)) + break; + } + if (i == num_rdevs) + return IRQ_NONE; + } + + /* Disable IRQ if HW keeps line asserted */ + if (d->irq_off_ms) + disable_irq_nosync(irq); + + /* + * IRQ seems to be for us. Let's fire correct notifiers / store error + * flags + */ + for_each_set_bit(i, &rdev_map, num_rdevs) { + struct regulator_err_state *stat; + struct regulator_dev *rdev; + + stat = &rid->states[i]; + rdev = stat->rdev; + + rdev_dbg(rdev, "Sending regulator notification EVT 0x%lx\n", + stat->notifs); + + regulator_notifier_call_chain(rdev, stat->notifs, NULL); + rdev_flag_err(rdev, stat->errors); + } + + if (d->irq_off_ms) { + if (!d->high_prio) + schedule_delayed_work(&h->isr_work, + msecs_to_jiffies(d->irq_off_ms)); + else + mod_delayed_work(system_highpri_wq, + &h->isr_work, + msecs_to_jiffies(d->irq_off_ms)); + } + + return IRQ_HANDLED; + +fail_out: + if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) { + /* If we have no recovery, just try shut down straight away */ + if (!d->die) { + hw_protection_shutdown("Regulator failure. Retry count exceeded", + REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS); + } else { + ret = d->die(rid); + /* If die() failed shut down as a last attempt to save the HW */ + if (ret) + hw_protection_shutdown("Regulator failure. Recovery failed", + REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS); + } + } + + return IRQ_NONE; +} + +static int init_rdev_state(struct device *dev, struct regulator_irq *h, + struct regulator_dev **rdev, int common_err, + int *rdev_err, int rdev_amount) +{ + int i; + + h->rdata.states = devm_kzalloc(dev, sizeof(*h->rdata.states) * + rdev_amount, GFP_KERNEL); + if (!h->rdata.states) + return -ENOMEM; + + h->rdata.num_states = rdev_amount; + h->rdata.data = h->desc.data; + + for (i = 0; i < rdev_amount; i++) { + h->rdata.states[i].possible_errs = common_err; + if (rdev_err) + h->rdata.states[i].possible_errs |= *rdev_err++; + h->rdata.states[i].rdev = *rdev++; + } + + return 0; +} + +static void init_rdev_errors(struct regulator_irq *h) +{ + int i; + + for (i = 0; i < h->rdata.num_states; i++) + if (h->rdata.states[i].possible_errs) + h->rdata.states[i].rdev->use_cached_err = true; +} + +/** + * regulator_irq_helper - register IRQ based regulator event/error notifier + * + * @dev: device providing the IRQs + * @d: IRQ helper descriptor. + * @irq: IRQ used to inform events/errors to be notified. + * @irq_flags: Extra IRQ flags to be OR'ed with the default + * IRQF_ONESHOT when requesting the (threaded) irq. + * @common_errs: Errors which can be flagged by this IRQ for all rdevs. + * When IRQ is re-enabled these errors will be cleared + * from all associated regulators + * @per_rdev_errs: Optional error flag array describing errors specific + * for only some of the regulators. These errors will be + * or'ed with common errors. If this is given the array + * should contain rdev_amount flags. Can be set to NULL + * if there is no regulator specific error flags for this + * IRQ. + * @rdev: Array of pointers to regulators associated with this + * IRQ. + * @rdev_amount: Amount of regulators associated with this IRQ. + * + * Return: handle to irq_helper or an ERR_PTR() encoded error code. + */ +void *regulator_irq_helper(struct device *dev, + const struct regulator_irq_desc *d, int irq, + int irq_flags, int common_errs, int *per_rdev_errs, + struct regulator_dev **rdev, int rdev_amount) +{ + struct regulator_irq *h; + int ret; + + if (!rdev_amount || !d || !d->map_event || !d->name) + return ERR_PTR(-EINVAL); + + h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL); + if (!h) + return ERR_PTR(-ENOMEM); + + h->irq = irq; + h->desc = *d; + + ret = init_rdev_state(dev, h, rdev, common_errs, per_rdev_errs, + rdev_amount); + if (ret) + return ERR_PTR(ret); + + init_rdev_errors(h); + + if (h->desc.irq_off_ms) + INIT_DELAYED_WORK(&h->isr_work, regulator_notifier_isr_work); + + ret = request_threaded_irq(h->irq, NULL, regulator_notifier_isr, + IRQF_ONESHOT | irq_flags, h->desc.name, h); + if (ret) { + dev_err(dev, "Failed to request IRQ %d\n", irq); + + return ERR_PTR(ret); + } + + return h; +} +EXPORT_SYMBOL_GPL(regulator_irq_helper); + +/** + * regulator_irq_helper_cancel - drop IRQ based regulator event/error notifier + * + * @handle: Pointer to handle returned by a successful call to + * regulator_irq_helper(). Will be NULLed upon return. + * + * The associated IRQ is released and work is cancelled when the function + * returns. + */ +void regulator_irq_helper_cancel(void **handle) +{ + if (handle && *handle) { + struct regulator_irq *h = *handle; + + free_irq(h->irq, h); + if (h->desc.irq_off_ms) + cancel_delayed_work_sync(&h->isr_work); + + h = NULL; + } +} +EXPORT_SYMBOL_GPL(regulator_irq_helper_cancel); diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c index 13c535711265..321bec6e3f8d 100644 --- a/drivers/regulator/lp8755.c +++ b/drivers/regulator/lp8755.c @@ -136,52 +136,9 @@ err_i2c: return 0; } -static int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp) -{ - int ret; - unsigned int regval = 0x00; - enum lp8755_bucks id = rdev_get_id(rdev); - - /* uV/us */ - switch (ramp) { - case 0 ... 230: - regval = 0x07; - break; - case 231 ... 470: - regval = 0x06; - break; - case 471 ... 940: - regval = 0x05; - break; - case 941 ... 1900: - regval = 0x04; - break; - case 1901 ... 3800: - regval = 0x03; - break; - case 3801 ... 7500: - regval = 0x02; - break; - case 7501 ... 15000: - regval = 0x01; - break; - case 15001 ... 30000: - regval = 0x00; - break; - default: - dev_err(&rdev->dev, - "Not supported ramp value %d %s\n", ramp, __func__); - return -EINVAL; - } - - ret = regmap_update_bits(rdev->regmap, 0x07 + id, 0x07, regval); - if (ret < 0) - goto err_i2c; - return ret; -err_i2c: - dev_err(&rdev->dev, "i2c access error %s\n", __func__); - return ret; -} +static const unsigned int lp8755_buck_ramp_table[] = { + 30000, 15000, 7500, 3800, 1900, 940, 470, 230 +}; static const struct regulator_ops lp8755_buck_ops = { .map_voltage = regulator_map_voltage_linear, @@ -194,7 +151,7 @@ static const struct regulator_ops lp8755_buck_ops = { .enable_time = lp8755_buck_enable_time, .set_mode = lp8755_buck_set_mode, .get_mode = lp8755_buck_get_mode, - .set_ramp_delay = lp8755_buck_set_ramp, + .set_ramp_delay = regulator_set_ramp_delay_regmap, }; #define lp8755_rail(_id) "lp8755_buck"#_id @@ -269,6 +226,10 @@ out_i2c_error: .enable_mask = LP8755_BUCK_EN_M,\ .vsel_reg = LP8755_REG_BUCK##_id,\ .vsel_mask = LP8755_BUCK_VOUT_M,\ + .ramp_reg = (LP8755_BUCK##_id) + 0x7,\ + .ramp_mask = 0x7,\ + .ramp_delay_table = lp8755_buck_ramp_table,\ + .n_ramp_values = ARRAY_SIZE(lp8755_buck_ramp_table),\ } static const struct regulator_desc lp8755_regulators[] = { diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 38f7ccb63b52..5e0b669c3a01 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -54,6 +54,11 @@ #define LTC3589_VCCR_SW3_GO BIT(4) #define LTC3589_VCCR_LDO2_GO BIT(6) +#define LTC3589_VRRCR_SW1_RAMP_MASK GENMASK(1, 0) +#define LTC3589_VRRCR_SW2_RAMP_MASK GENMASK(3, 2) +#define LTC3589_VRRCR_SW3_RAMP_MASK GENMASK(5, 4) +#define LTC3589_VRRCR_LDO2_RAMP_MASK GENMASK(7, 6) + enum ltc3589_variant { LTC3589, LTC3589_1, @@ -88,27 +93,9 @@ static const int ltc3589_12_ldo4[] = { 1200000, 1800000, 2500000, 3200000, }; -static int ltc3589_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) -{ - struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev); - int sel, shift; - - if (unlikely(ramp_delay <= 0)) - return -EINVAL; - - /* VRRCR slew rate offsets are the same as VCCR go bit offsets */ - shift = ffs(rdev->desc->apply_bit) - 1; - - /* The slew rate can be set to 0.88, 1.75, 3.5, or 7 mV/uS */ - for (sel = 0; sel < 4; sel++) { - if ((880 << sel) >= ramp_delay) { - return regmap_update_bits(ltc3589->regmap, - LTC3589_VRRCR, - 0x3 << shift, sel << shift); - } - } - return -EINVAL; -} +static const unsigned int ltc3589_ramp_table[] = { + 880, 1750, 3500, 7000 +}; static int ltc3589_set_suspend_voltage(struct regulator_dev *rdev, int uV) { @@ -149,7 +136,7 @@ static const struct regulator_ops ltc3589_linear_regulator_ops = { .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_ramp_delay = ltc3589_set_ramp_delay, + .set_ramp_delay = regulator_set_ramp_delay_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, .set_suspend_voltage = ltc3589_set_suspend_voltage, .set_suspend_mode = ltc3589_set_suspend_mode, @@ -218,16 +205,13 @@ static int ltc3589_of_parse_cb(struct device_node *np, return 0; } -#define LTC3589_REG(_name, _of_name, _ops, en_bit, dtv1_reg, dtv_mask, go_bit)\ +#define LTC3589_REG(_name, _of_name, _ops, en_bit, dtv1_reg, dtv_mask) \ [LTC3589_ ## _name] = { \ .name = #_name, \ .of_match = of_match_ptr(#_of_name), \ .regulators_node = of_match_ptr("regulators"), \ .of_parse_cb = ltc3589_of_parse_cb, \ .n_voltages = (dtv_mask) + 1, \ - .min_uV = (go_bit) ? 362500 : 0, \ - .uV_step = (go_bit) ? 12500 : 0, \ - .ramp_delay = (go_bit) ? 1750 : 0, \ .fixed_uV = (dtv_mask) ? 0 : 800000, \ .ops = <c3589_ ## _ops ## _regulator_ops, \ .type = REGULATOR_VOLTAGE, \ @@ -235,30 +219,49 @@ static int ltc3589_of_parse_cb(struct device_node *np, .owner = THIS_MODULE, \ .vsel_reg = (dtv1_reg), \ .vsel_mask = (dtv_mask), \ - .apply_reg = (go_bit) ? LTC3589_VCCR : 0, \ - .apply_bit = (go_bit), \ .enable_reg = (en_bit) ? LTC3589_OVEN : 0, \ .enable_mask = (en_bit), \ } #define LTC3589_LINEAR_REG(_name, _of_name, _dtv1) \ - LTC3589_REG(_name, _of_name, linear, LTC3589_OVEN_ ## _name, \ - LTC3589_ ## _dtv1, 0x1f, \ - LTC3589_VCCR_ ## _name ## _GO) + [LTC3589_ ## _name] = { \ + .name = #_name, \ + .of_match = of_match_ptr(#_of_name), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = ltc3589_of_parse_cb, \ + .n_voltages = 32, \ + .min_uV = 362500, \ + .uV_step = 12500, \ + .ramp_delay = 1750, \ + .ops = <c3589_linear_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = LTC3589_ ## _name, \ + .owner = THIS_MODULE, \ + .vsel_reg = LTC3589_ ## _dtv1, \ + .vsel_mask = 0x1f, \ + .apply_reg = LTC3589_VCCR, \ + .apply_bit = LTC3589_VCCR_ ## _name ## _GO, \ + .enable_reg = LTC3589_OVEN, \ + .enable_mask = (LTC3589_OVEN_ ## _name), \ + .ramp_reg = LTC3589_VRRCR, \ + .ramp_mask = LTC3589_VRRCR_ ## _name ## _RAMP_MASK, \ + .ramp_delay_table = ltc3589_ramp_table, \ + .n_ramp_values = ARRAY_SIZE(ltc3589_ramp_table), \ + } + #define LTC3589_FIXED_REG(_name, _of_name) \ - LTC3589_REG(_name, _of_name, fixed, LTC3589_OVEN_ ## _name, 0, 0, 0) + LTC3589_REG(_name, _of_name, fixed, LTC3589_OVEN_ ## _name, 0, 0) static const struct regulator_desc ltc3589_regulators[] = { LTC3589_LINEAR_REG(SW1, sw1, B1DTV1), LTC3589_LINEAR_REG(SW2, sw2, B2DTV1), LTC3589_LINEAR_REG(SW3, sw3, B3DTV1), LTC3589_FIXED_REG(BB_OUT, bb-out), - LTC3589_REG(LDO1, ldo1, fixed_standby, 0, 0, 0, 0), + LTC3589_REG(LDO1, ldo1, fixed_standby, 0, 0, 0), LTC3589_LINEAR_REG(LDO2, ldo2, L2DTV1), LTC3589_FIXED_REG(LDO3, ldo3), - LTC3589_REG(LDO4, ldo4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2, - 0x60, 0), + LTC3589_REG(LDO4, ldo4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2, 0x60), }; static bool ltc3589_writeable_reg(struct device *dev, unsigned int reg) diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index 9089ec608fcc..55a07d3f3ee2 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -67,13 +67,6 @@ #define MAX77686_REGULATORS MAX77686_REG_MAX #define MAX77686_LDOS 26 -enum max77686_ramp_rate { - RAMP_RATE_13P75MV, - RAMP_RATE_27P5MV, - RAMP_RATE_55MV, - RAMP_RATE_NO_CTRL, /* 100mV/us */ -}; - struct max77686_data { struct device *dev; DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS); @@ -220,31 +213,6 @@ static int max77686_enable(struct regulator_dev *rdev) max77686->opmode[id] << shift); } -static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) -{ - unsigned int ramp_value = RAMP_RATE_NO_CTRL; - - switch (ramp_delay) { - case 1 ... 13750: - ramp_value = RAMP_RATE_13P75MV; - break; - case 13751 ... 27500: - ramp_value = RAMP_RATE_27P5MV; - break; - case 27501 ... 55000: - ramp_value = RAMP_RATE_55MV; - break; - case 55001 ... 100000: - break; - default: - pr_warn("%s: ramp_delay: %d not supported, setting 100000\n", - rdev->desc->name, ramp_delay); - } - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - MAX77686_RAMP_RATE_MASK, ramp_value << 6); -} - static int max77686_of_parse_cb(struct device_node *np, const struct regulator_desc *desc, struct regulator_config *config) @@ -284,6 +252,10 @@ static int max77686_of_parse_cb(struct device_node *np, return 0; } +static const unsigned int max77686_buck_dvs_ramp_table[] = { + 13750, 27500, 55000, 100000 +}; + static const struct regulator_ops max77686_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -330,7 +302,7 @@ static const struct regulator_ops max77686_buck_dvs_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = max77686_set_ramp_delay, + .set_ramp_delay = regulator_set_ramp_delay_regmap, .set_suspend_disable = max77686_set_suspend_disable, }; @@ -462,6 +434,10 @@ static const struct regulator_ops max77686_buck_dvs_ops = { .enable_reg = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10, \ .enable_mask = MAX77686_OPMODE_MASK \ << MAX77686_OPMODE_BUCK234_SHIFT, \ + .ramp_reg = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10, \ + .ramp_mask = MAX77686_RAMP_RATE_MASK, \ + .ramp_delay_table = max77686_buck_dvs_ramp_table, \ + .n_ramp_values = ARRAY_SIZE(max77686_buck_dvs_ramp_table), \ } static const struct regulator_desc regulators[] = { diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index 7b8ec8c0bd15..21e0eb0f43f9 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -43,15 +43,14 @@ #define MAX77802_OFF_PWRREQ 0x1 #define MAX77802_LP_PWRREQ 0x2 -/* MAX77802 has two register formats: 2-bit and 4-bit */ -static const unsigned int ramp_table_77802_2bit[] = { +static const unsigned int max77802_buck234_ramp_table[] = { 12500, 25000, 50000, 100000, }; -static unsigned int ramp_table_77802_4bit[] = { +static const unsigned int max77802_buck16_ramp_table[] = { 1000, 2000, 3030, 4000, 5000, 5880, 7140, 8330, 9090, 10000, 11110, 12500, @@ -221,58 +220,6 @@ static int max77802_enable(struct regulator_dev *rdev) max77802->opmode[id] << shift); } -static int max77802_find_ramp_value(struct regulator_dev *rdev, - const unsigned int limits[], int size, - unsigned int ramp_delay) -{ - int i; - - for (i = 0; i < size; i++) { - if (ramp_delay <= limits[i]) - return i; - } - - /* Use maximum value for no ramp control */ - dev_warn(&rdev->dev, "%s: ramp_delay: %d not supported, setting 100000\n", - rdev->desc->name, ramp_delay); - return size - 1; -} - -/* Used for BUCKs 2-4 */ -static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev, - int ramp_delay) -{ - int id = rdev_get_id(rdev); - unsigned int ramp_value; - - if (id > MAX77802_BUCK4) { - dev_warn(&rdev->dev, - "%s: regulator: ramp delay not supported\n", - rdev->desc->name); - return -EINVAL; - } - ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit, - ARRAY_SIZE(ramp_table_77802_2bit), ramp_delay); - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - MAX77802_RAMP_RATE_MASK_2BIT, - ramp_value << MAX77802_RAMP_RATE_SHIFT_2BIT); -} - -/* For BUCK1, 6 */ -static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev, - int ramp_delay) -{ - unsigned int ramp_value; - - ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_4bit, - ARRAY_SIZE(ramp_table_77802_4bit), ramp_delay); - - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - MAX77802_RAMP_RATE_MASK_4BIT, - ramp_value << MAX77802_RAMP_RATE_SHIFT_4BIT); -} - /* * LDOs 2, 4-19, 22-35 */ @@ -316,7 +263,7 @@ static const struct regulator_ops max77802_buck_16_dvs_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = max77802_set_ramp_delay_4bit, + .set_ramp_delay = regulator_set_ramp_delay_regmap, .set_suspend_disable = max77802_set_suspend_disable, }; @@ -330,7 +277,7 @@ static const struct regulator_ops max77802_buck_234_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = max77802_set_ramp_delay_2bit, + .set_ramp_delay = regulator_set_ramp_delay_regmap, .set_suspend_disable = max77802_set_suspend_disable, .set_suspend_mode = max77802_set_suspend_mode, }; @@ -345,7 +292,6 @@ static const struct regulator_ops max77802_buck_dvs_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = max77802_set_ramp_delay_2bit, .set_suspend_disable = max77802_set_suspend_disable, }; @@ -409,6 +355,10 @@ static const struct regulator_ops max77802_buck_dvs_ops = { .vsel_mask = MAX77802_DVS_VSEL_MASK, \ .enable_reg = MAX77802_REG_BUCK ## num ## CTRL, \ .enable_mask = MAX77802_OPMODE_MASK, \ + .ramp_reg = MAX77802_REG_BUCK ## num ## CTRL, \ + .ramp_mask = MAX77802_RAMP_RATE_MASK_4BIT, \ + .ramp_delay_table = max77802_buck16_ramp_table, \ + .n_ramp_values = ARRAY_SIZE(max77802_buck16_ramp_table), \ .of_map_mode = max77802_map_mode, \ } @@ -431,6 +381,10 @@ static const struct regulator_ops max77802_buck_dvs_ops = { .enable_reg = MAX77802_REG_BUCK ## num ## CTRL1, \ .enable_mask = MAX77802_OPMODE_MASK << \ MAX77802_OPMODE_BUCK234_SHIFT, \ + .ramp_reg = MAX77802_REG_BUCK ## num ## CTRL1, \ + .ramp_mask = MAX77802_RAMP_RATE_MASK_2BIT, \ + .ramp_delay_table = max77802_buck234_ramp_table, \ + .n_ramp_values = ARRAY_SIZE(max77802_buck234_ramp_table), \ .of_map_mode = max77802_map_mode, \ } diff --git a/drivers/regulator/max8893.c b/drivers/regulator/max8893.c new file mode 100644 index 000000000000..1519bf760da7 --- /dev/null +++ b/drivers/regulator/max8893.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +static const struct regulator_ops max8893_ops = { + .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, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, +}; + +static const struct regulator_desc max8893_regulators[] = { + { + .name = "BUCK", + .supply_name = "in-buck", + .of_match = of_match_ptr("buck"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x11, + .id = 6, + .ops = &max8893_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .min_uV = 800000, + .uV_step = 100000, + .vsel_reg = 0x4, + .vsel_mask = 0x1f, + .enable_reg = 0x0, + .enable_mask = BIT(7), + }, + { + .name = "LDO1", + .supply_name = "in-ldo1", + .of_match = of_match_ptr("ldo1"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x12, + .id = 1, + .ops = &max8893_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .min_uV = 1600000, + .uV_step = 100000, + .vsel_reg = 0x5, + .vsel_mask = 0x1f, + .enable_reg = 0x0, + .enable_mask = BIT(5), + }, + { + .name = "LDO2", + .supply_name = "in-ldo2", + .of_match = of_match_ptr("ldo2"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x16, + .id = 2, + .ops = &max8893_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .min_uV = 1200000, + .uV_step = 100000, + .vsel_reg = 0x6, + .vsel_mask = 0x1f, + .enable_reg = 0x0, + .enable_mask = BIT(4), + }, + { + .name = "LDO3", + .supply_name = "in-ldo3", + .of_match = of_match_ptr("ldo3"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x12, + .id = 3, + .ops = &max8893_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .min_uV = 1600000, + .uV_step = 100000, + .vsel_reg = 0x7, + .vsel_mask = 0x1f, + .enable_reg = 0x0, + .enable_mask = BIT(3), + }, + { + .name = "LDO4", + .supply_name = "in-ldo4", + .of_match = of_match_ptr("ldo4"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x1a, + .id = 4, + .ops = &max8893_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .min_uV = 800000, + .uV_step = 100000, + .vsel_reg = 0x8, + .vsel_mask = 0x1f, + .enable_reg = 0x0, + .enable_mask = BIT(2), + }, + { + .name = "LDO5", + .supply_name = "in-ldo5", + .of_match = of_match_ptr("ldo5"), + .regulators_node = of_match_ptr("regulators"), + .n_voltages = 0x1a, + .id = 5, + .ops = &max8893_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .min_uV = 800000, + .uV_step = 100000, + .vsel_reg = 0x9, + .vsel_mask = 0x1f, + .enable_reg = 0x0, + .enable_mask = BIT(1), + } +}; + +static const struct regmap_config max8893_regmap = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int max8893_probe_new(struct i2c_client *i2c) +{ + int id, ret; + struct regulator_config config = {.dev = &i2c->dev}; + struct regmap *regmap = devm_regmap_init_i2c(i2c, &max8893_regmap); + + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "regmap init failed: %d\n", ret); + return ret; + } + + for (id = 0; id < ARRAY_SIZE(max8893_regulators); id++) { + struct regulator_dev *rdev; + rdev = devm_regulator_register(&i2c->dev, + &max8893_regulators[id], + &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&i2c->dev, "failed to register %s: %d\n", + max8893_regulators[id].name, ret); + return ret; + } + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id max8893_dt_match[] = { + { .compatible = "maxim,max8893" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, max8893_dt_match); +#endif + +static const struct i2c_device_id max8893_ids[] = { + { "max8893", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, max8893_ids); + +static struct i2c_driver max8893_driver = { + .probe_new = max8893_probe_new, + .driver = { + .name = "max8893", + .of_match_table = of_match_ptr(max8893_dt_match), + }, + .id_table = max8893_ids, +}; + +module_i2c_driver(max8893_driver); + +MODULE_DESCRIPTION("Maxim MAX8893 PMIC driver"); +MODULE_AUTHOR("Sergey Larin <cerg2010cerg2010@mail.ru>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 9aee1444181d..8da8f9b6c4fd 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -265,33 +265,6 @@ static unsigned int max8973_dcdc_get_mode(struct regulator_dev *rdev) REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; } -static int max8973_set_ramp_delay(struct regulator_dev *rdev, - int ramp_delay) -{ - struct max8973_chip *max = rdev_get_drvdata(rdev); - unsigned int control; - int ret; - - /* Set ramp delay */ - if (ramp_delay <= 12000) - control = MAX8973_RAMP_12mV_PER_US; - else if (ramp_delay <= 25000) - control = MAX8973_RAMP_25mV_PER_US; - else if (ramp_delay <= 50000) - control = MAX8973_RAMP_50mV_PER_US; - else if (ramp_delay <= 200000) - control = MAX8973_RAMP_200mV_PER_US; - else - return -EINVAL; - - ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1, - MAX8973_RAMP_MASK, control); - if (ret < 0) - dev_err(max->dev, "register %d update failed, %d", - MAX8973_CONTROL1, ret); - return ret; -} - static int max8973_set_current_limit(struct regulator_dev *rdev, int min_ua, int max_ua) { @@ -341,6 +314,10 @@ static int max8973_get_current_limit(struct regulator_dev *rdev) return 9000000; } +static const unsigned int max8973_buck_ramp_table[] = { + 12000, 25000, 50000, 200000 +}; + static const struct regulator_ops max8973_dcdc_ops = { .get_voltage_sel = max8973_dcdc_get_voltage_sel, .set_voltage_sel = max8973_dcdc_set_voltage_sel, @@ -348,7 +325,7 @@ static const struct regulator_ops max8973_dcdc_ops = { .set_mode = max8973_dcdc_set_mode, .get_mode = max8973_dcdc_get_mode, .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = max8973_set_ramp_delay, + .set_ramp_delay = regulator_set_ramp_delay_regmap, }; static int max8973_init_dcdc(struct max8973_chip *max, @@ -694,6 +671,10 @@ static int max8973_probe(struct i2c_client *client, max->desc.min_uV = MAX8973_MIN_VOLATGE; max->desc.uV_step = MAX8973_VOLATGE_STEP; max->desc.n_voltages = MAX8973_BUCK_N_VOLTAGE; + max->desc.ramp_reg = MAX8973_CONTROL1; + max->desc.ramp_mask = MAX8973_RAMP_MASK; + max->desc.ramp_delay_table = max8973_buck_ramp_table; + max->desc.n_ramp_values = ARRAY_SIZE(max8973_buck_ramp_table); max->dvs_gpio = (pdata->dvs_gpio) ? pdata->dvs_gpio : -EINVAL; max->enable_external_control = pdata->enable_ext_control; diff --git a/drivers/regulator/mcp16502.c b/drivers/regulator/mcp16502.c index 88c6bd5b6c78..042668385678 100644 --- a/drivers/regulator/mcp16502.c +++ b/drivers/regulator/mcp16502.c @@ -90,10 +90,14 @@ enum mcp16502_reg { }; /* Ramp delay (uV/us) for buck1, ldo1, ldo2. */ -static const int mcp16502_ramp_b1l12[] = { 6250, 3125, 2083, 1563 }; +static const unsigned int mcp16502_ramp_b1l12[] = { + 6250, 3125, 2083, 1563 +}; /* Ramp delay (uV/us) for buck2, buck3, buck4. */ -static const int mcp16502_ramp_b234[] = { 3125, 1563, 1042, 781 }; +static const unsigned int mcp16502_ramp_b234[] = { + 3125, 1563, 1042, 781 +}; static unsigned int mcp16502_of_map_mode(unsigned int mode) { @@ -103,7 +107,7 @@ static unsigned int mcp16502_of_map_mode(unsigned int mode) return REGULATOR_MODE_INVALID; } -#define MCP16502_REGULATOR(_name, _id, _ranges, _ops) \ +#define MCP16502_REGULATOR(_name, _id, _ranges, _ops, _ramp_table) \ [_id] = { \ .name = _name, \ .regulators_node = of_match_ptr("regulators"), \ @@ -121,6 +125,10 @@ static unsigned int mcp16502_of_map_mode(unsigned int mode) .vsel_mask = MCP16502_VSEL, \ .enable_reg = (((_id) + 1) << 4), \ .enable_mask = MCP16502_EN, \ + .ramp_reg = MCP16502_REG_BASE(_id, CFG), \ + .ramp_mask = MCP16502_DVSR, \ + .ramp_delay_table = _ramp_table, \ + .n_ramp_values = ARRAY_SIZE(_ramp_table), \ } enum { @@ -314,42 +322,6 @@ static int mcp16502_set_voltage_time_sel(struct regulator_dev *rdev, return ret; } -static int mcp16502_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) -{ - const int *ramp; - int id = rdev_get_id(rdev); - unsigned int i, size; - - switch (id) { - case BUCK1: - case LDO1: - case LDO2: - ramp = mcp16502_ramp_b1l12; - size = ARRAY_SIZE(mcp16502_ramp_b1l12); - break; - - case BUCK2: - case BUCK3: - case BUCK4: - ramp = mcp16502_ramp_b234; - size = ARRAY_SIZE(mcp16502_ramp_b234); - break; - - default: - return -EINVAL; - } - - for (i = 0; i < size; i++) { - if (ramp[i] == ramp_delay) - break; - } - if (i == size) - return -EINVAL; - - return regmap_update_bits(rdev->regmap, MCP16502_REG_BASE(id, CFG), - MCP16502_DVSR, (i << 2)); -} - #ifdef CONFIG_SUSPEND /* * mcp16502_suspend_get_target_reg() - get the reg of the target suspend PMIC @@ -445,7 +417,7 @@ static const struct regulator_ops mcp16502_buck_ops = { .is_enabled = regulator_is_enabled_regmap, .get_status = mcp16502_get_status, .set_voltage_time_sel = mcp16502_set_voltage_time_sel, - .set_ramp_delay = mcp16502_set_ramp_delay, + .set_ramp_delay = regulator_set_ramp_delay_regmap, .set_mode = mcp16502_set_mode, .get_mode = mcp16502_get_mode, @@ -471,7 +443,7 @@ static const struct regulator_ops mcp16502_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .get_status = mcp16502_get_status, .set_voltage_time_sel = mcp16502_set_voltage_time_sel, - .set_ramp_delay = mcp16502_set_ramp_delay, + .set_ramp_delay = regulator_set_ramp_delay_regmap, #ifdef CONFIG_SUSPEND .set_suspend_voltage = mcp16502_set_suspend_voltage, @@ -495,13 +467,19 @@ static const struct linear_range b234_ranges[] = { }; static const struct regulator_desc mcp16502_desc[] = { - /* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops) */ - MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops), - MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops), - MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops), - MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops), - MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops), - MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops) + /* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops, ramp_table) */ + MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops, + mcp16502_ramp_b1l12), + MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops, + mcp16502_ramp_b234), + MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops, + mcp16502_ramp_b234), + MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops, + mcp16502_ramp_b234), + MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops, + mcp16502_ramp_b1l12), + MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops, + mcp16502_ramp_b1l12) }; static const struct regmap_range mcp16502_ranges[] = { @@ -522,8 +500,7 @@ static const struct regmap_config mcp16502_regmap_config = { .wr_table = &mcp16502_yes_reg_table, }; -static int mcp16502_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mcp16502_probe(struct i2c_client *client) { struct regulator_config config = { }; struct regulator_dev *rdev; @@ -606,7 +583,7 @@ static const struct i2c_device_id mcp16502_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, mcp16502_i2c_id); static struct i2c_driver mcp16502_drv = { - .probe = mcp16502_probe, + .probe_new = mcp16502_probe, .driver = { .name = "mcp16502-regulator", .of_match_table = of_match_ptr(mcp16502_ids), diff --git a/drivers/regulator/mp5416.c b/drivers/regulator/mp5416.c index 67ce1b52a1a1..39cebec0edb6 100644 --- a/drivers/regulator/mp5416.c +++ b/drivers/regulator/mp5416.c @@ -67,6 +67,10 @@ .vsel_mask = MP5416_MASK_VSET, \ .enable_reg = MP5416_REG_BUCK ## _id, \ .enable_mask = MP5416_REGULATOR_EN, \ + .ramp_reg = MP5416_REG_CTL2, \ + .ramp_mask = MP5416_MASK_DVS_SLEWRATE, \ + .ramp_delay_table = mp5416_buck_ramp_table, \ + .n_ramp_values = ARRAY_SIZE(mp5416_buck_ramp_table), \ .active_discharge_on = _dval, \ .active_discharge_reg = _dreg, \ .active_discharge_mask = _dval, \ @@ -123,7 +127,16 @@ static const unsigned int mp5416_I_limits2[] = { 2200000, 3200000, 4200000, 5200000 }; -static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay); +/* + * DVS ramp rate BUCK1 to BUCK4 + * 00: 32mV/us + * 01: 16mV/us + * 10: 8mV/us + * 11: 4mV/us + */ +static const unsigned int mp5416_buck_ramp_table[] = { + 32000, 16000, 8000, 4000 +}; static const struct regulator_ops mp5416_ldo_ops = { .enable = regulator_enable_regmap, @@ -147,7 +160,7 @@ static const struct regulator_ops mp5416_buck_ops = { .set_active_discharge = regulator_set_active_discharge_regmap, .get_current_limit = regulator_get_current_limit_regmap, .set_current_limit = regulator_set_current_limit_regmap, - .set_ramp_delay = mp5416_set_ramp_delay, + .set_ramp_delay = regulator_set_ramp_delay_regmap, }; static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = { @@ -161,33 +174,6 @@ static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = { MP5416LDO("ldo4", 4, BIT(1)), }; -/* - * DVS ramp rate BUCK1 to BUCK4 - * 00: 32mV/us - * 01: 16mV/us - * 10: 8mV/us - * 11: 4mV/us - */ -static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) -{ - unsigned int ramp_val; - - if (ramp_delay > 32000 || ramp_delay < 0) - return -EINVAL; - - if (ramp_delay <= 4000) - ramp_val = 3; - else if (ramp_delay <= 8000) - ramp_val = 2; - else if (ramp_delay <= 16000) - ramp_val = 1; - else - ramp_val = 0; - - return regmap_update_bits(rdev->regmap, MP5416_REG_CTL2, - MP5416_MASK_DVS_SLEWRATE, ramp_val << 6); -} - static int mp5416_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; diff --git a/drivers/regulator/mp886x.c b/drivers/regulator/mp886x.c index a84fd74081de..8ad4722eca4b 100644 --- a/drivers/regulator/mp886x.c +++ b/drivers/regulator/mp886x.c @@ -26,7 +26,7 @@ struct mp886x_cfg_info { const struct regulator_ops *rops; - const int slew_rates[8]; + const unsigned int slew_rates[8]; const int switch_freq[4]; const u8 fs_reg; const u8 fs_shift; @@ -42,28 +42,6 @@ struct mp886x_device_info { unsigned int sel; }; -static int mp886x_set_ramp(struct regulator_dev *rdev, int ramp) -{ - struct mp886x_device_info *di = rdev_get_drvdata(rdev); - const struct mp886x_cfg_info *ci = di->ci; - int reg = -1, i; - - for (i = 0; i < ARRAY_SIZE(ci->slew_rates); i++) { - if (ramp <= ci->slew_rates[i]) - reg = i; - else - break; - } - - if (reg < 0) { - dev_err(di->dev, "unsupported ramp value %d\n", ramp); - return -EINVAL; - } - - return regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1, - MP886X_SLEW_MASK, reg << MP886X_SLEW_SHIFT); -} - static void mp886x_set_switch_freq(struct mp886x_device_info *di, struct regmap *regmap, u32 freq) @@ -169,7 +147,7 @@ static const struct regulator_ops mp8869_regulator_ops = { .is_enabled = regulator_is_enabled_regmap, .set_mode = mp886x_set_mode, .get_mode = mp886x_get_mode, - .set_ramp_delay = mp886x_set_ramp, + .set_ramp_delay = regulator_set_ramp_delay_regmap, }; static const struct mp886x_cfg_info mp8869_ci = { @@ -248,7 +226,7 @@ static const struct regulator_ops mp8867_regulator_ops = { .is_enabled = regulator_is_enabled_regmap, .set_mode = mp886x_set_mode, .get_mode = mp886x_get_mode, - .set_ramp_delay = mp886x_set_ramp, + .set_ramp_delay = regulator_set_ramp_delay_regmap, }; static const struct mp886x_cfg_info mp8867_ci = { @@ -290,6 +268,10 @@ static int mp886x_regulator_register(struct mp886x_device_info *di, rdesc->uV_step = 10000; rdesc->vsel_reg = MP886X_VSEL; rdesc->vsel_mask = 0x3f; + rdesc->ramp_reg = MP886X_SYSCNTLREG1; + rdesc->ramp_mask = MP886X_SLEW_MASK; + rdesc->ramp_delay_table = di->ci->slew_rates; + rdesc->n_ramp_values = ARRAY_SIZE(di->ci->slew_rates); rdesc->owner = THIS_MODULE; rdev = devm_regulator_register(di->dev, &di->desc, config); diff --git a/drivers/regulator/mt6315-regulator.c b/drivers/regulator/mt6315-regulator.c index 6b8be52c3772..284c229e1aa4 100644 --- a/drivers/regulator/mt6315-regulator.c +++ b/drivers/regulator/mt6315-regulator.c @@ -84,7 +84,7 @@ static unsigned int mt6315_regulator_get_mode(struct regulator_dev *rdev) modeset_mask = init->modeset_mask[rdev_get_id(rdev)]; ret = regmap_read(rdev->regmap, MT6315_BUCK_TOP_4PHASE_ANA_CON42, ®val); if (ret != 0) { - dev_notice(&rdev->dev, "Failed to get mode: %d\n", ret); + dev_err(&rdev->dev, "Failed to get mode: %d\n", ret); return ret; } @@ -93,7 +93,7 @@ static unsigned int mt6315_regulator_get_mode(struct regulator_dev *rdev) ret = regmap_read(rdev->regmap, MT6315_BUCK_TOP_CON1, ®val); if (ret != 0) { - dev_notice(&rdev->dev, "Failed to get lp mode: %d\n", ret); + dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret); return ret; } @@ -147,12 +147,12 @@ static int mt6315_regulator_set_mode(struct regulator_dev *rdev, break; default: ret = -EINVAL; - dev_notice(&rdev->dev, "Unsupported mode: %d\n", mode); + dev_err(&rdev->dev, "Unsupported mode: %d\n", mode); break; } if (ret != 0) { - dev_notice(&rdev->dev, "Failed to set mode: %d\n", ret); + dev_err(&rdev->dev, "Failed to set mode: %d\n", ret); return ret; } @@ -168,7 +168,7 @@ static int mt6315_get_status(struct regulator_dev *rdev) info = container_of(rdev->desc, struct mt6315_regulator_info, desc); ret = regmap_read(rdev->regmap, info->status_reg, ®val); if (ret < 0) { - dev_notice(&rdev->dev, "Failed to get enable reg: %d\n", ret); + dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret); return ret; } @@ -223,8 +223,8 @@ static int mt6315_regulator_probe(struct spmi_device *pdev) int i; regmap = devm_regmap_init_spmi_ext(pdev, &mt6315_regmap_config); - if (!regmap) - return -ENODEV; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); chip = devm_kzalloc(dev, sizeof(struct mt6315_chip), GFP_KERNEL); if (!chip) @@ -260,8 +260,9 @@ static int mt6315_regulator_probe(struct spmi_device *pdev) config.driver_data = init_data; rdev = devm_regulator_register(dev, &mt6315_regulators[i].desc, &config); if (IS_ERR(rdev)) { - dev_notice(dev, "Failed to register %s\n", mt6315_regulators[i].desc.name); - continue; + dev_err(dev, "Failed to register %s\n", + mt6315_regulators[i].desc.name); + return PTR_ERR(rdev); } } @@ -279,7 +280,7 @@ static void mt6315_regulator_shutdown(struct spmi_device *pdev) ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY, 0); ret |= regmap_write(chip->regmap, MT6315_TOP_TMA_KEY_H, 0); if (ret < 0) - dev_notice(&pdev->dev, "[%#x] Failed to enable power off sequence. %d\n", + dev_err(&pdev->dev, "[%#x] Failed to enable power off sequence. %d\n", pdev->usid, ret); } diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c index 13cb6ac9a892..0d35be4e0e5a 100644 --- a/drivers/regulator/mt6358-regulator.c +++ b/drivers/regulator/mt6358-regulator.c @@ -153,50 +153,50 @@ static const struct linear_range buck_volt_range4[] = { REGULATOR_LINEAR_RANGE(1000000, 0, 0x7f, 12500), }; -static const u32 vdram2_voltages[] = { +static const unsigned int vdram2_voltages[] = { 600000, 1800000, }; -static const u32 vsim_voltages[] = { +static const unsigned int vsim_voltages[] = { 1700000, 1800000, 2700000, 3000000, 3100000, }; -static const u32 vibr_voltages[] = { +static const unsigned int vibr_voltages[] = { 1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000, }; -static const u32 vusb_voltages[] = { +static const unsigned int vusb_voltages[] = { 3000000, 3100000, }; -static const u32 vcamd_voltages[] = { +static const unsigned int vcamd_voltages[] = { 900000, 1000000, 1100000, 1200000, 1300000, 1500000, 1800000, }; -static const u32 vefuse_voltages[] = { +static const unsigned int vefuse_voltages[] = { 1700000, 1800000, 1900000, }; -static const u32 vmch_vemc_voltages[] = { +static const unsigned int vmch_vemc_voltages[] = { 2900000, 3000000, 3300000, }; -static const u32 vcama_voltages[] = { +static const unsigned int vcama_voltages[] = { 1800000, 2500000, 2700000, 2800000, 2900000, 3000000, }; -static const u32 vcn33_bt_wifi_voltages[] = { +static const unsigned int vcn33_bt_wifi_voltages[] = { 3300000, 3400000, 3500000, }; -static const u32 vmc_voltages[] = { +static const unsigned int vmc_voltages[] = { 1800000, 2900000, 3000000, 3300000, }; -static const u32 vldo28_voltages[] = { +static const unsigned int vldo28_voltages[] = { 2800000, 3000000, }; @@ -457,7 +457,7 @@ static struct mt6358_regulator_info mt6358_regulators[] = { MT6358_REG_FIXED("ldo_vaud28", VAUD28, MT6358_LDO_VAUD28_CON0, 0, 2800000), MT6358_LDO("ldo_vdram2", VDRAM2, vdram2_voltages, vdram2_idx, - MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0x10, 0), + MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0xf, 0), MT6358_LDO("ldo_vsim1", VSIM1, vsim_voltages, vsim_idx, MT6358_LDO_VSIM1_CON0, 0, MT6358_VSIM1_ANA_CON0, 0xf00, 8), MT6358_LDO("ldo_vibr", VIBR, vibr_voltages, vibr_idx, diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c new file mode 100644 index 000000000000..7ce0bd377a08 --- /dev/null +++ b/drivers/regulator/mt6359-regulator.c @@ -0,0 +1,997 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2021 MediaTek Inc. + +#include <linux/platform_device.h> +#include <linux/mfd/mt6359/registers.h> +#include <linux/mfd/mt6359p/registers.h> +#include <linux/mfd/mt6397/core.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/mt6359-regulator.h> +#include <linux/regulator/of_regulator.h> + +#define MT6359_BUCK_MODE_AUTO 0 +#define MT6359_BUCK_MODE_FORCE_PWM 1 +#define MT6359_BUCK_MODE_NORMAL 0 +#define MT6359_BUCK_MODE_LP 2 + +/* + * MT6359 regulators' information + * + * @desc: standard fields of regulator description. + * @status_reg: for query status of regulators. + * @qi: Mask for query enable signal status of regulators. + * @modeset_reg: for operating AUTO/PWM mode register. + * @modeset_mask: MASK for operating modeset register. + * @modeset_shift: SHIFT for operating modeset register. + */ +struct mt6359_regulator_info { + struct regulator_desc desc; + u32 status_reg; + u32 qi; + u32 modeset_reg; + u32 modeset_mask; + u32 modeset_shift; + u32 lp_mode_reg; + u32 lp_mode_mask; + u32 lp_mode_shift; +}; + +#define MT6359_BUCK(match, _name, min, max, step, \ + _enable_reg, _status_reg, \ + _vsel_reg, _vsel_mask, \ + _lp_mode_reg, _lp_mode_shift, \ + _modeset_reg, _modeset_shift) \ +[MT6359_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &mt6359_volt_linear_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6359_ID_##_name, \ + .owner = THIS_MODULE, \ + .uV_step = (step), \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .min_uV = (min), \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(0), \ + .of_map_mode = mt6359_map_mode, \ + }, \ + .status_reg = _status_reg, \ + .qi = BIT(0), \ + .lp_mode_reg = _lp_mode_reg, \ + .lp_mode_mask = BIT(_lp_mode_shift), \ + .lp_mode_shift = _lp_mode_shift, \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = BIT(_modeset_shift), \ + .modeset_shift = _modeset_shift \ +} + +#define MT6359_LDO_LINEAR(match, _name, min, max, step, \ + _enable_reg, _status_reg, _vsel_reg, _vsel_mask) \ +[MT6359_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &mt6359_volt_linear_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6359_ID_##_name, \ + .owner = THIS_MODULE, \ + .uV_step = (step), \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .min_uV = (min), \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(0), \ + }, \ + .status_reg = _status_reg, \ + .qi = BIT(0), \ +} + +#define MT6359_LDO(match, _name, _volt_table, \ + _enable_reg, _enable_mask, _status_reg, \ + _vsel_reg, _vsel_mask, _en_delay) \ +[MT6359_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &mt6359_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6359_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(_volt_table), \ + .volt_table = _volt_table, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(_enable_mask), \ + .enable_time = _en_delay, \ + }, \ + .status_reg = _status_reg, \ + .qi = BIT(0), \ +} + +#define MT6359_REG_FIXED(match, _name, _enable_reg, \ + _status_reg, _fixed_volt) \ +[MT6359_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &mt6359_volt_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6359_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = 1, \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(0), \ + .fixed_uV = (_fixed_volt), \ + }, \ + .status_reg = _status_reg, \ + .qi = BIT(0), \ +} + +#define MT6359P_LDO1(match, _name, _ops, _volt_table, \ + _enable_reg, _enable_mask, _status_reg, \ + _vsel_reg, _vsel_mask) \ +[MT6359_ID_##_name] = { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6359_ID_##_name, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(_volt_table), \ + .volt_table = _volt_table, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .enable_reg = _enable_reg, \ + .enable_mask = BIT(_enable_mask), \ + }, \ + .status_reg = _status_reg, \ + .qi = BIT(0), \ +} + +static const unsigned int vsim1_voltages[] = { + 0, 0, 0, 1700000, 1800000, 0, 0, 0, 2700000, 0, 0, 3000000, 3100000, +}; + +static const unsigned int vibr_voltages[] = { + 1200000, 1300000, 1500000, 0, 1800000, 2000000, 0, 0, 2700000, 2800000, + 0, 3000000, 0, 3300000, +}; + +static const unsigned int vrf12_voltages[] = { + 0, 0, 1100000, 1200000, 1300000, +}; + +static const unsigned int volt18_voltages[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700000, 1800000, 1900000, +}; + +static const unsigned int vcn13_voltages[] = { + 900000, 1000000, 0, 1200000, 1300000, +}; + +static const unsigned int vcn33_voltages[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2800000, 0, 0, 0, 3300000, 3400000, 3500000, +}; + +static const unsigned int vefuse_voltages[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1700000, 1800000, 1900000, 2000000, +}; + +static const unsigned int vxo22_voltages[] = { + 1800000, 0, 0, 0, 2200000, +}; + +static const unsigned int vrfck_voltages[] = { + 0, 0, 1500000, 0, 0, 0, 0, 1600000, 0, 0, 0, 0, 1700000, +}; + +static const unsigned int vrfck_voltages_1[] = { + 1240000, 1600000, +}; + +static const unsigned int vio28_voltages[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2800000, 2900000, 3000000, 3100000, 3300000, +}; + +static const unsigned int vemc_voltages[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2900000, 3000000, 0, 3300000, +}; + +static const unsigned int vemc_voltages_1[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 2500000, 2800000, 2900000, 3000000, 3100000, + 3300000, +}; + +static const unsigned int va12_voltages[] = { + 0, 0, 0, 0, 0, 0, 1200000, 1300000, +}; + +static const unsigned int va09_voltages[] = { + 0, 0, 800000, 900000, 0, 0, 1200000, +}; + +static const unsigned int vrf18_voltages[] = { + 0, 0, 0, 0, 0, 1700000, 1800000, 1810000, +}; + +static const unsigned int vbbck_voltages[] = { + 0, 0, 0, 0, 1100000, 0, 0, 0, 1150000, 0, 0, 0, 1200000, +}; + +static const unsigned int vsim2_voltages[] = { + 0, 0, 0, 1700000, 1800000, 0, 0, 0, 2700000, 0, 0, 3000000, 3100000, +}; + +static inline unsigned int mt6359_map_mode(unsigned int mode) +{ + switch (mode) { + case MT6359_BUCK_MODE_NORMAL: + return REGULATOR_MODE_NORMAL; + case MT6359_BUCK_MODE_FORCE_PWM: + return REGULATOR_MODE_FAST; + case MT6359_BUCK_MODE_LP: + return REGULATOR_MODE_IDLE; + default: + return REGULATOR_MODE_INVALID; + } +} + +static int mt6359_get_status(struct regulator_dev *rdev) +{ + int ret; + u32 regval; + struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + + ret = regmap_read(rdev->regmap, info->status_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret); + return ret; + } + + if (regval & info->qi) + return REGULATOR_STATUS_ON; + else + return REGULATOR_STATUS_OFF; +} + +static unsigned int mt6359_regulator_get_mode(struct regulator_dev *rdev) +{ + struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + int ret, regval; + + ret = regmap_read(rdev->regmap, info->modeset_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, + "Failed to get mt6359 buck mode: %d\n", ret); + return ret; + } + + if ((regval & info->modeset_mask) >> info->modeset_shift == + MT6359_BUCK_MODE_FORCE_PWM) + return REGULATOR_MODE_FAST; + + ret = regmap_read(rdev->regmap, info->lp_mode_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, + "Failed to get mt6359 buck lp mode: %d\n", ret); + return ret; + } + + if (regval & info->lp_mode_mask) + return REGULATOR_MODE_IDLE; + else + return REGULATOR_MODE_NORMAL; +} + +static int mt6359_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + int ret = 0, val; + int curr_mode; + + curr_mode = mt6359_regulator_get_mode(rdev); + switch (mode) { + case REGULATOR_MODE_FAST: + val = MT6359_BUCK_MODE_FORCE_PWM; + val <<= info->modeset_shift; + ret = regmap_update_bits(rdev->regmap, + info->modeset_reg, + info->modeset_mask, + val); + break; + case REGULATOR_MODE_NORMAL: + if (curr_mode == REGULATOR_MODE_FAST) { + val = MT6359_BUCK_MODE_AUTO; + val <<= info->modeset_shift; + ret = regmap_update_bits(rdev->regmap, + info->modeset_reg, + info->modeset_mask, + val); + } else if (curr_mode == REGULATOR_MODE_IDLE) { + val = MT6359_BUCK_MODE_NORMAL; + val <<= info->lp_mode_shift; + ret = regmap_update_bits(rdev->regmap, + info->lp_mode_reg, + info->lp_mode_mask, + val); + udelay(100); + } + break; + case REGULATOR_MODE_IDLE: + val = MT6359_BUCK_MODE_LP >> 1; + val <<= info->lp_mode_shift; + ret = regmap_update_bits(rdev->regmap, + info->lp_mode_reg, + info->lp_mode_mask, + val); + break; + default: + return -EINVAL; + } + + if (ret != 0) { + dev_err(&rdev->dev, + "Failed to set mt6359 buck mode: %d\n", ret); + } + + return ret; +} + +static int mt6359p_vemc_set_voltage_sel(struct regulator_dev *rdev, + u32 sel) +{ + struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + u32 val = 0; + + sel <<= ffs(info->desc.vsel_mask) - 1; + ret = regmap_write(rdev->regmap, MT6359P_TMA_KEY_ADDR, TMA_KEY); + if (ret) + return ret; + + ret = regmap_read(rdev->regmap, MT6359P_VM_MODE_ADDR, &val); + if (ret) + return ret; + + switch (val) { + case 0: + /* If HW trapping is 0, use VEMC_VOSEL_0 */ + ret = regmap_update_bits(rdev->regmap, + info->desc.vsel_reg, + info->desc.vsel_mask, sel); + break; + case 1: + /* If HW trapping is 1, use VEMC_VOSEL_1 */ + ret = regmap_update_bits(rdev->regmap, + info->desc.vsel_reg + 0x2, + info->desc.vsel_mask, sel); + break; + default: + return -EINVAL; + } + + if (ret) + return ret; + + ret = regmap_write(rdev->regmap, MT6359P_TMA_KEY_ADDR, 0); + return ret; +} + +static int mt6359p_vemc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct mt6359_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + u32 val = 0; + + ret = regmap_read(rdev->regmap, MT6359P_VM_MODE_ADDR, &val); + if (ret) + return ret; + switch (val) { + case 0: + /* If HW trapping is 0, use VEMC_VOSEL_0 */ + ret = regmap_read(rdev->regmap, + info->desc.vsel_reg, &val); + break; + case 1: + /* If HW trapping is 1, use VEMC_VOSEL_1 */ + ret = regmap_read(rdev->regmap, + info->desc.vsel_reg + 0x2, &val); + break; + default: + return -EINVAL; + } + if (ret) + return ret; + + val &= info->desc.vsel_mask; + val >>= ffs(info->desc.vsel_mask) - 1; + + return val; +} + +static const struct regulator_ops mt6359_volt_linear_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .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, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6359_get_status, + .set_mode = mt6359_regulator_set_mode, + .get_mode = mt6359_regulator_get_mode, +}; + +static const struct regulator_ops mt6359_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .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, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6359_get_status, +}; + +static const struct regulator_ops mt6359_volt_fixed_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6359_get_status, +}; + +static const struct regulator_ops mt6359p_vemc_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = mt6359p_vemc_set_voltage_sel, + .get_voltage_sel = mt6359p_vemc_get_voltage_sel, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6359_get_status, +}; + +/* The array is indexed by id(MT6359_ID_XXX) */ +static struct mt6359_regulator_info mt6359_regulators[] = { + MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500, + MT6359_RG_BUCK_VS1_EN_ADDR, + MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR, + MT6359_RG_BUCK_VS1_VOSEL_MASK << + MT6359_RG_BUCK_VS1_VOSEL_SHIFT, + MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT, + MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT), + MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250, + MT6359_RG_BUCK_VGPU11_EN_ADDR, + MT6359_DA_VGPU11_EN_ADDR, MT6359_RG_BUCK_VGPU11_VOSEL_ADDR, + MT6359_RG_BUCK_VGPU11_VOSEL_MASK << + MT6359_RG_BUCK_VGPU11_VOSEL_SHIFT, + MT6359_RG_BUCK_VGPU11_LP_ADDR, + MT6359_RG_BUCK_VGPU11_LP_SHIFT, + MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT), + MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250, + MT6359_RG_BUCK_VMODEM_EN_ADDR, + MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR, + MT6359_RG_BUCK_VMODEM_VOSEL_MASK << + MT6359_RG_BUCK_VMODEM_VOSEL_SHIFT, + MT6359_RG_BUCK_VMODEM_LP_ADDR, + MT6359_RG_BUCK_VMODEM_LP_SHIFT, + MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT), + MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250, + MT6359_RG_BUCK_VPU_EN_ADDR, + MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR, + MT6359_RG_BUCK_VPU_VOSEL_MASK << + MT6359_RG_BUCK_VPU_VOSEL_SHIFT, + MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT, + MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT), + MT6359_BUCK("buck_vcore", VCORE, 400000, 1193750, 6250, + MT6359_RG_BUCK_VCORE_EN_ADDR, + MT6359_DA_VCORE_EN_ADDR, MT6359_RG_BUCK_VCORE_VOSEL_ADDR, + MT6359_RG_BUCK_VCORE_VOSEL_MASK << + MT6359_RG_BUCK_VCORE_VOSEL_SHIFT, + MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT, + MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT), + MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500, + MT6359_RG_BUCK_VS2_EN_ADDR, + MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR, + MT6359_RG_BUCK_VS2_VOSEL_MASK << + MT6359_RG_BUCK_VS2_VOSEL_SHIFT, + MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT, + MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT), + MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, + MT6359_RG_BUCK_VPA_EN_ADDR, + MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR, + MT6359_RG_BUCK_VPA_VOSEL_MASK << + MT6359_RG_BUCK_VPA_VOSEL_SHIFT, + MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT, + MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT), + MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250, + MT6359_RG_BUCK_VPROC2_EN_ADDR, + MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR, + MT6359_RG_BUCK_VPROC2_VOSEL_MASK << + MT6359_RG_BUCK_VPROC2_VOSEL_SHIFT, + MT6359_RG_BUCK_VPROC2_LP_ADDR, + MT6359_RG_BUCK_VPROC2_LP_SHIFT, + MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT), + MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250, + MT6359_RG_BUCK_VPROC1_EN_ADDR, + MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR, + MT6359_RG_BUCK_VPROC1_VOSEL_MASK << + MT6359_RG_BUCK_VPROC1_VOSEL_SHIFT, + MT6359_RG_BUCK_VPROC1_LP_ADDR, + MT6359_RG_BUCK_VPROC1_LP_SHIFT, + MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT), + MT6359_BUCK("buck_vcore_sshub", VCORE_SSHUB, 400000, 1193750, 6250, + MT6359_RG_BUCK_VCORE_SSHUB_EN_ADDR, + MT6359_DA_VCORE_EN_ADDR, + MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_ADDR, + MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_MASK << + MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_SHIFT, + MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT, + MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT), + MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359_RG_LDO_VAUD18_EN_ADDR, + MT6359_DA_VAUD18_B_EN_ADDR, 1800000), + MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages, + MT6359_RG_LDO_VSIM1_EN_ADDR, MT6359_RG_LDO_VSIM1_EN_SHIFT, + MT6359_DA_VSIM1_B_EN_ADDR, MT6359_RG_VSIM1_VOSEL_ADDR, + MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT, + 480), + MT6359_LDO("ldo_vibr", VIBR, vibr_voltages, + MT6359_RG_LDO_VIBR_EN_ADDR, MT6359_RG_LDO_VIBR_EN_SHIFT, + MT6359_DA_VIBR_B_EN_ADDR, MT6359_RG_VIBR_VOSEL_ADDR, + MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages, + MT6359_RG_LDO_VRF12_EN_ADDR, MT6359_RG_LDO_VRF12_EN_SHIFT, + MT6359_DA_VRF12_B_EN_ADDR, MT6359_RG_VRF12_VOSEL_ADDR, + MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT, + 120), + MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359_RG_LDO_VUSB_EN_0_ADDR, + MT6359_DA_VUSB_B_EN_ADDR, 3000000), + MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250, + MT6359_RG_LDO_VSRAM_PROC2_EN_ADDR, + MT6359_DA_VSRAM_PROC2_B_EN_ADDR, + MT6359_RG_LDO_VSRAM_PROC2_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT), + MT6359_LDO("ldo_vio18", VIO18, volt18_voltages, + MT6359_RG_LDO_VIO18_EN_ADDR, MT6359_RG_LDO_VIO18_EN_SHIFT, + MT6359_DA_VIO18_B_EN_ADDR, MT6359_RG_VIO18_VOSEL_ADDR, + MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT, + 960), + MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages, + MT6359_RG_LDO_VCAMIO_EN_ADDR, MT6359_RG_LDO_VCAMIO_EN_SHIFT, + MT6359_DA_VCAMIO_B_EN_ADDR, MT6359_RG_VCAMIO_VOSEL_ADDR, + MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT, + 1290), + MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359_RG_LDO_VCN18_EN_ADDR, + MT6359_DA_VCN18_B_EN_ADDR, 1800000), + MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359_RG_LDO_VFE28_EN_ADDR, + MT6359_DA_VFE28_B_EN_ADDR, 2800000), + MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages, + MT6359_RG_LDO_VCN13_EN_ADDR, MT6359_RG_LDO_VCN13_EN_SHIFT, + MT6359_DA_VCN13_B_EN_ADDR, MT6359_RG_VCN13_VOSEL_ADDR, + MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages, + MT6359_RG_LDO_VCN33_1_EN_0_ADDR, + MT6359_RG_LDO_VCN33_1_EN_0_SHIFT, + MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR, + MT6359_RG_VCN33_1_VOSEL_MASK << + MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), + MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages, + MT6359_RG_LDO_VCN33_1_EN_1_ADDR, + MT6359_RG_LDO_VCN33_1_EN_1_SHIFT, + MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR, + MT6359_RG_VCN33_1_VOSEL_MASK << + MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), + MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359_RG_LDO_VAUX18_EN_ADDR, + MT6359_DA_VAUX18_B_EN_ADDR, 1800000), + MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, + 6250, + MT6359_RG_LDO_VSRAM_OTHERS_EN_ADDR, + MT6359_DA_VSRAM_OTHERS_B_EN_ADDR, + MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT), + MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, + MT6359_RG_LDO_VEFUSE_EN_ADDR, MT6359_RG_LDO_VEFUSE_EN_SHIFT, + MT6359_DA_VEFUSE_B_EN_ADDR, MT6359_RG_VEFUSE_VOSEL_ADDR, + MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages, + MT6359_RG_LDO_VXO22_EN_ADDR, MT6359_RG_LDO_VXO22_EN_SHIFT, + MT6359_DA_VXO22_B_EN_ADDR, MT6359_RG_VXO22_VOSEL_ADDR, + MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT, + 120), + MT6359_LDO("ldo_vrfck", VRFCK, vrfck_voltages, + MT6359_RG_LDO_VRFCK_EN_ADDR, MT6359_RG_LDO_VRFCK_EN_SHIFT, + MT6359_DA_VRFCK_B_EN_ADDR, MT6359_RG_VRFCK_VOSEL_ADDR, + MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT, + 480), + MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359_RG_LDO_VBIF28_EN_ADDR, + MT6359_DA_VBIF28_B_EN_ADDR, 2800000), + MT6359_LDO("ldo_vio28", VIO28, vio28_voltages, + MT6359_RG_LDO_VIO28_EN_ADDR, MT6359_RG_LDO_VIO28_EN_SHIFT, + MT6359_DA_VIO28_B_EN_ADDR, MT6359_RG_VIO28_VOSEL_ADDR, + MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_vemc", VEMC, vemc_voltages, + MT6359_RG_LDO_VEMC_EN_ADDR, MT6359_RG_LDO_VEMC_EN_SHIFT, + MT6359_DA_VEMC_B_EN_ADDR, MT6359_RG_VEMC_VOSEL_ADDR, + MT6359_RG_VEMC_VOSEL_MASK << MT6359_RG_VEMC_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages, + MT6359_RG_LDO_VCN33_2_EN_0_ADDR, + MT6359_RG_LDO_VCN33_2_EN_0_SHIFT, + MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR, + MT6359_RG_VCN33_2_VOSEL_MASK << + MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), + MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages, + MT6359_RG_LDO_VCN33_2_EN_1_ADDR, + MT6359_RG_LDO_VCN33_2_EN_1_SHIFT, + MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR, + MT6359_RG_VCN33_2_VOSEL_MASK << + MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), + MT6359_LDO("ldo_va12", VA12, va12_voltages, + MT6359_RG_LDO_VA12_EN_ADDR, MT6359_RG_LDO_VA12_EN_SHIFT, + MT6359_DA_VA12_B_EN_ADDR, MT6359_RG_VA12_VOSEL_ADDR, + MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_va09", VA09, va09_voltages, + MT6359_RG_LDO_VA09_EN_ADDR, MT6359_RG_LDO_VA09_EN_SHIFT, + MT6359_DA_VA09_B_EN_ADDR, MT6359_RG_VA09_VOSEL_ADDR, + MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages, + MT6359_RG_LDO_VRF18_EN_ADDR, MT6359_RG_LDO_VRF18_EN_SHIFT, + MT6359_DA_VRF18_B_EN_ADDR, MT6359_RG_VRF18_VOSEL_ADDR, + MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT, + 120), + MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1100000, 6250, + MT6359_RG_LDO_VSRAM_MD_EN_ADDR, + MT6359_DA_VSRAM_MD_B_EN_ADDR, + MT6359_RG_LDO_VSRAM_MD_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT), + MT6359_LDO("ldo_vufs", VUFS, volt18_voltages, + MT6359_RG_LDO_VUFS_EN_ADDR, MT6359_RG_LDO_VUFS_EN_SHIFT, + MT6359_DA_VUFS_B_EN_ADDR, MT6359_RG_VUFS_VOSEL_ADDR, + MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT, + 1920), + MT6359_LDO("ldo_vm18", VM18, volt18_voltages, + MT6359_RG_LDO_VM18_EN_ADDR, MT6359_RG_LDO_VM18_EN_SHIFT, + MT6359_DA_VM18_B_EN_ADDR, MT6359_RG_VM18_VOSEL_ADDR, + MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT, + 1920), + MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages, + MT6359_RG_LDO_VBBCK_EN_ADDR, MT6359_RG_LDO_VBBCK_EN_SHIFT, + MT6359_DA_VBBCK_B_EN_ADDR, MT6359_RG_VBBCK_VOSEL_ADDR, + MT6359_RG_VBBCK_VOSEL_MASK << MT6359_RG_VBBCK_VOSEL_SHIFT, + 240), + MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250, + MT6359_RG_LDO_VSRAM_PROC1_EN_ADDR, + MT6359_DA_VSRAM_PROC1_B_EN_ADDR, + MT6359_RG_LDO_VSRAM_PROC1_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT), + MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages, + MT6359_RG_LDO_VSIM2_EN_ADDR, MT6359_RG_LDO_VSIM2_EN_SHIFT, + MT6359_DA_VSIM2_B_EN_ADDR, MT6359_RG_VSIM2_VOSEL_ADDR, + MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT, + 480), + MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, + 500000, 1293750, 6250, + MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR, + MT6359_DA_VSRAM_OTHERS_B_EN_ADDR, + MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT), +}; + +static struct mt6359_regulator_info mt6359p_regulators[] = { + MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500, + MT6359_RG_BUCK_VS1_EN_ADDR, + MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR, + MT6359_RG_BUCK_VS1_VOSEL_MASK << + MT6359_RG_BUCK_VS1_VOSEL_SHIFT, + MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT, + MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT), + MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250, + MT6359_RG_BUCK_VGPU11_EN_ADDR, + MT6359_DA_VGPU11_EN_ADDR, MT6359P_RG_BUCK_VGPU11_VOSEL_ADDR, + MT6359_RG_BUCK_VGPU11_VOSEL_MASK << + MT6359_RG_BUCK_VGPU11_VOSEL_SHIFT, + MT6359_RG_BUCK_VGPU11_LP_ADDR, + MT6359_RG_BUCK_VGPU11_LP_SHIFT, + MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT), + MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250, + MT6359_RG_BUCK_VMODEM_EN_ADDR, + MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR, + MT6359_RG_BUCK_VMODEM_VOSEL_MASK << + MT6359_RG_BUCK_VMODEM_VOSEL_SHIFT, + MT6359_RG_BUCK_VMODEM_LP_ADDR, + MT6359_RG_BUCK_VMODEM_LP_SHIFT, + MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT), + MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250, + MT6359_RG_BUCK_VPU_EN_ADDR, + MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR, + MT6359_RG_BUCK_VPU_VOSEL_MASK << + MT6359_RG_BUCK_VPU_VOSEL_SHIFT, + MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT, + MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT), + MT6359_BUCK("buck_vcore", VCORE, 506250, 1300000, 6250, + MT6359_RG_BUCK_VCORE_EN_ADDR, + MT6359_DA_VCORE_EN_ADDR, MT6359P_RG_BUCK_VCORE_VOSEL_ADDR, + MT6359_RG_BUCK_VCORE_VOSEL_MASK << + MT6359_RG_BUCK_VCORE_VOSEL_SHIFT, + MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT, + MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT), + MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500, + MT6359_RG_BUCK_VS2_EN_ADDR, + MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR, + MT6359_RG_BUCK_VS2_VOSEL_MASK << + MT6359_RG_BUCK_VS2_VOSEL_SHIFT, + MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT, + MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT), + MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, + MT6359_RG_BUCK_VPA_EN_ADDR, + MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR, + MT6359_RG_BUCK_VPA_VOSEL_MASK << + MT6359_RG_BUCK_VPA_VOSEL_SHIFT, + MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT, + MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT), + MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250, + MT6359_RG_BUCK_VPROC2_EN_ADDR, + MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR, + MT6359_RG_BUCK_VPROC2_VOSEL_MASK << + MT6359_RG_BUCK_VPROC2_VOSEL_SHIFT, + MT6359_RG_BUCK_VPROC2_LP_ADDR, + MT6359_RG_BUCK_VPROC2_LP_SHIFT, + MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT), + MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250, + MT6359_RG_BUCK_VPROC1_EN_ADDR, + MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR, + MT6359_RG_BUCK_VPROC1_VOSEL_MASK << + MT6359_RG_BUCK_VPROC1_VOSEL_SHIFT, + MT6359_RG_BUCK_VPROC1_LP_ADDR, + MT6359_RG_BUCK_VPROC1_LP_SHIFT, + MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT), + MT6359_BUCK("buck_vgpu11_sshub", VGPU11_SSHUB, 400000, 1193750, 6250, + MT6359P_RG_BUCK_VGPU11_SSHUB_EN_ADDR, + MT6359_DA_VGPU11_EN_ADDR, + MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_ADDR, + MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_MASK << + MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_SHIFT, + MT6359_RG_BUCK_VGPU11_LP_ADDR, + MT6359_RG_BUCK_VGPU11_LP_SHIFT, + MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT), + MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359P_RG_LDO_VAUD18_EN_ADDR, + MT6359P_DA_VAUD18_B_EN_ADDR, 1800000), + MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages, + MT6359P_RG_LDO_VSIM1_EN_ADDR, MT6359P_RG_LDO_VSIM1_EN_SHIFT, + MT6359P_DA_VSIM1_B_EN_ADDR, MT6359P_RG_VSIM1_VOSEL_ADDR, + MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT, + 480), + MT6359_LDO("ldo_vibr", VIBR, vibr_voltages, + MT6359P_RG_LDO_VIBR_EN_ADDR, MT6359P_RG_LDO_VIBR_EN_SHIFT, + MT6359P_DA_VIBR_B_EN_ADDR, MT6359P_RG_VIBR_VOSEL_ADDR, + MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages, + MT6359P_RG_LDO_VRF12_EN_ADDR, MT6359P_RG_LDO_VRF12_EN_SHIFT, + MT6359P_DA_VRF12_B_EN_ADDR, MT6359P_RG_VRF12_VOSEL_ADDR, + MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT, + 480), + MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359P_RG_LDO_VUSB_EN_0_ADDR, + MT6359P_DA_VUSB_B_EN_ADDR, 3000000), + MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250, + MT6359P_RG_LDO_VSRAM_PROC2_EN_ADDR, + MT6359P_DA_VSRAM_PROC2_B_EN_ADDR, + MT6359P_RG_LDO_VSRAM_PROC2_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT), + MT6359_LDO("ldo_vio18", VIO18, volt18_voltages, + MT6359P_RG_LDO_VIO18_EN_ADDR, MT6359P_RG_LDO_VIO18_EN_SHIFT, + MT6359P_DA_VIO18_B_EN_ADDR, MT6359P_RG_VIO18_VOSEL_ADDR, + MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT, + 960), + MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages, + MT6359P_RG_LDO_VCAMIO_EN_ADDR, + MT6359P_RG_LDO_VCAMIO_EN_SHIFT, + MT6359P_DA_VCAMIO_B_EN_ADDR, MT6359P_RG_VCAMIO_VOSEL_ADDR, + MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT, + 1290), + MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359P_RG_LDO_VCN18_EN_ADDR, + MT6359P_DA_VCN18_B_EN_ADDR, 1800000), + MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359P_RG_LDO_VFE28_EN_ADDR, + MT6359P_DA_VFE28_B_EN_ADDR, 2800000), + MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages, + MT6359P_RG_LDO_VCN13_EN_ADDR, MT6359P_RG_LDO_VCN13_EN_SHIFT, + MT6359P_DA_VCN13_B_EN_ADDR, MT6359P_RG_VCN13_VOSEL_ADDR, + MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages, + MT6359P_RG_LDO_VCN33_1_EN_0_ADDR, + MT6359_RG_LDO_VCN33_1_EN_0_SHIFT, + MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR, + MT6359_RG_VCN33_1_VOSEL_MASK << + MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), + MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages, + MT6359P_RG_LDO_VCN33_1_EN_1_ADDR, + MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT, + MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR, + MT6359_RG_VCN33_1_VOSEL_MASK << + MT6359_RG_VCN33_1_VOSEL_SHIFT, 240), + MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359P_RG_LDO_VAUX18_EN_ADDR, + MT6359P_DA_VAUX18_B_EN_ADDR, 1800000), + MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, + 6250, + MT6359P_RG_LDO_VSRAM_OTHERS_EN_ADDR, + MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR, + MT6359P_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT), + MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, + MT6359P_RG_LDO_VEFUSE_EN_ADDR, + MT6359P_RG_LDO_VEFUSE_EN_SHIFT, + MT6359P_DA_VEFUSE_B_EN_ADDR, MT6359P_RG_VEFUSE_VOSEL_ADDR, + MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT, + 240), + MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages, + MT6359P_RG_LDO_VXO22_EN_ADDR, MT6359P_RG_LDO_VXO22_EN_SHIFT, + MT6359P_DA_VXO22_B_EN_ADDR, MT6359P_RG_VXO22_VOSEL_ADDR, + MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT, + 480), + MT6359_LDO("ldo_vrfck_1", VRFCK, vrfck_voltages_1, + MT6359P_RG_LDO_VRFCK_EN_ADDR, MT6359P_RG_LDO_VRFCK_EN_SHIFT, + MT6359P_DA_VRFCK_B_EN_ADDR, MT6359P_RG_VRFCK_VOSEL_ADDR, + MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT, + 480), + MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359P_RG_LDO_VBIF28_EN_ADDR, + MT6359P_DA_VBIF28_B_EN_ADDR, 2800000), + MT6359_LDO("ldo_vio28", VIO28, vio28_voltages, + MT6359P_RG_LDO_VIO28_EN_ADDR, MT6359P_RG_LDO_VIO28_EN_SHIFT, + MT6359P_DA_VIO28_B_EN_ADDR, MT6359P_RG_VIO28_VOSEL_ADDR, + MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT, + 1920), + MT6359P_LDO1("ldo_vemc_1", VEMC, mt6359p_vemc_ops, vemc_voltages_1, + MT6359P_RG_LDO_VEMC_EN_ADDR, MT6359P_RG_LDO_VEMC_EN_SHIFT, + MT6359P_DA_VEMC_B_EN_ADDR, + MT6359P_RG_LDO_VEMC_VOSEL_0_ADDR, + MT6359P_RG_LDO_VEMC_VOSEL_0_MASK << + MT6359P_RG_LDO_VEMC_VOSEL_0_SHIFT), + MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages, + MT6359P_RG_LDO_VCN33_2_EN_0_ADDR, + MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT, + MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR, + MT6359_RG_VCN33_2_VOSEL_MASK << + MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), + MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages, + MT6359P_RG_LDO_VCN33_2_EN_1_ADDR, + MT6359_RG_LDO_VCN33_2_EN_1_SHIFT, + MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR, + MT6359_RG_VCN33_2_VOSEL_MASK << + MT6359_RG_VCN33_2_VOSEL_SHIFT, 240), + MT6359_LDO("ldo_va12", VA12, va12_voltages, + MT6359P_RG_LDO_VA12_EN_ADDR, MT6359P_RG_LDO_VA12_EN_SHIFT, + MT6359P_DA_VA12_B_EN_ADDR, MT6359P_RG_VA12_VOSEL_ADDR, + MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT, + 960), + MT6359_LDO("ldo_va09", VA09, va09_voltages, + MT6359P_RG_LDO_VA09_EN_ADDR, MT6359P_RG_LDO_VA09_EN_SHIFT, + MT6359P_DA_VA09_B_EN_ADDR, MT6359P_RG_VA09_VOSEL_ADDR, + MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT, + 960), + MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages, + MT6359P_RG_LDO_VRF18_EN_ADDR, MT6359P_RG_LDO_VRF18_EN_SHIFT, + MT6359P_DA_VRF18_B_EN_ADDR, MT6359P_RG_VRF18_VOSEL_ADDR, + MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT, + 240), + MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1293750, 6250, + MT6359P_RG_LDO_VSRAM_MD_EN_ADDR, + MT6359P_DA_VSRAM_MD_B_EN_ADDR, + MT6359P_RG_LDO_VSRAM_MD_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT), + MT6359_LDO("ldo_vufs", VUFS, volt18_voltages, + MT6359P_RG_LDO_VUFS_EN_ADDR, MT6359P_RG_LDO_VUFS_EN_SHIFT, + MT6359P_DA_VUFS_B_EN_ADDR, MT6359P_RG_VUFS_VOSEL_ADDR, + MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT, + 1920), + MT6359_LDO("ldo_vm18", VM18, volt18_voltages, + MT6359P_RG_LDO_VM18_EN_ADDR, MT6359P_RG_LDO_VM18_EN_SHIFT, + MT6359P_DA_VM18_B_EN_ADDR, MT6359P_RG_VM18_VOSEL_ADDR, + MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT, + 1920), + MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages, + MT6359P_RG_LDO_VBBCK_EN_ADDR, MT6359P_RG_LDO_VBBCK_EN_SHIFT, + MT6359P_DA_VBBCK_B_EN_ADDR, MT6359P_RG_VBBCK_VOSEL_ADDR, + MT6359P_RG_VBBCK_VOSEL_MASK << MT6359P_RG_VBBCK_VOSEL_SHIFT, + 480), + MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250, + MT6359P_RG_LDO_VSRAM_PROC1_EN_ADDR, + MT6359P_DA_VSRAM_PROC1_B_EN_ADDR, + MT6359P_RG_LDO_VSRAM_PROC1_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT), + MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages, + MT6359P_RG_LDO_VSIM2_EN_ADDR, MT6359P_RG_LDO_VSIM2_EN_SHIFT, + MT6359P_DA_VSIM2_B_EN_ADDR, MT6359P_RG_VSIM2_VOSEL_ADDR, + MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT, + 480), + MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, + 500000, 1293750, 6250, + MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR, + MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR, + MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR, + MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK << + MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT), +}; + +static int mt6359_regulator_probe(struct platform_device *pdev) +{ + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = {}; + struct regulator_dev *rdev; + struct mt6359_regulator_info *mt6359_info; + int i, hw_ver; + + regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver); + if (hw_ver >= MT6359P_CHIP_VER) + mt6359_info = mt6359p_regulators; + else + mt6359_info = mt6359_regulators; + + config.dev = mt6397->dev; + config.regmap = mt6397->regmap; + for (i = 0; i < MT6359_MAX_REGULATOR; i++, mt6359_info++) { + config.driver_data = mt6359_info; + rdev = devm_regulator_register(&pdev->dev, &mt6359_info->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", mt6359_info->desc.name); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id mt6359_platform_ids[] = { + {"mt6359-regulator", 0}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, mt6359_platform_ids); + +static struct platform_driver mt6359_regulator_driver = { + .driver = { + .name = "mt6359-regulator", + }, + .probe = mt6359_regulator_probe, + .id_table = mt6359_platform_ids, +}; + +module_platform_driver(mt6359_regulator_driver); + +MODULE_AUTHOR("Wen Su <wen.su@mediatek.com>"); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6359 PMIC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 49f6c05fee34..f54d4f176882 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -21,6 +21,62 @@ static const char *const regulator_states[PM_SUSPEND_MAX + 1] = { [PM_SUSPEND_MAX] = "regulator-state-disk", }; +static void fill_limit(int *limit, int val) +{ + if (val) + if (val == 1) + *limit = REGULATOR_NOTIF_LIMIT_ENABLE; + else + *limit = val; + else + *limit = REGULATOR_NOTIF_LIMIT_DISABLE; +} + +static void of_get_regulator_prot_limits(struct device_node *np, + struct regulation_constraints *constraints) +{ + u32 pval; + int i; + static const char *const props[] = { + "regulator-oc-%s-microamp", + "regulator-ov-%s-microvolt", + "regulator-temp-%s-kelvin", + "regulator-uv-%s-microvolt", + }; + struct notification_limit *limits[] = { + &constraints->over_curr_limits, + &constraints->over_voltage_limits, + &constraints->temp_limits, + &constraints->under_voltage_limits, + }; + bool set[4] = {0}; + + /* Protection limits: */ + for (i = 0; i < ARRAY_SIZE(props); i++) { + char prop[255]; + bool found; + int j; + static const char *const lvl[] = { + "protection", "error", "warn" + }; + int *l[] = { + &limits[i]->prot, &limits[i]->err, &limits[i]->warn, + }; + + for (j = 0; j < ARRAY_SIZE(lvl); j++) { + snprintf(prop, 255, props[i], lvl[j]); + found = !of_property_read_u32(np, prop, &pval); + if (found) + fill_limit(l[j], pval); + set[i] |= found; + } + } + constraints->over_current_detection = set[0]; + constraints->over_voltage_detection = set[1]; + constraints->over_temp_detection = set[2]; + constraints->under_voltage_detection = set[3]; +} + static int of_get_regulation_constraints(struct device *dev, struct device_node *np, struct regulator_init_data **init_data, @@ -188,6 +244,8 @@ static int of_get_regulation_constraints(struct device *dev, constraints->over_current_protection = of_property_read_bool(np, "regulator-over-current-protection"); + of_get_regulator_prot_limits(np, constraints); + for (i = 0; i < ARRAY_SIZE(regulator_states); i++) { switch (i) { case PM_SUSPEND_MEM: diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c index 2f7ee212cb8c..64e5f5f0cc84 100644 --- a/drivers/regulator/pca9450-regulator.c +++ b/drivers/regulator/pca9450-regulator.c @@ -65,32 +65,9 @@ static const struct regmap_config pca9450_regmap_config = { * 10: 25mV/4usec * 11: 25mV/8usec */ -static int pca9450_dvs_set_ramp_delay(struct regulator_dev *rdev, - int ramp_delay) -{ - int id = rdev_get_id(rdev); - unsigned int ramp_value; - - switch (ramp_delay) { - case 1 ... 3125: - ramp_value = BUCK1_RAMP_3P125MV; - break; - case 3126 ... 6250: - ramp_value = BUCK1_RAMP_6P25MV; - break; - case 6251 ... 12500: - ramp_value = BUCK1_RAMP_12P5MV; - break; - case 12501 ... 25000: - ramp_value = BUCK1_RAMP_25MV; - break; - default: - ramp_value = BUCK1_RAMP_25MV; - } - - return regmap_update_bits(rdev->regmap, PCA9450_REG_BUCK1CTRL + id * 3, - BUCK1_RAMP_MASK, ramp_value << 6); -} +static const unsigned int pca9450_dvs_buck_ramp_table[] = { + 25000, 12500, 6250, 3125 +}; static const struct regulator_ops pca9450_dvs_buck_regulator_ops = { .enable = regulator_enable_regmap, @@ -100,7 +77,7 @@ static const struct regulator_ops pca9450_dvs_buck_regulator_ops = { .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 = pca9450_dvs_set_ramp_delay, + .set_ramp_delay = regulator_set_ramp_delay_regmap, }; static const struct regulator_ops pca9450_buck_regulator_ops = { @@ -251,6 +228,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK1OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK1CTRL, .enable_mask = BUCK1_ENMODE_MASK, + .ramp_reg = PCA9450_REG_BUCK1CTRL, + .ramp_mask = BUCK1_RAMP_MASK, + .ramp_delay_table = pca9450_dvs_buck_ramp_table, + .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), .owner = THIS_MODULE, .of_parse_cb = pca9450_set_dvs_levels, }, @@ -276,6 +257,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK2OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK2CTRL, .enable_mask = BUCK1_ENMODE_MASK, + .ramp_reg = PCA9450_REG_BUCK2CTRL, + .ramp_mask = BUCK2_RAMP_MASK, + .ramp_delay_table = pca9450_dvs_buck_ramp_table, + .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), .owner = THIS_MODULE, .of_parse_cb = pca9450_set_dvs_levels, }, @@ -301,6 +286,10 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = { .vsel_mask = BUCK3OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK3CTRL, .enable_mask = BUCK3_ENMODE_MASK, + .ramp_reg = PCA9450_REG_BUCK3CTRL, + .ramp_mask = BUCK3_RAMP_MASK, + .ramp_delay_table = pca9450_dvs_buck_ramp_table, + .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), .owner = THIS_MODULE, .of_parse_cb = pca9450_set_dvs_levels, }, @@ -477,6 +466,10 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK1OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK1CTRL, .enable_mask = BUCK1_ENMODE_MASK, + .ramp_reg = PCA9450_REG_BUCK1CTRL, + .ramp_mask = BUCK1_RAMP_MASK, + .ramp_delay_table = pca9450_dvs_buck_ramp_table, + .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), .owner = THIS_MODULE, .of_parse_cb = pca9450_set_dvs_levels, }, @@ -502,6 +495,10 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = { .vsel_mask = BUCK2OUT_DVS0_MASK, .enable_reg = PCA9450_REG_BUCK2CTRL, .enable_mask = BUCK1_ENMODE_MASK, + .ramp_reg = PCA9450_REG_BUCK2CTRL, + .ramp_mask = BUCK2_RAMP_MASK, + .ramp_delay_table = pca9450_dvs_buck_ramp_table, + .n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table), .owner = THIS_MODULE, .of_parse_cb = pca9450_set_dvs_levels, }, diff --git a/drivers/regulator/qcom-labibb-regulator.c b/drivers/regulator/qcom-labibb-regulator.c index de25e3279b4b..b3da0dc58782 100644 --- a/drivers/regulator/qcom-labibb-regulator.c +++ b/drivers/regulator/qcom-labibb-regulator.c @@ -307,13 +307,21 @@ end: return IRQ_HANDLED; } -static int qcom_labibb_set_ocp(struct regulator_dev *rdev) +static int qcom_labibb_set_ocp(struct regulator_dev *rdev, int lim, + int severity, bool enable) { struct labibb_regulator *vreg = rdev_get_drvdata(rdev); char *ocp_irq_name; u32 irq_flags = IRQF_ONESHOT; int irq_trig_low, ret; + /* + * labibb supports only protection - and does not support setting + * limit. Furthermore, we don't support disabling protection. + */ + if (lim || severity != REGULATOR_SEVERITY_PROT || !enable) + return -EINVAL; + /* If there is no OCP interrupt, there's nothing to set */ if (vreg->ocp_irq <= 0) return -EINVAL; diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 22fec370fa61..6cca910a76de 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -811,12 +811,12 @@ static const struct rpmh_vreg_init_data pm8998_vreg_data[] = { RPMH_VREG("ldo28", "ldo%s28", &pmic4_pldo, "vdd-l16-l28"), RPMH_VREG("lvs1", "vs%s1", &pmic4_lvs, "vin-lvs-1-2"), RPMH_VREG("lvs2", "vs%s2", &pmic4_lvs, "vin-lvs-1-2"), - {}, + {} }; static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = { RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"), - {}, + {} }; static const struct rpmh_vreg_init_data pm8005_vreg_data[] = { @@ -824,7 +824,7 @@ static const struct rpmh_vreg_init_data pm8005_vreg_data[] = { RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"), RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"), RPMH_VREG("smps4", "smp%s4", &pmic4_ftsmps426, "vdd-s4"), - {}, + {} }; static const struct rpmh_vreg_init_data pm8150_vreg_data[] = { @@ -856,7 +856,7 @@ static const struct rpmh_vreg_init_data pm8150_vreg_data[] = { RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"), RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"), RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"), - {}, + {} }; static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = { @@ -880,7 +880,39 @@ static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = { RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"), RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"), RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), - {}, + {} +}; + +static const struct rpmh_vreg_init_data pmm8155au_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"), + RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"), + RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"), + RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + {} }; static const struct rpmh_vreg_init_data pm8350_vreg_data[] = { @@ -906,7 +938,7 @@ static const struct rpmh_vreg_init_data pm8350_vreg_data[] = { RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"), RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"), RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"), - {}, + {} }; static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = { @@ -934,7 +966,7 @@ static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = { RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l1-l12"), RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"), RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), - {}, + {} }; static const struct rpmh_vreg_init_data pm8009_vreg_data[] = { @@ -947,7 +979,7 @@ static const struct rpmh_vreg_init_data pm8009_vreg_data[] = { RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"), RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"), RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"), - {}, + {} }; static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = { @@ -960,7 +992,7 @@ static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = { RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"), RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"), RPMH_VREG("ldo7", "ldo%s6", &pmic5_pldo_lv, "vdd-l7"), - {}, + {} }; static const struct rpmh_vreg_init_data pm6150_vreg_data[] = { @@ -988,7 +1020,7 @@ static const struct rpmh_vreg_init_data pm6150_vreg_data[] = { RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"), - {}, + {} }; static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { @@ -1012,7 +1044,7 @@ static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"), RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"), RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), - {}, + {} }; static const struct rpmh_vreg_init_data pmx55_vreg_data[] = { @@ -1039,7 +1071,7 @@ static const struct rpmh_vreg_init_data pmx55_vreg_data[] = { RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"), RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"), RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l16"), - {}, + {} }; static const struct rpmh_vreg_init_data pm7325_vreg_data[] = { @@ -1070,6 +1102,7 @@ static const struct rpmh_vreg_init_data pm7325_vreg_data[] = { RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"), + {} }; static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = { @@ -1083,6 +1116,7 @@ static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = { RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5-l6"), RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l5-l6"), RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-bob"), + {} }; static int rpmh_regulator_probe(struct platform_device *pdev) @@ -1176,6 +1210,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .data = pm8150l_vreg_data, }, { + .compatible = "qcom,pmm8155au-rpmh-regulators", + .data = pmm8155au_vreg_data, + }, + { .compatible = "qcom,pmx55-rpmh-regulators", .data = pmx55_vreg_data, }, diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index bb944ee5fe3b..198fcc6551f6 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -251,6 +251,50 @@ static const struct regulator_desc pma8084_switch = { .ops = &rpm_switch_ops, }; +static const struct regulator_desc pm8226_hfsmps = { + .linear_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(375000, 0, 95, 12500), + REGULATOR_LINEAR_RANGE(1575000, 96, 158, 25000), + }, + .n_linear_ranges = 2, + .n_voltages = 159, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8226_ftsmps = { + .linear_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000), + REGULATOR_LINEAR_RANGE(1280000, 185, 261, 10000), + }, + .n_linear_ranges = 2, + .n_voltages = 262, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8226_pldo = { + .linear_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500), + REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000), + REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000), + }, + .n_linear_ranges = 3, + .n_voltages = 164, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8226_nldo = { + .linear_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500), + }, + .n_linear_ranges = 1, + .n_voltages = 64, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8226_switch = { + .ops = &rpm_switch_ops, +}; + static const struct regulator_desc pm8x41_hfsmps = { .linear_ranges = (struct linear_range[]) { REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500), @@ -405,8 +449,8 @@ static const struct regulator_desc pm8950_pldo = { static const struct regulator_desc pm8953_lnldo = { .linear_ranges = (struct linear_range[]) { - REGULATOR_LINEAR_RANGE(1380000, 8, 15, 120000), REGULATOR_LINEAR_RANGE(690000, 0, 7, 60000), + REGULATOR_LINEAR_RANGE(1380000, 8, 15, 120000), }, .n_linear_ranges = 2, .n_voltages = 16, @@ -746,6 +790,44 @@ static const struct rpm_regulator_data rpm_pm8916_regulators[] = { {} }; +static const struct rpm_regulator_data rpm_pm8226_regulators[] = { + { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8226_hfsmps, "vdd_s1" }, + { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8226_ftsmps, "vdd_s2" }, + { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8226_hfsmps, "vdd_s3" }, + { "s4", QCOM_SMD_RPM_SMPA, 4, &pm8226_hfsmps, "vdd_s4" }, + { "s5", QCOM_SMD_RPM_SMPA, 5, &pm8226_hfsmps, "vdd_s5" }, + { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8226_nldo, "vdd_l1_l2_l4_l5" }, + { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8226_nldo, "vdd_l1_l2_l4_l5" }, + { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8226_nldo, "vdd_l3_l24_l26" }, + { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8226_nldo, "vdd_l1_l2_l4_l5" }, + { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8226_nldo, "vdd_l1_l2_l4_l5" }, + { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" }, + { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" }, + { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" }, + { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" }, + { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8226_pldo, "vdd_l10_l11_l13" }, + { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8226_pldo, "vdd_l10_l11_l13" }, + { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8226_pldo, "vdd_l12_l14" }, + { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8226_pldo, "vdd_l10_l11_l13" }, + { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8226_pldo, "vdd_l12_l14" }, + { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8226_pldo, "vdd_l15_l16_l17_l18" }, + { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8226_pldo, "vdd_l15_l16_l17_l18" }, + { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8226_pldo, "vdd_l15_l16_l17_l18" }, + { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8226_pldo, "vdd_l15_l16_l17_l18" }, + { "l19", QCOM_SMD_RPM_LDOA, 19, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" }, + { "l20", QCOM_SMD_RPM_LDOA, 20, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" }, + { "l21", QCOM_SMD_RPM_LDOA, 21, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" }, + { "l22", QCOM_SMD_RPM_LDOA, 22, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" }, + { "l23", QCOM_SMD_RPM_LDOA, 23, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" }, + { "l24", QCOM_SMD_RPM_LDOA, 24, &pm8226_nldo, "vdd_l3_l24_l26" }, + { "l25", QCOM_SMD_RPM_LDOA, 25, &pm8226_pldo, "vdd_l25" }, + { "l26", QCOM_SMD_RPM_LDOA, 26, &pm8226_nldo, "vdd_l3_l24_l26" }, + { "l27", QCOM_SMD_RPM_LDOA, 27, &pm8226_pldo, "vdd_l6_l7_l8_l9_l27" }, + { "l28", QCOM_SMD_RPM_LDOA, 28, &pm8226_pldo, "vdd_l19_l20_l21_l22_l23_l28" }, + { "lvs1", QCOM_SMD_RPM_VSA, 1, &pm8226_switch, "vdd_lvs1" }, + {} +}; + static const struct rpm_regulator_data rpm_pm8941_regulators[] = { { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" }, { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" }, @@ -1092,6 +1174,7 @@ static const struct of_device_id rpm_of_match[] = { { .compatible = "qcom,rpm-mp5496-regulators", .data = &rpm_mp5496_regulators }, { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators }, { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators }, + { .compatible = "qcom,rpm-pm8226-regulators", .data = &rpm_pm8226_regulators }, { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators }, { .compatible = "qcom,rpm-pm8950-regulators", .data = &rpm_pm8950_regulators }, { .compatible = "qcom,rpm-pm8953-regulators", .data = &rpm_pm8953_regulators }, diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 95677c51c1fa..41424a3366d0 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -595,11 +595,15 @@ static int spmi_regulator_vs_enable(struct regulator_dev *rdev) return regulator_enable_regmap(rdev); } -static int spmi_regulator_vs_ocp(struct regulator_dev *rdev) +static int spmi_regulator_vs_ocp(struct regulator_dev *rdev, int lim_uA, + int severity, bool enable) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); u8 reg = SPMI_VS_OCP_OVERRIDE; + if (lim_uA || !enable || severity != REGULATOR_SEVERITY_PROT) + return -EINVAL; + return spmi_vreg_write(vreg, SPMI_VS_REG_OCP, ®, 1); } diff --git a/drivers/regulator/qcom_usb_vbus-regulator.c b/drivers/regulator/qcom_usb_vbus-regulator.c index 457788b50572..2e627c2b6c51 100644 --- a/drivers/regulator/qcom_usb_vbus-regulator.c +++ b/drivers/regulator/qcom_usb_vbus-regulator.c @@ -16,13 +16,21 @@ #define CMD_OTG 0x40 #define OTG_EN BIT(0) +#define OTG_CURRENT_LIMIT_CFG 0x52 +#define OTG_CURRENT_LIMIT_MASK GENMASK(2, 0) #define OTG_CFG 0x53 #define OTG_EN_SRC_CFG BIT(1) +static const unsigned int curr_table[] = { + 500000, 1000000, 1500000, 2000000, 2500000, 3000000, +}; + static const struct regulator_ops qcom_usb_vbus_reg_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, + .get_current_limit = regulator_get_current_limit_regmap, + .set_current_limit = regulator_set_current_limit_regmap, }; static struct regulator_desc qcom_usb_vbus_rdesc = { @@ -30,6 +38,8 @@ static struct regulator_desc qcom_usb_vbus_rdesc = { .ops = &qcom_usb_vbus_reg_ops, .owner = THIS_MODULE, .type = REGULATOR_VOLTAGE, + .curr_table = curr_table, + .n_current_limits = ARRAY_SIZE(curr_table), }; static int qcom_usb_vbus_regulator_probe(struct platform_device *pdev) @@ -61,6 +71,8 @@ static int qcom_usb_vbus_regulator_probe(struct platform_device *pdev) qcom_usb_vbus_rdesc.enable_reg = base + CMD_OTG; qcom_usb_vbus_rdesc.enable_mask = OTG_EN; + qcom_usb_vbus_rdesc.csel_reg = base + OTG_CURRENT_LIMIT_CFG; + qcom_usb_vbus_rdesc.csel_mask = OTG_CURRENT_LIMIT_MASK; config.dev = dev; config.init_data = init_data; config.of_node = dev->of_node; diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index e926c1a85846..127dc2e2e690 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -158,13 +158,6 @@ struct rk808_regulator_data { struct gpio_desc *dvs_gpio[2]; }; -static const int rk808_buck_config_regs[] = { - RK808_BUCK1_CONFIG_REG, - RK808_BUCK2_CONFIG_REG, - RK808_BUCK3_CONFIG_REG, - RK808_BUCK4_CONFIG_REG, -}; - static const struct linear_range rk808_ldo3_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000), REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0), @@ -215,6 +208,15 @@ static const struct linear_range rk817_buck3_voltage_ranges[] = { RK817_BUCK3_SEL_CNT, RK817_BUCK1_STP1), }; +static const unsigned int rk808_buck1_2_ramp_table[] = { + 2000, 4000, 6000, 10000 +}; + +/* RK817 RK809 */ +static const unsigned int rk817_buck1_4_ramp_table[] = { + 3000, 6300, 12500, 25000 +}; + static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev) { struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); @@ -340,62 +342,6 @@ static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev, return regulator_set_voltage_time_sel(rdev, old_selector, new_selector); } -static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) -{ - unsigned int ramp_value = RK808_RAMP_RATE_10MV_PER_US; - unsigned int reg = rk808_buck_config_regs[rdev_get_id(rdev)]; - - switch (ramp_delay) { - case 1 ... 2000: - ramp_value = RK808_RAMP_RATE_2MV_PER_US; - break; - case 2001 ... 4000: - ramp_value = RK808_RAMP_RATE_4MV_PER_US; - break; - case 4001 ... 6000: - ramp_value = RK808_RAMP_RATE_6MV_PER_US; - break; - case 6001 ... 10000: - break; - default: - pr_warn("%s ramp_delay: %d not supported, setting 10000\n", - rdev->desc->name, ramp_delay); - } - - return regmap_update_bits(rdev->regmap, reg, - RK808_RAMP_RATE_MASK, ramp_value); -} - -/* - * RK817 RK809 - */ -static int rk817_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) -{ - unsigned int ramp_value = RK817_RAMP_RATE_25MV_PER_US; - unsigned int reg = RK817_BUCK_CONFIG_REG(rdev_get_id(rdev)); - - switch (ramp_delay) { - case 0 ... 3000: - ramp_value = RK817_RAMP_RATE_3MV_PER_US; - break; - case 3001 ... 6300: - ramp_value = RK817_RAMP_RATE_6_3MV_PER_US; - break; - case 6301 ... 12500: - ramp_value = RK817_RAMP_RATE_12_5MV_PER_US; - break; - case 12501 ... 25000: - break; - default: - dev_warn(&rdev->dev, - "%s ramp_delay: %d not supported, setting 25000\n", - rdev->desc->name, ramp_delay); - } - - return regmap_update_bits(rdev->regmap, reg, - RK817_RAMP_RATE_MASK, ramp_value); -} - static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv) { unsigned int reg; @@ -625,7 +571,7 @@ static const struct regulator_ops rk808_buck1_2_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, - .set_ramp_delay = rk808_set_ramp_delay, + .set_ramp_delay = regulator_set_ramp_delay_regmap, .set_suspend_voltage = rk808_set_suspend_voltage, .set_suspend_enable = rk808_set_suspend_enable, .set_suspend_disable = rk808_set_suspend_disable, @@ -722,7 +668,7 @@ static const struct regulator_ops rk817_buck_ops_range = { .set_mode = rk8xx_set_mode, .get_mode = rk8xx_get_mode, .set_suspend_mode = rk8xx_set_suspend_mode, - .set_ramp_delay = rk817_set_ramp_delay, + .set_ramp_delay = regulator_set_ramp_delay_regmap, .set_suspend_voltage = rk808_set_suspend_voltage_range, .set_suspend_enable = rk817_set_suspend_enable, .set_suspend_disable = rk817_set_suspend_disable, @@ -814,6 +760,10 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_BUCK_VSEL_MASK, .enable_reg = RK808_DCDC_EN_REG, .enable_mask = BIT(0), + .ramp_reg = RK808_BUCK1_CONFIG_REG, + .ramp_mask = RK808_RAMP_RATE_MASK, + .ramp_delay_table = rk808_buck1_2_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk808_buck1_2_ramp_table), .owner = THIS_MODULE, }, { .name = "DCDC_REG2", @@ -830,6 +780,10 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_BUCK_VSEL_MASK, .enable_reg = RK808_DCDC_EN_REG, .enable_mask = BIT(1), + .ramp_reg = RK808_BUCK2_CONFIG_REG, + .ramp_mask = RK808_RAMP_RATE_MASK, + .ramp_delay_table = rk808_buck1_2_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk808_buck1_2_ramp_table), .owner = THIS_MODULE, }, { .name = "DCDC_REG3", @@ -910,6 +864,10 @@ static const struct regulator_desc rk809_reg[] = { .enable_mask = ENABLE_MASK(RK817_ID_DCDC1), .enable_val = ENABLE_MASK(RK817_ID_DCDC1), .disable_val = DISABLE_VAL(RK817_ID_DCDC1), + .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC1), + .ramp_mask = RK817_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), .of_map_mode = rk8xx_regulator_of_map_mode, .owner = THIS_MODULE, }, { @@ -929,6 +887,10 @@ static const struct regulator_desc rk809_reg[] = { .enable_mask = ENABLE_MASK(RK817_ID_DCDC2), .enable_val = ENABLE_MASK(RK817_ID_DCDC2), .disable_val = DISABLE_VAL(RK817_ID_DCDC2), + .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC2), + .ramp_mask = RK817_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), .of_map_mode = rk8xx_regulator_of_map_mode, .owner = THIS_MODULE, }, { @@ -948,6 +910,10 @@ static const struct regulator_desc rk809_reg[] = { .enable_mask = ENABLE_MASK(RK817_ID_DCDC3), .enable_val = ENABLE_MASK(RK817_ID_DCDC3), .disable_val = DISABLE_VAL(RK817_ID_DCDC3), + .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC3), + .ramp_mask = RK817_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), .of_map_mode = rk8xx_regulator_of_map_mode, .owner = THIS_MODULE, }, { @@ -967,6 +933,10 @@ static const struct regulator_desc rk809_reg[] = { .enable_mask = ENABLE_MASK(RK817_ID_DCDC4), .enable_val = ENABLE_MASK(RK817_ID_DCDC4), .disable_val = DISABLE_VAL(RK817_ID_DCDC4), + .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC4), + .ramp_mask = RK817_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), .of_map_mode = rk8xx_regulator_of_map_mode, .owner = THIS_MODULE, }, @@ -1052,6 +1022,10 @@ static const struct regulator_desc rk817_reg[] = { .enable_mask = ENABLE_MASK(RK817_ID_DCDC1), .enable_val = ENABLE_MASK(RK817_ID_DCDC1), .disable_val = DISABLE_VAL(RK817_ID_DCDC1), + .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC1), + .ramp_mask = RK817_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), .of_map_mode = rk8xx_regulator_of_map_mode, .owner = THIS_MODULE, }, { @@ -1071,6 +1045,10 @@ static const struct regulator_desc rk817_reg[] = { .enable_mask = ENABLE_MASK(RK817_ID_DCDC2), .enable_val = ENABLE_MASK(RK817_ID_DCDC2), .disable_val = DISABLE_VAL(RK817_ID_DCDC2), + .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC2), + .ramp_mask = RK817_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), .of_map_mode = rk8xx_regulator_of_map_mode, .owner = THIS_MODULE, }, { @@ -1090,6 +1068,10 @@ static const struct regulator_desc rk817_reg[] = { .enable_mask = ENABLE_MASK(RK817_ID_DCDC3), .enable_val = ENABLE_MASK(RK817_ID_DCDC3), .disable_val = DISABLE_VAL(RK817_ID_DCDC3), + .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC3), + .ramp_mask = RK817_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), .of_map_mode = rk8xx_regulator_of_map_mode, .owner = THIS_MODULE, }, { @@ -1109,6 +1091,10 @@ static const struct regulator_desc rk817_reg[] = { .enable_mask = ENABLE_MASK(RK817_ID_DCDC4), .enable_val = ENABLE_MASK(RK817_ID_DCDC4), .disable_val = DISABLE_VAL(RK817_ID_DCDC4), + .ramp_reg = RK817_BUCK_CONFIG_REG(RK817_ID_DCDC4), + .ramp_mask = RK817_RAMP_RATE_MASK, + .ramp_delay_table = rk817_buck1_4_ramp_table, + .n_ramp_values = ARRAY_SIZE(rk817_buck1_4_ramp_table), .of_map_mode = rk8xx_regulator_of_map_mode, .owner = THIS_MODULE, }, diff --git a/drivers/regulator/rt4831-regulator.c b/drivers/regulator/rt4831-regulator.c index e3aaac90d238..676b0419e48f 100644 --- a/drivers/regulator/rt4831-regulator.c +++ b/drivers/regulator/rt4831-regulator.c @@ -108,6 +108,7 @@ static const struct regulator_desc rt4831_regulator_descs[] = { .bypass_reg = RT4831_REG_DSVEN, .bypass_val_on = DSV_MODE_BYPASS, .bypass_val_off = DSV_MODE_NORMAL, + .owner = THIS_MODULE, }, { .name = "DSVP", @@ -125,6 +126,7 @@ static const struct regulator_desc rt4831_regulator_descs[] = { .enable_mask = RT4831_POSEN_MASK, .active_discharge_reg = RT4831_REG_DSVEN, .active_discharge_mask = RT4831_POSADEN_MASK, + .owner = THIS_MODULE, }, { .name = "DSVN", @@ -142,6 +144,7 @@ static const struct regulator_desc rt4831_regulator_descs[] = { .enable_mask = RT4831_NEGEN_MASK, .active_discharge_reg = RT4831_REG_DSVEN, .active_discharge_mask = RT4831_NEGADEN_MASK, + .owner = THIS_MODULE, } }; diff --git a/drivers/regulator/rt6160-regulator.c b/drivers/regulator/rt6160-regulator.c new file mode 100644 index 000000000000..5d7b0e7ad69a --- /dev/null +++ b/drivers/regulator/rt6160-regulator.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +#define RT6160_MODE_AUTO 0 +#define RT6160_MODE_FPWM 1 + +#define RT6160_REG_CNTL 0x01 +#define RT6160_REG_STATUS 0x02 +#define RT6160_REG_DEVID 0x03 +#define RT6160_REG_VSELL 0x04 +#define RT6160_REG_VSELH 0x05 +#define RT6160_NUM_REGS (RT6160_REG_VSELH + 1) + +#define RT6160_FPWM_MASK BIT(3) +#define RT6160_RAMPRATE_MASK GENMASK(1, 0) +#define RT6160_VID_MASK GENMASK(7, 4) +#define RT6160_VSEL_MASK GENMASK(6, 0) +#define RT6160_HDSTAT_MASK BIT(4) +#define RT6160_UVSTAT_MASK BIT(3) +#define RT6160_OCSTAT_MASK BIT(2) +#define RT6160_TSDSTAT_MASK BIT(1) +#define RT6160_PGSTAT_MASK BIT(0) + +#define RT6160_VENDOR_ID 0xA0 +#define RT6160_VOUT_MINUV 2025000 +#define RT6160_VOUT_MAXUV 5200000 +#define RT6160_VOUT_STPUV 25000 +#define RT6160_N_VOUTS ((RT6160_VOUT_MAXUV - RT6160_VOUT_MINUV) / RT6160_VOUT_STPUV + 1) + +#define RT6160_I2CRDY_TIMEUS 100 + +struct rt6160_priv { + struct regulator_desc desc; + struct gpio_desc *enable_gpio; + struct regmap *regmap; + bool enable_state; +}; + +static const unsigned int rt6160_ramp_tables[] = { + 1000, 2500, 5000, 10000 +}; + +static int rt6160_enable(struct regulator_dev *rdev) +{ + struct rt6160_priv *priv = rdev_get_drvdata(rdev); + + if (!priv->enable_gpio) + return 0; + + gpiod_set_value_cansleep(priv->enable_gpio, 1); + priv->enable_state = true; + + usleep_range(RT6160_I2CRDY_TIMEUS, RT6160_I2CRDY_TIMEUS + 100); + + regcache_cache_only(priv->regmap, false); + return regcache_sync(priv->regmap); +} + +static int rt6160_disable(struct regulator_dev *rdev) +{ + struct rt6160_priv *priv = rdev_get_drvdata(rdev); + + if (!priv->enable_gpio) + return -EINVAL; + + /* Mark regcache as dirty and cache only before HW disabled */ + regcache_cache_only(priv->regmap, true); + regcache_mark_dirty(priv->regmap); + + priv->enable_state = false; + gpiod_set_value_cansleep(priv->enable_gpio, 0); + + return 0; +} + +static int rt6160_is_enabled(struct regulator_dev *rdev) +{ + struct rt6160_priv *priv = rdev_get_drvdata(rdev); + + return priv->enable_state ? 1 : 0; +} + +static int rt6160_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int mode_val; + + switch (mode) { + case REGULATOR_MODE_FAST: + mode_val = RT6160_FPWM_MASK; + break; + case REGULATOR_MODE_NORMAL: + mode_val = 0; + break; + default: + dev_err(&rdev->dev, "mode not supported\n"); + return -EINVAL; + } + + return regmap_update_bits(regmap, RT6160_REG_CNTL, RT6160_FPWM_MASK, mode_val); +} + +static unsigned int rt6160_get_mode(struct regulator_dev *rdev) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int val; + int ret; + + ret = regmap_read(regmap, RT6160_REG_CNTL, &val); + if (ret) + return ret; + + if (val & RT6160_FPWM_MASK) + return REGULATOR_MODE_FAST; + + return REGULATOR_MODE_NORMAL; +} + +static int rt6160_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int suspend_vsel_reg; + int vsel; + + vsel = regulator_map_voltage_linear(rdev, uV, uV); + if (vsel < 0) + return vsel; + + if (rdev->desc->vsel_reg == RT6160_REG_VSELL) + suspend_vsel_reg = RT6160_REG_VSELH; + else + suspend_vsel_reg = RT6160_REG_VSELL; + + return regmap_update_bits(regmap, suspend_vsel_reg, + RT6160_VSEL_MASK, vsel); +} + +static int rt6160_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) +{ + struct regmap *regmap = rdev_get_regmap(rdev); + unsigned int val, events = 0; + int ret; + + ret = regmap_read(regmap, RT6160_REG_STATUS, &val); + if (ret) + return ret; + + if (val & (RT6160_HDSTAT_MASK | RT6160_TSDSTAT_MASK)) + events |= REGULATOR_ERROR_OVER_TEMP; + + if (val & RT6160_UVSTAT_MASK) + events |= REGULATOR_ERROR_UNDER_VOLTAGE; + + if (val & RT6160_OCSTAT_MASK) + events |= REGULATOR_ERROR_OVER_CURRENT; + + if (val & RT6160_PGSTAT_MASK) + events |= REGULATOR_ERROR_FAIL; + + *flags = events; + return 0; +} + +static const struct regulator_ops rt6160_regulator_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + + .enable = rt6160_enable, + .disable = rt6160_disable, + .is_enabled = rt6160_is_enabled, + + .set_mode = rt6160_set_mode, + .get_mode = rt6160_get_mode, + .set_suspend_voltage = rt6160_set_suspend_voltage, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .get_error_flags = rt6160_get_error_flags, +}; + +static unsigned int rt6160_of_map_mode(unsigned int mode) +{ + switch (mode) { + case RT6160_MODE_FPWM: + return REGULATOR_MODE_FAST; + case RT6160_MODE_AUTO: + return REGULATOR_MODE_NORMAL; + } + + return REGULATOR_MODE_INVALID; +} + +static bool rt6160_is_accessible_reg(struct device *dev, unsigned int reg) +{ + if (reg >= RT6160_REG_CNTL && reg <= RT6160_REG_VSELH) + return true; + return false; +} + +static bool rt6160_is_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg == RT6160_REG_STATUS) + return true; + return false; +} + +static const struct regmap_config rt6160_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RT6160_REG_VSELH, + .num_reg_defaults_raw = RT6160_NUM_REGS, + .cache_type = REGCACHE_FLAT, + + .writeable_reg = rt6160_is_accessible_reg, + .readable_reg = rt6160_is_accessible_reg, + .volatile_reg = rt6160_is_volatile_reg, +}; + +static int rt6160_probe(struct i2c_client *i2c) +{ + struct rt6160_priv *priv; + struct regulator_config regulator_cfg = {}; + struct regulator_dev *rdev; + bool vsel_active_low; + unsigned int devid; + int ret; + + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + vsel_active_low = + device_property_present(&i2c->dev, "richtek,vsel-active-low"); + + priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(priv->enable_gpio)) { + dev_err(&i2c->dev, "Failed to get 'enable' gpio\n"); + return PTR_ERR(priv->enable_gpio); + } + priv->enable_state = true; + + usleep_range(RT6160_I2CRDY_TIMEUS, RT6160_I2CRDY_TIMEUS + 100); + + priv->regmap = devm_regmap_init_i2c(i2c, &rt6160_regmap_config); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(&i2c->dev, "Failed to init regmap (%d)\n", ret); + return ret; + } + + ret = regmap_read(priv->regmap, RT6160_REG_DEVID, &devid); + if (ret) + return ret; + + if ((devid & RT6160_VID_MASK) != RT6160_VENDOR_ID) { + dev_err(&i2c->dev, "VID not correct [0x%02x]\n", devid); + return -ENODEV; + } + + priv->desc.name = "rt6160-buckboost"; + priv->desc.type = REGULATOR_VOLTAGE; + priv->desc.owner = THIS_MODULE; + priv->desc.min_uV = RT6160_VOUT_MINUV; + priv->desc.uV_step = RT6160_VOUT_STPUV; + if (vsel_active_low) + priv->desc.vsel_reg = RT6160_REG_VSELL; + else + priv->desc.vsel_reg = RT6160_REG_VSELH; + priv->desc.vsel_mask = RT6160_VSEL_MASK; + priv->desc.n_voltages = RT6160_N_VOUTS; + priv->desc.ramp_reg = RT6160_REG_CNTL; + priv->desc.ramp_mask = RT6160_RAMPRATE_MASK; + priv->desc.ramp_delay_table = rt6160_ramp_tables; + priv->desc.n_ramp_values = ARRAY_SIZE(rt6160_ramp_tables); + priv->desc.of_map_mode = rt6160_of_map_mode; + priv->desc.ops = &rt6160_regulator_ops; + + regulator_cfg.dev = &i2c->dev; + regulator_cfg.of_node = i2c->dev.of_node; + regulator_cfg.regmap = priv->regmap; + regulator_cfg.driver_data = priv; + regulator_cfg.init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node, + &priv->desc); + + rdev = devm_regulator_register(&i2c->dev, &priv->desc, ®ulator_cfg); + if (IS_ERR(rdev)) { + dev_err(&i2c->dev, "Failed to register regulator\n"); + return PTR_ERR(rdev); + } + + return 0; +} + +static const struct of_device_id __maybe_unused rt6160_of_match_table[] = { + { .compatible = "richtek,rt6160", }, + {} +}; +MODULE_DEVICE_TABLE(of, rt6160_of_match_table); + +static struct i2c_driver rt6160_driver = { + .driver = { + .name = "rt6160", + .of_match_table = rt6160_of_match_table, + }, + .probe_new = rt6160_probe, +}; +module_i2c_driver(rt6160_driver); + +MODULE_DESCRIPTION("Richtek RT6160 voltage regulator driver"); +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/rt6245-regulator.c b/drivers/regulator/rt6245-regulator.c new file mode 100644 index 000000000000..d3299a72fd10 --- /dev/null +++ b/drivers/regulator/rt6245-regulator.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +#define RT6245_VIRT_OCLIMIT 0x00 +#define RT6245_VIRT_OTLEVEL 0x01 +#define RT6245_VIRT_PGDLYTIME 0x02 +#define RT6245_VIRT_SLEWRATE 0x03 +#define RT6245_VIRT_SWFREQ 0x04 +#define RT6245_VIRT_VOUT 0x05 + +#define RT6245_VOUT_MASK GENMASK(6, 0) +#define RT6245_SLEW_MASK GENMASK(2, 0) +#define RT6245_CHKSUM_MASK BIT(7) +#define RT6245_CODE_MASK GENMASK(6, 0) + +/* HW Enable + Soft start time */ +#define RT6245_ENTIME_IN_US 5000 + +#define RT6245_VOUT_MINUV 437500 +#define RT6245_VOUT_MAXUV 1387500 +#define RT6245_VOUT_STEPUV 12500 +#define RT6245_NUM_VOUT ((RT6245_VOUT_MAXUV - RT6245_VOUT_MINUV) / RT6245_VOUT_STEPUV + 1) + +struct rt6245_priv { + struct gpio_desc *enable_gpio; + bool enable_state; +}; + +static int rt6245_enable(struct regulator_dev *rdev) +{ + struct rt6245_priv *priv = rdev_get_drvdata(rdev); + struct regmap *regmap = rdev_get_regmap(rdev); + int ret; + + if (!priv->enable_gpio) + return 0; + + gpiod_direction_output(priv->enable_gpio, 1); + usleep_range(RT6245_ENTIME_IN_US, RT6245_ENTIME_IN_US + 1000); + + regcache_cache_only(regmap, false); + ret = regcache_sync(regmap); + if (ret) + return ret; + + priv->enable_state = true; + return 0; +} + +static int rt6245_disable(struct regulator_dev *rdev) +{ + struct rt6245_priv *priv = rdev_get_drvdata(rdev); + struct regmap *regmap = rdev_get_regmap(rdev); + + if (!priv->enable_gpio) + return -EINVAL; + + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + + gpiod_direction_output(priv->enable_gpio, 0); + + priv->enable_state = false; + return 0; +} + +static int rt6245_is_enabled(struct regulator_dev *rdev) +{ + struct rt6245_priv *priv = rdev_get_drvdata(rdev); + + return priv->enable_state ? 1 : 0; +} + +static const struct regulator_ops rt6245_regulator_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .enable = rt6245_enable, + .disable = rt6245_disable, + .is_enabled = rt6245_is_enabled, +}; + +/* ramp delay dividend is 12500 uV/uS, and divisor from 1 to 8 */ +static const unsigned int rt6245_ramp_delay_table[] = { + 12500, 6250, 4167, 3125, 2500, 2083, 1786, 1562 +}; + +static const struct regulator_desc rt6245_regulator_desc = { + .name = "rt6245-regulator", + .ops = &rt6245_regulator_ops, + .type = REGULATOR_VOLTAGE, + .min_uV = RT6245_VOUT_MINUV, + .uV_step = RT6245_VOUT_STEPUV, + .n_voltages = RT6245_NUM_VOUT, + .ramp_delay_table = rt6245_ramp_delay_table, + .n_ramp_values = ARRAY_SIZE(rt6245_ramp_delay_table), + .owner = THIS_MODULE, + .vsel_reg = RT6245_VIRT_VOUT, + .vsel_mask = RT6245_VOUT_MASK, + .ramp_reg = RT6245_VIRT_SLEWRATE, + .ramp_mask = RT6245_SLEW_MASK, +}; + +static int rt6245_init_device_properties(struct device *dev) +{ + const struct { + const char *name; + unsigned int reg; + } rt6245_props[] = { + { "richtek,oc-level-select", RT6245_VIRT_OCLIMIT }, + { "richtek,ot-level-select", RT6245_VIRT_OTLEVEL }, + { "richtek,pgdly-time-select", RT6245_VIRT_PGDLYTIME }, + { "richtek,switch-freq-select", RT6245_VIRT_SWFREQ } + }; + struct regmap *regmap = dev_get_regmap(dev, NULL); + u8 propval; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(rt6245_props); i++) { + ret = device_property_read_u8(dev, rt6245_props[i].name, &propval); + if (ret) + continue; + + ret = regmap_write(regmap, rt6245_props[i].reg, propval); + if (ret) { + dev_err(dev, "Fail to apply [%s:%d]\n", rt6245_props[i].name, propval); + return ret; + } + } + + return 0; +} + +static int rt6245_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct i2c_client *i2c = context; + const u8 func_base[] = { 0x6F, 0x73, 0x78, 0x61, 0x7C, 0 }; + unsigned int code, bit_count; + + code = func_base[reg]; + code += val; + + /* xor checksum for bit 6 to 0 */ + bit_count = hweight8(code & RT6245_CODE_MASK); + if (bit_count % 2) + code |= RT6245_CHKSUM_MASK; + else + code &= ~RT6245_CHKSUM_MASK; + + return i2c_smbus_write_byte(i2c, code); +} + +static const struct reg_default rt6245_reg_defaults[] = { + /* Default over current 14A */ + { RT6245_VIRT_OCLIMIT, 2 }, + /* Default over temperature 150'c */ + { RT6245_VIRT_OTLEVEL, 0 }, + /* Default power good delay time 10us */ + { RT6245_VIRT_PGDLYTIME, 1 }, + /* Default slewrate 12.5mV/uS */ + { RT6245_VIRT_SLEWRATE, 0 }, + /* Default switch frequency 800KHz */ + { RT6245_VIRT_SWFREQ, 1 }, + /* Default voltage 750mV */ + { RT6245_VIRT_VOUT, 0x19 } +}; + +static const struct regmap_config rt6245_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RT6245_VIRT_VOUT, + .cache_type = REGCACHE_FLAT, + .reg_defaults = rt6245_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt6245_reg_defaults), + .reg_write = rt6245_reg_write, +}; + +static int rt6245_probe(struct i2c_client *i2c) +{ + struct rt6245_priv *priv; + struct regmap *regmap; + struct regulator_config regulator_cfg = {}; + struct regulator_dev *rdev; + int ret; + + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->enable_state = true; + + priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(priv->enable_gpio)) { + dev_err(&i2c->dev, "Failed to get 'enable' gpio\n"); + return PTR_ERR(priv->enable_gpio); + } + + usleep_range(RT6245_ENTIME_IN_US, RT6245_ENTIME_IN_US + 1000); + + regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt6245_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&i2c->dev, "Failed to initialize the regmap\n"); + return PTR_ERR(regmap); + } + + ret = rt6245_init_device_properties(&i2c->dev); + if (ret) { + dev_err(&i2c->dev, "Failed to initialize device properties\n"); + return ret; + } + + regulator_cfg.dev = &i2c->dev; + regulator_cfg.of_node = i2c->dev.of_node; + regulator_cfg.regmap = regmap; + regulator_cfg.driver_data = priv; + regulator_cfg.init_data = of_get_regulator_init_data(&i2c->dev, i2c->dev.of_node, + &rt6245_regulator_desc); + rdev = devm_regulator_register(&i2c->dev, &rt6245_regulator_desc, ®ulator_cfg); + if (IS_ERR(rdev)) { + dev_err(&i2c->dev, "Failed to register regulator\n"); + return PTR_ERR(rdev); + } + + return 0; +} + +static const struct of_device_id __maybe_unused rt6245_of_match_table[] = { + { .compatible = "richtek,rt6245", }, + {} +}; +MODULE_DEVICE_TABLE(of, rt6245_of_match_table); + +static struct i2c_driver rt6245_driver = { + .driver = { + .name = "rt6245", + .of_match_table = rt6245_of_match_table, + }, + .probe_new = rt6245_probe, +}; +module_i2c_driver(rt6245_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Richtek RT6245 Regulator Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c index cf10fdb72e32..2d7597c76e4a 100644 --- a/drivers/regulator/stpmic1_regulator.c +++ b/drivers/regulator/stpmic1_regulator.c @@ -32,7 +32,8 @@ struct stpmic1_regulator_cfg { 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_set_icc(struct regulator_dev *rdev, int lim, int severity, + bool enable); static unsigned int stpmic1_map_mode(unsigned int mode); enum { @@ -491,11 +492,26 @@ static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode) STPMIC1_BUCK_MODE_LP, value); } -static int stpmic1_set_icc(struct regulator_dev *rdev) +static int stpmic1_set_icc(struct regulator_dev *rdev, int lim, int severity, + bool enable) { struct stpmic1_regulator_cfg *cfg = rdev_get_drvdata(rdev); struct regmap *regmap = rdev_get_regmap(rdev); + /* + * The code seems like one bit in a register controls whether OCP is + * enabled. So we might be able to turn it off here is if that + * was requested. I won't support this because I don't have the HW. + * Feel free to try and implement if you have the HW and need kernel + * to disable this. + * + * Also, I don't know if limit can be configured or if we support + * error/warning instead of protect. So I just keep existing logic + * and assume no. + */ + if (lim || severity != REGULATOR_SEVERITY_PROT || !enable) + return -EINVAL; + /* enable switch off in case of over current */ return regmap_update_bits(regmap, cfg->icc_reg, cfg->icc_mask, cfg->icc_mask); diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c new file mode 100644 index 000000000000..e021ae08cbaa --- /dev/null +++ b/drivers/regulator/sy7636a-regulator.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Functions to access SY3686A power management chip voltages +// +// Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/ +// +// Authors: Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com> +// Alistair Francis <alistair@alistair23.me> + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/gpio/consumer.h> +#include <linux/mfd/sy7636a.h> + +#define SY7636A_POLL_ENABLED_TIME 500 + +static int sy7636a_get_vcom_voltage_op(struct regulator_dev *rdev) +{ + int ret; + unsigned int val, val_h; + + ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_L, &val); + if (ret) + return ret; + + ret = regmap_read(rdev->regmap, SY7636A_REG_VCOM_ADJUST_CTRL_H, &val_h); + if (ret) + return ret; + + val |= (val_h << VCOM_ADJUST_CTRL_SHIFT); + + return (val & VCOM_ADJUST_CTRL_MASK) * VCOM_ADJUST_CTRL_SCAL; +} + +static int sy7636a_get_status(struct regulator_dev *rdev) +{ + struct sy7636a *sy7636a = rdev_get_drvdata(rdev); + int ret = 0; + + ret = gpiod_get_value_cansleep(sy7636a->pgood_gpio); + if (ret < 0) + dev_err(&rdev->dev, "Failed to read pgood gpio: %d\n", ret); + + return ret; +} + +static const struct regulator_ops sy7636a_vcom_volt_ops = { + .get_voltage = sy7636a_get_vcom_voltage_op, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = sy7636a_get_status, +}; + +static const struct regulator_desc desc = { + .name = "vcom", + .id = 0, + .ops = &sy7636a_vcom_volt_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = SY7636A_REG_OPERATION_MODE_CRL, + .enable_mask = SY7636A_OPERATION_MODE_CRL_ONOFF, + .poll_enabled_time = SY7636A_POLL_ENABLED_TIME, + .regulators_node = of_match_ptr("regulators"), + .of_match = of_match_ptr("vcom"), +}; + +static int sy7636a_regulator_probe(struct platform_device *pdev) +{ + struct sy7636a *sy7636a = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct gpio_desc *gdp; + int ret; + + if (!sy7636a) + return -EPROBE_DEFER; + + platform_set_drvdata(pdev, sy7636a); + + gdp = devm_gpiod_get(sy7636a->dev, "epd-pwr-good", GPIOD_IN); + if (IS_ERR(gdp)) { + dev_err(sy7636a->dev, "Power good GPIO fault %ld\n", PTR_ERR(gdp)); + return PTR_ERR(gdp); + } + + sy7636a->pgood_gpio = gdp; + + ret = regmap_write(sy7636a->regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0); + if (ret) { + dev_err(sy7636a->dev, "Failed to initialize regulator: %d\n", ret); + return ret; + } + + config.dev = &pdev->dev; + config.dev->of_node = sy7636a->dev->of_node; + config.driver_data = sy7636a; + config.regmap = sy7636a->regmap; + + rdev = devm_regulator_register(&pdev->dev, &desc, &config); + if (IS_ERR(rdev)) { + dev_err(sy7636a->dev, "Failed to register %s regulator\n", + pdev->name); + return PTR_ERR(rdev); + } + + return 0; +} + +static const struct platform_device_id sy7636a_regulator_id_table[] = { + { "sy7636a-regulator", }, + { } +}; +MODULE_DEVICE_TABLE(platform, sy7636a_regulator_id_table); + +static struct platform_driver sy7636a_regulator_driver = { + .driver = { + .name = "sy7636a-regulator", + }, + .probe = sy7636a_regulator_probe, + .id_table = sy7636a_regulator_id_table, +}; +module_platform_driver(sy7636a_regulator_driver); + +MODULE_AUTHOR("Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>"); +MODULE_DESCRIPTION("SY7636A voltage regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c index 2e02e26b516c..e75b0973e325 100644 --- a/drivers/regulator/uniphier-regulator.c +++ b/drivers/regulator/uniphier-regulator.c @@ -201,6 +201,7 @@ static const struct of_device_id uniphier_regulator_match[] = { }, { /* Sentinel */ }, }; +MODULE_DEVICE_TABLE(of, uniphier_regulator_match); static struct platform_driver uniphier_regulator_driver = { .probe = uniphier_regulator_probe, diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index 8e3b5a67cfd8..8ca28664776e 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -29,15 +29,15 @@ struct userspace_consumer_data { struct regulator_bulk_data *supplies; }; -static ssize_t reg_show_name(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct userspace_consumer_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static ssize_t reg_show_state(struct device *dev, +static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct userspace_consumer_data *data = dev_get_drvdata(dev); @@ -48,8 +48,8 @@ static ssize_t reg_show_state(struct device *dev, return sprintf(buf, "disabled\n"); } -static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t state_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct userspace_consumer_data *data = dev_get_drvdata(dev); bool enabled; @@ -87,8 +87,8 @@ static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(name, 0444, reg_show_name, NULL); -static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state); +static DEVICE_ATTR_RO(name); +static DEVICE_ATTR_RW(state); static struct attribute *attributes[] = { &dev_attr_name.attr, diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 6655035e5164..80dc479a6ff0 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -75,7 +75,7 @@ static int __mtk_rtc_read_time(struct mt6397_rtc *rtc, tm->tm_min = data[RTC_OFFSET_MIN]; tm->tm_hour = data[RTC_OFFSET_HOUR]; tm->tm_mday = data[RTC_OFFSET_DOM]; - tm->tm_mon = data[RTC_OFFSET_MTH]; + tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK; tm->tm_year = data[RTC_OFFSET_YEAR]; ret = regmap_read(rtc->regmap, rtc->addr_base + RTC_TC_SEC, sec); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index d20b25f40d19..10a2d8e1cacf 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -36,10 +36,8 @@ static LIST_HEAD(thermal_governor_list); static DEFINE_MUTEX(thermal_list_lock); static DEFINE_MUTEX(thermal_governor_lock); -static DEFINE_MUTEX(poweroff_lock); static atomic_t in_suspend; -static bool power_off_triggered; static struct thermal_governor *def_governor; @@ -327,70 +325,18 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip) def_governor->throttle(tz, trip); } -/** - * thermal_emergency_poweroff_func - emergency poweroff work after a known delay - * @work: work_struct associated with the emergency poweroff function - * - * This function is called in very critical situations to force - * a kernel poweroff after a configurable timeout value. - */ -static void thermal_emergency_poweroff_func(struct work_struct *work) -{ - /* - * We have reached here after the emergency thermal shutdown - * Waiting period has expired. This means orderly_poweroff has - * not been able to shut off the system for some reason. - * Try to shut down the system immediately using kernel_power_off - * if populated - */ - WARN(1, "Attempting kernel_power_off: Temperature too high\n"); - kernel_power_off(); - - /* - * Worst of the worst case trigger emergency restart - */ - WARN(1, "Attempting emergency_restart: Temperature too high\n"); - emergency_restart(); -} - -static DECLARE_DELAYED_WORK(thermal_emergency_poweroff_work, - thermal_emergency_poweroff_func); - -/** - * thermal_emergency_poweroff - Trigger an emergency system poweroff - * - * This may be called from any critical situation to trigger a system shutdown - * after a known period of time. By default this is not scheduled. - */ -static void thermal_emergency_poweroff(void) +void thermal_zone_device_critical(struct thermal_zone_device *tz) { - int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS; /* * poweroff_delay_ms must be a carefully profiled positive value. - * Its a must for thermal_emergency_poweroff_work to be scheduled + * Its a must for forced_emergency_poweroff_work to be scheduled. */ - if (poweroff_delay_ms <= 0) - return; - schedule_delayed_work(&thermal_emergency_poweroff_work, - msecs_to_jiffies(poweroff_delay_ms)); -} + int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS; -void thermal_zone_device_critical(struct thermal_zone_device *tz) -{ dev_emerg(&tz->device, "%s: critical temperature reached, " "shutting down\n", tz->type); - mutex_lock(&poweroff_lock); - if (!power_off_triggered) { - /* - * Queue a backup emergency shutdown in the event of - * orderly_poweroff failure - */ - thermal_emergency_poweroff(); - orderly_poweroff(true); - power_off_triggered = true; - } - mutex_unlock(&poweroff_lock); + hw_protection_shutdown("Temperature too high", poweroff_delay_ms); } EXPORT_SYMBOL(thermal_zone_device_critical); @@ -1538,7 +1484,6 @@ error: ida_destroy(&thermal_cdev_ida); mutex_destroy(&thermal_list_lock); mutex_destroy(&thermal_governor_lock); - mutex_destroy(&poweroff_lock); return result; } postcore_initcall(thermal_init); |