summaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig14
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/ad5398.c30
-rw-r--r--drivers/regulator/axp20x-regulator.c14
-rw-r--r--drivers/regulator/cros-ec-regulator.c4
-rw-r--r--drivers/regulator/devres.c22
-rw-r--r--drivers/regulator/of_regulator.c21
-rw-r--r--drivers/regulator/pca9450-regulator.c91
-rw-r--r--drivers/regulator/pcf50633-regulator.c124
-rw-r--r--drivers/regulator/pf9453-regulator.c879
-rw-r--r--drivers/regulator/rtq6752-regulator.c2
11 files changed, 1030 insertions, 173 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 39297f7d8177..807d07067951 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -981,6 +981,13 @@ config REGULATOR_PCA9450
Say y here to support the NXP PCA9450A/PCA9450B/PCA9450C PMIC
regulator driver.
+config REGULATOR_PF9453
+ tristate "NXP PF9453 regulator driver"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support the NXP PF9453 PMIC regulator driver.
+
config REGULATOR_PCAP
tristate "Motorola PCAP2 regulator driver"
depends on EZX_PCAP
@@ -988,13 +995,6 @@ config REGULATOR_PCAP
This driver provides support for the voltage regulators of the
PCAP2 PMIC.
-config REGULATOR_PCF50633
- tristate "NXP PCF50633 regulator driver"
- depends on MFD_PCF50633
- help
- Say Y here to support the voltage regulators and converters
- on PCF50633
-
config REGULATOR_PF8X00
tristate "NXP PF8100/PF8121A/PF8200 regulator driver"
depends on I2C && OF
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 3d5a803dce8a..524e026c0273 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -123,6 +123,7 @@ obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o
+obj-$(CONFIG_REGULATOR_PF9453) += pf9453-regulator.o
obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
@@ -132,7 +133,6 @@ obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
-obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RAA215300) += raa215300.o
obj-$(CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY) += rpi-panel-attiny-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index 40f7dba42b5a..eb2a666a45cb 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -14,8 +14,9 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
-#define AD5398_CURRENT_EN_MASK 0x8000
+#define AD5398_SW_POWER_DOWN BIT(15)
struct ad5398_chip_info {
struct i2c_client *client;
@@ -113,7 +114,7 @@ static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int
/* prepare register data */
selector = (selector << chip->current_offset) & chip->current_mask;
- data = (unsigned short)selector | (data & AD5398_CURRENT_EN_MASK);
+ data = (unsigned short)selector | (data & AD5398_SW_POWER_DOWN);
/* write the new current value back as well as enable bit */
ret = ad5398_write_reg(client, data);
@@ -132,10 +133,10 @@ static int ad5398_is_enabled(struct regulator_dev *rdev)
if (ret < 0)
return ret;
- if (data & AD5398_CURRENT_EN_MASK)
- return 1;
- else
+ if (data & AD5398_SW_POWER_DOWN)
return 0;
+ else
+ return 1;
}
static int ad5398_enable(struct regulator_dev *rdev)
@@ -149,10 +150,10 @@ static int ad5398_enable(struct regulator_dev *rdev)
if (ret < 0)
return ret;
- if (data & AD5398_CURRENT_EN_MASK)
+ if (!(data & AD5398_SW_POWER_DOWN))
return 0;
- data |= AD5398_CURRENT_EN_MASK;
+ data &= ~AD5398_SW_POWER_DOWN;
ret = ad5398_write_reg(client, data);
@@ -170,10 +171,10 @@ static int ad5398_disable(struct regulator_dev *rdev)
if (ret < 0)
return ret;
- if (!(data & AD5398_CURRENT_EN_MASK))
+ if (data & AD5398_SW_POWER_DOWN)
return 0;
- data &= ~AD5398_CURRENT_EN_MASK;
+ data |= AD5398_SW_POWER_DOWN;
ret = ad5398_write_reg(client, data);
@@ -221,15 +222,20 @@ static int ad5398_probe(struct i2c_client *client)
const struct ad5398_current_data_format *df =
(struct ad5398_current_data_format *)id->driver_data;
- if (!init_data)
- return -EINVAL;
-
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
config.dev = &client->dev;
+ if (client->dev.of_node)
+ init_data = of_get_regulator_init_data(&client->dev,
+ client->dev.of_node,
+ &ad5398_reg);
+ if (!init_data)
+ return -EINVAL;
+
config.init_data = init_data;
+ config.of_node = client->dev.of_node;
config.driver_data = chip;
chip->client = client;
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index dca99cfb7cbb..da891415efc0 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -371,8 +371,8 @@
.ops = &axp20x_ops, \
}
-#define AXP_DESC_DELAY(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
- _vmask, _ereg, _emask, _ramp_delay) \
+#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask) \
[_family##_##_id] = { \
.name = (_match), \
.supply_name = (_supply), \
@@ -388,15 +388,9 @@
.vsel_mask = (_vmask), \
.enable_reg = (_ereg), \
.enable_mask = (_emask), \
- .ramp_delay = (_ramp_delay), \
.ops = &axp20x_ops, \
}
-#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
- _vmask, _ereg, _emask) \
- AXP_DESC_DELAY(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
- _vmask, _ereg, _emask, 0)
-
#define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \
[_family##_##_id] = { \
.name = (_match), \
@@ -805,9 +799,9 @@ static const struct regulator_desc axp717_regulators[] = {
axp717_dcdc3_ranges, AXP717_DCDC3_NUM_VOLTAGES,
AXP717_DCDC3_CONTROL, AXP717_DCDC_V_OUT_MASK,
AXP717_DCDC_OUTPUT_CONTROL, BIT(2), 640),
- AXP_DESC_DELAY(AXP717, DCDC4, "dcdc4", "vin4", 1000, 3700, 100,
+ AXP_DESC(AXP717, DCDC4, "dcdc4", "vin4", 1000, 3700, 100,
AXP717_DCDC4_CONTROL, AXP717_DCDC_V_OUT_MASK,
- AXP717_DCDC_OUTPUT_CONTROL, BIT(3), 6400),
+ AXP717_DCDC_OUTPUT_CONTROL, BIT(3)),
AXP_DESC(AXP717, ALDO1, "aldo1", "aldoin", 500, 3500, 100,
AXP717_ALDO1_CONTROL, AXP717_LDO_V_OUT_MASK,
AXP717_LDO0_OUTPUT_CONTROL, BIT(0)),
diff --git a/drivers/regulator/cros-ec-regulator.c b/drivers/regulator/cros-ec-regulator.c
index fb9643ed7a49..fb0767b33a36 100644
--- a/drivers/regulator/cros-ec-regulator.c
+++ b/drivers/regulator/cros-ec-regulator.c
@@ -138,8 +138,8 @@ static int cros_ec_regulator_init_info(struct device *dev,
data->num_voltages =
min_t(u16, ARRAY_SIZE(resp.voltages_mv), resp.num_voltages);
data->voltages_mV =
- devm_kmemdup(dev, resp.voltages_mv,
- sizeof(u16) * data->num_voltages, GFP_KERNEL);
+ devm_kmemdup_array(dev, resp.voltages_mv, data->num_voltages,
+ sizeof(resp.voltages_mv[0]), GFP_KERNEL);
if (!data->voltages_mV)
return -ENOMEM;
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index 36164aec30e8..2cf03042fddf 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -332,9 +332,8 @@ int devm_regulator_bulk_get_const(struct device *dev, int num_consumers,
const struct regulator_bulk_data *in_consumers,
struct regulator_bulk_data **out_consumers)
{
- *out_consumers = devm_kmemdup(dev, in_consumers,
- num_consumers * sizeof(*in_consumers),
- GFP_KERNEL);
+ *out_consumers = devm_kmemdup_array(dev, in_consumers, num_consumers,
+ sizeof(*in_consumers), GFP_KERNEL);
if (*out_consumers == NULL)
return -ENOMEM;
@@ -772,6 +771,23 @@ static struct regulator *_devm_of_regulator_get(struct device *dev, struct devic
}
/**
+ * devm_of_regulator_get - Resource managed of_regulator_get()
+ * @dev: device used for dev_printk() messages and resource lifetime management
+ * @node: device node for regulator "consumer"
+ * @id: supply name or regulator ID.
+ *
+ * Managed of_regulator_get(). Regulators returned from this
+ * function are automatically regulator_put() on driver detach. See
+ * of_regulator_get() for more information.
+ */
+struct regulator *devm_of_regulator_get(struct device *dev, struct device_node *node,
+ const char *id)
+{
+ return _devm_of_regulator_get(dev, node, id, NORMAL_GET);
+}
+EXPORT_SYMBOL_GPL(devm_of_regulator_get);
+
+/**
* devm_of_regulator_get_optional - Resource managed of_regulator_get_optional()
* @dev: device used for dev_printk() messages and resource lifetime management
* @node: device node for regulator "consumer"
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 011088c57891..32e88cada47a 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -698,6 +698,27 @@ struct regulator *_of_regulator_get(struct device *dev, struct device_node *node
}
/**
+ * of_regulator_get - get regulator via device tree lookup
+ * @dev: device used for dev_printk() messages
+ * @node: device node for regulator "consumer"
+ * @id: Supply name
+ *
+ * Return: pointer to struct regulator corresponding to the regulator producer,
+ * or PTR_ERR() encoded error number.
+ *
+ * This is intended for use by consumers that want to get a regulator
+ * supply directly from a device node. This will _not_ consider supply
+ * aliases. See regulator_dev_lookup().
+ */
+struct regulator *of_regulator_get(struct device *dev,
+ struct device_node *node,
+ const char *id)
+{
+ return _of_regulator_get(dev, node, id, NORMAL_GET);
+}
+EXPORT_SYMBOL_GPL(of_regulator_get);
+
+/**
* of_regulator_get_optional - get optional regulator via device tree lookup
* @dev: device used for dev_printk() messages
* @node: device node for regulator "consumer"
diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c
index faa6b79c27d7..a56f3ab754fa 100644
--- a/drivers/regulator/pca9450-regulator.c
+++ b/drivers/regulator/pca9450-regulator.c
@@ -36,6 +36,7 @@ struct pca9450 {
enum pca9450_chip_type type;
unsigned int rcnt;
int irq;
+ bool sd_vsel_fixed_low;
};
static const struct regmap_range pca9450_status_range = {
@@ -98,6 +99,61 @@ static const struct regulator_ops pca9450_ldo_regulator_ops = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
+static unsigned int pca9450_ldo5_get_reg_voltage_sel(struct regulator_dev *rdev)
+{
+ struct pca9450 *pca9450 = rdev_get_drvdata(rdev);
+
+ if (pca9450->sd_vsel_fixed_low)
+ return PCA9450_REG_LDO5CTRL_L;
+
+ if (pca9450->sd_vsel_gpio && !gpiod_get_value(pca9450->sd_vsel_gpio))
+ return PCA9450_REG_LDO5CTRL_L;
+
+ return rdev->desc->vsel_reg;
+}
+
+static int pca9450_ldo5_get_voltage_sel_regmap(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(rdev->regmap, pca9450_ldo5_get_reg_voltage_sel(rdev), &val);
+ if (ret != 0)
+ return ret;
+
+ val &= rdev->desc->vsel_mask;
+ val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+ return val;
+}
+
+static int pca9450_ldo5_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned int sel)
+{
+ int ret;
+
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+
+ ret = regmap_update_bits(rdev->regmap, pca9450_ldo5_get_reg_voltage_sel(rdev),
+ rdev->desc->vsel_mask, sel);
+ if (ret)
+ return ret;
+
+ if (rdev->desc->apply_bit)
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+ rdev->desc->apply_bit,
+ rdev->desc->apply_bit);
+ return ret;
+}
+
+static const struct regulator_ops pca9450_ldo5_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = pca9450_ldo5_set_voltage_sel_regmap,
+ .get_voltage_sel = pca9450_ldo5_get_voltage_sel_regmap,
+};
+
/*
* BUCK1/2/3
* 0.60 to 2.1875V (12.5mV step)
@@ -453,14 +509,14 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.of_match = of_match_ptr("LDO5"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO5,
- .ops = &pca9450_ldo_regulator_ops,
+ .ops = &pca9450_ldo5_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
.linear_ranges = pca9450_ldo5_volts,
.n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
.vsel_reg = PCA9450_REG_LDO5CTRL_H,
.vsel_mask = LDO5HOUT_MASK,
- .enable_reg = PCA9450_REG_LDO5CTRL_H,
+ .enable_reg = PCA9450_REG_LDO5CTRL_L,
.enable_mask = LDO5H_EN_MASK,
.owner = THIS_MODULE,
},
@@ -667,14 +723,14 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.of_match = of_match_ptr("LDO5"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO5,
- .ops = &pca9450_ldo_regulator_ops,
+ .ops = &pca9450_ldo5_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
.linear_ranges = pca9450_ldo5_volts,
.n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
.vsel_reg = PCA9450_REG_LDO5CTRL_H,
.vsel_mask = LDO5HOUT_MASK,
- .enable_reg = PCA9450_REG_LDO5CTRL_H,
+ .enable_reg = PCA9450_REG_LDO5CTRL_L,
.enable_mask = LDO5H_EN_MASK,
.owner = THIS_MODULE,
},
@@ -857,14 +913,14 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
.of_match = of_match_ptr("LDO5"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO5,
- .ops = &pca9450_ldo_regulator_ops,
+ .ops = &pca9450_ldo5_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = PCA9450_LDO5_VOLTAGE_NUM,
.linear_ranges = pca9450_ldo5_volts,
.n_linear_ranges = ARRAY_SIZE(pca9450_ldo5_volts),
.vsel_reg = PCA9450_REG_LDO5CTRL_H,
.vsel_mask = LDO5HOUT_MASK,
- .enable_reg = PCA9450_REG_LDO5CTRL_H,
+ .enable_reg = PCA9450_REG_LDO5CTRL_L,
.enable_mask = LDO5H_EN_MASK,
.owner = THIS_MODULE,
},
@@ -915,6 +971,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
of_device_get_match_data(&i2c->dev);
const struct pca9450_regulator_desc *regulator_desc;
struct regulator_config config = { };
+ struct regulator_dev *ldo5;
struct pca9450 *pca9450;
unsigned int device_id, i;
unsigned int reset_ctrl;
@@ -980,11 +1037,15 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
config.regmap = pca9450->regmap;
config.dev = pca9450->dev;
+ config.driver_data = pca9450;
rdev = devm_regulator_register(pca9450->dev, desc, &config);
if (IS_ERR(rdev))
return dev_err_probe(pca9450->dev, PTR_ERR(rdev),
"Failed to register regulator(%s)\n", desc->name);
+
+ if (!strcmp(desc->name, "ldo5"))
+ ldo5 = rdev;
}
if (pca9450->irq) {
@@ -1032,15 +1093,19 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
}
/*
- * The driver uses the LDO5CTRL_H register to control the LDO5 regulator.
- * This is only valid if the SD_VSEL input of the PMIC is high. Let's
- * check if the pin is available as GPIO and set it to high.
+ * For LDO5 we need to be able to check the status of the SD_VSEL input in
+ * order to know which control register is used. Most boards connect SD_VSEL
+ * to the VSELECT signal, so we can use the GPIO that is internally routed
+ * to this signal (if SION bit is set in IOMUX).
*/
- pca9450->sd_vsel_gpio = gpiod_get_optional(pca9450->dev, "sd-vsel", GPIOD_OUT_HIGH);
+ pca9450->sd_vsel_gpio = gpiod_get_optional(&ldo5->dev, "sd-vsel", GPIOD_IN);
+ if (IS_ERR(pca9450->sd_vsel_gpio)) {
+ dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n");
+ return ret;
+ }
- if (IS_ERR(pca9450->sd_vsel_gpio))
- return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->sd_vsel_gpio),
- "Failed to get SD_VSEL GPIO\n");
+ pca9450->sd_vsel_fixed_low =
+ of_property_read_bool(ldo5->dev.of_node, "nxp,sd-vsel-fixed-low");
dev_info(&i2c->dev, "%s probed.\n",
type == PCA9450_TYPE_PCA9450A ? "pca9450a" :
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
deleted file mode 100644
index 9f08a62c800e..000000000000
--- a/drivers/regulator/pcf50633-regulator.c
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* NXP PCF50633 PMIC Driver
- *
- * (C) 2006-2008 by Openmoko, Inc.
- * Author: Balaji Rao <balajirrao@openmoko.org>
- * All rights reserved.
- *
- * Broken down from monstrous PCF50633 driver mainly by
- * Harald Welte and Andy Green and Werner Almesberger
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-
-#include <linux/mfd/pcf50633/core.h>
-#include <linux/mfd/pcf50633/pmic.h>
-
-#define PCF50633_REGULATOR(_name, _id, _min_uV, _uV_step, _min_sel, _n) \
- { \
- .name = _name, \
- .id = PCF50633_REGULATOR_##_id, \
- .ops = &pcf50633_regulator_ops, \
- .n_voltages = _n, \
- .min_uV = _min_uV, \
- .uV_step = _uV_step, \
- .linear_min_sel = _min_sel, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
- .vsel_reg = PCF50633_REG_##_id##OUT, \
- .vsel_mask = 0xff, \
- .enable_reg = PCF50633_REG_##_id##OUT + 1, \
- .enable_mask = PCF50633_REGULATOR_ON, \
- }
-
-static const struct regulator_ops pcf50633_regulator_ops = {
- .set_voltage_sel = regulator_set_voltage_sel_regmap,
- .get_voltage_sel = regulator_get_voltage_sel_regmap,
- .list_voltage = regulator_list_voltage_linear,
- .map_voltage = regulator_map_voltage_linear,
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
-};
-
-static const struct regulator_desc regulators[] = {
- [PCF50633_REGULATOR_AUTO] =
- PCF50633_REGULATOR("auto", AUTO, 1800000, 25000, 0x2f, 128),
- [PCF50633_REGULATOR_DOWN1] =
- PCF50633_REGULATOR("down1", DOWN1, 625000, 25000, 0, 96),
- [PCF50633_REGULATOR_DOWN2] =
- PCF50633_REGULATOR("down2", DOWN2, 625000, 25000, 0, 96),
- [PCF50633_REGULATOR_LDO1] =
- PCF50633_REGULATOR("ldo1", LDO1, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO2] =
- PCF50633_REGULATOR("ldo2", LDO2, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO3] =
- PCF50633_REGULATOR("ldo3", LDO3, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO4] =
- PCF50633_REGULATOR("ldo4", LDO4, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO5] =
- PCF50633_REGULATOR("ldo5", LDO5, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_LDO6] =
- PCF50633_REGULATOR("ldo6", LDO6, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_HCLDO] =
- PCF50633_REGULATOR("hcldo", HCLDO, 900000, 100000, 0, 28),
- [PCF50633_REGULATOR_MEMLDO] =
- PCF50633_REGULATOR("memldo", MEMLDO, 900000, 100000, 0, 28),
-};
-
-static int pcf50633_regulator_probe(struct platform_device *pdev)
-{
- struct regulator_dev *rdev;
- struct pcf50633 *pcf;
- struct regulator_config config = { };
-
- /* Already set by core driver */
- pcf = dev_to_pcf50633(pdev->dev.parent);
-
- config.dev = &pdev->dev;
- config.init_data = dev_get_platdata(&pdev->dev);
- config.driver_data = pcf;
- config.regmap = pcf->regmap;
-
- rdev = devm_regulator_register(&pdev->dev, &regulators[pdev->id],
- &config);
- if (IS_ERR(rdev))
- return PTR_ERR(rdev);
-
- platform_set_drvdata(pdev, rdev);
-
- if (pcf->pdata->regulator_registered)
- pcf->pdata->regulator_registered(pcf, pdev->id);
-
- return 0;
-}
-
-static struct platform_driver pcf50633_regulator_driver = {
- .driver = {
- .name = "pcf50633-regulator",
- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
- },
- .probe = pcf50633_regulator_probe,
-};
-
-static int __init pcf50633_regulator_init(void)
-{
- return platform_driver_register(&pcf50633_regulator_driver);
-}
-subsys_initcall(pcf50633_regulator_init);
-
-static void __exit pcf50633_regulator_exit(void)
-{
- platform_driver_unregister(&pcf50633_regulator_driver);
-}
-module_exit(pcf50633_regulator_exit);
-
-MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
-MODULE_DESCRIPTION("PCF50633 regulator driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pcf50633-regulator");
diff --git a/drivers/regulator/pf9453-regulator.c b/drivers/regulator/pf9453-regulator.c
new file mode 100644
index 000000000000..ed6bf0f6c4fe
--- /dev/null
+++ b/drivers/regulator/pf9453-regulator.c
@@ -0,0 +1,879 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2024 NXP.
+ * NXP PF9453 pmic driver
+ */
+
+#include <linux/bits.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.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>
+
+struct pf9453_dvs_config {
+ unsigned int run_reg; /* dvs0 */
+ unsigned int run_mask;
+ unsigned int standby_reg; /* dvs1 */
+ unsigned int standby_mask;
+};
+
+struct pf9453_regulator_desc {
+ struct regulator_desc desc;
+ const struct pf9453_dvs_config dvs;
+};
+
+struct pf9453 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct gpio_desc *sd_vsel_gpio;
+ int irq;
+};
+
+enum {
+ PF9453_BUCK1 = 0,
+ PF9453_BUCK2,
+ PF9453_BUCK3,
+ PF9453_BUCK4,
+ PF9453_LDO1,
+ PF9453_LDO2,
+ PF9453_LDOSNVS,
+ PF9453_REGULATOR_CNT
+};
+
+enum {
+ PF9453_DVS_LEVEL_RUN = 0,
+ PF9453_DVS_LEVEL_STANDBY,
+ PF9453_DVS_LEVEL_DPSTANDBY,
+ PF9453_DVS_LEVEL_MAX
+};
+
+#define PF9453_BUCK1_VOLTAGE_NUM 0x80
+#define PF9453_BUCK2_VOLTAGE_NUM 0x80
+#define PF9453_BUCK3_VOLTAGE_NUM 0x80
+#define PF9453_BUCK4_VOLTAGE_NUM 0x80
+
+#define PF9453_LDO1_VOLTAGE_NUM 0x65
+#define PF9453_LDO2_VOLTAGE_NUM 0x3b
+#define PF9453_LDOSNVS_VOLTAGE_NUM 0x59
+
+enum {
+ PF9453_REG_DEV_ID = 0x00,
+ PF9453_REG_OTP_VER = 0x01,
+ PF9453_REG_INT1 = 0x02,
+ PF9453_REG_INT1_MASK = 0x03,
+ PF9453_REG_INT1_STATUS = 0x04,
+ PF9453_REG_VRFLT1_INT = 0x05,
+ PF9453_REG_VRFLT1_MASK = 0x06,
+ PF9453_REG_PWRON_STAT = 0x07,
+ PF9453_REG_RESET_CTRL = 0x08,
+ PF9453_REG_SW_RST = 0x09,
+ PF9453_REG_PWR_CTRL = 0x0a,
+ PF9453_REG_CONFIG1 = 0x0b,
+ PF9453_REG_CONFIG2 = 0x0c,
+ PF9453_REG_32K_CONFIG = 0x0d,
+ PF9453_REG_BUCK1CTRL = 0x10,
+ PF9453_REG_BUCK1OUT = 0x11,
+ PF9453_REG_BUCK2CTRL = 0x14,
+ PF9453_REG_BUCK2OUT = 0x15,
+ PF9453_REG_BUCK2OUT_STBY = 0x1d,
+ PF9453_REG_BUCK2OUT_MAX_LIMIT = 0x1f,
+ PF9453_REG_BUCK2OUT_MIN_LIMIT = 0x20,
+ PF9453_REG_BUCK3CTRL = 0x21,
+ PF9453_REG_BUCK3OUT = 0x22,
+ PF9453_REG_BUCK4CTRL = 0x2e,
+ PF9453_REG_BUCK4OUT = 0x2f,
+ PF9453_REG_LDO1OUT_L = 0x36,
+ PF9453_REG_LDO1CFG = 0x37,
+ PF9453_REG_LDO1OUT_H = 0x38,
+ PF9453_REG_LDOSNVS_CFG1 = 0x39,
+ PF9453_REG_LDOSNVS_CFG2 = 0x3a,
+ PF9453_REG_LDO2CFG = 0x3b,
+ PF9453_REG_LDO2OUT = 0x3c,
+ PF9453_REG_BUCK_POK = 0x3d,
+ PF9453_REG_LSW_CTRL1 = 0x40,
+ PF9453_REG_LSW_CTRL2 = 0x41,
+ PF9453_REG_LOCK = 0x4e,
+ PF9453_MAX_REG
+};
+
+#define PF9453_UNLOCK_KEY 0x5c
+#define PF9453_LOCK_KEY 0x0
+
+/* PF9453 BUCK ENMODE bits */
+#define BUCK_ENMODE_OFF 0x00
+#define BUCK_ENMODE_ONREQ 0x01
+#define BUCK_ENMODE_ONREQ_STBY 0x02
+#define BUCK_ENMODE_ONREQ_STBY_DPSTBY 0x03
+
+/* PF9453 BUCK ENMODE bits */
+#define LDO_ENMODE_OFF 0x00
+#define LDO_ENMODE_ONREQ 0x01
+#define LDO_ENMODE_ONREQ_STBY 0x02
+#define LDO_ENMODE_ONREQ_STBY_DPSTBY 0x03
+
+/* PF9453_REG_BUCK1_CTRL bits */
+#define BUCK1_LPMODE 0x30
+#define BUCK1_AD 0x08
+#define BUCK1_FPWM 0x04
+#define BUCK1_ENMODE_MASK GENMASK(1, 0)
+
+/* PF9453_REG_BUCK2_CTRL bits */
+#define BUCK2_RAMP_MASK GENMASK(7, 6)
+#define BUCK2_RAMP_25MV 0x0
+#define BUCK2_RAMP_12P5MV 0x1
+#define BUCK2_RAMP_6P25MV 0x2
+#define BUCK2_RAMP_3P125MV 0x3
+#define BUCK2_LPMODE 0x30
+#define BUCK2_AD 0x08
+#define BUCK2_FPWM 0x04
+#define BUCK2_ENMODE_MASK GENMASK(1, 0)
+
+/* PF9453_REG_BUCK3_CTRL bits */
+#define BUCK3_LPMODE 0x30
+#define BUCK3_AD 0x08
+#define BUCK3_FPWM 0x04
+#define BUCK3_ENMODE_MASK GENMASK(1, 0)
+
+/* PF9453_REG_BUCK4_CTRL bits */
+#define BUCK4_LPMODE 0x30
+#define BUCK4_AD 0x08
+#define BUCK4_FPWM 0x04
+#define BUCK4_ENMODE_MASK GENMASK(1, 0)
+
+/* PF9453_REG_BUCK123_PRESET_EN bit */
+#define BUCK123_PRESET_EN 0x80
+
+/* PF9453_BUCK1OUT bits */
+#define BUCK1OUT_MASK GENMASK(6, 0)
+
+/* PF9453_BUCK2OUT bits */
+#define BUCK2OUT_MASK GENMASK(6, 0)
+#define BUCK2OUT_STBY_MASK GENMASK(6, 0)
+
+/* PF9453_REG_BUCK3OUT bits */
+#define BUCK3OUT_MASK GENMASK(6, 0)
+
+/* PF9453_REG_BUCK4OUT bits */
+#define BUCK4OUT_MASK GENMASK(6, 0)
+
+/* PF9453_REG_LDO1_VOLT bits */
+#define LDO1_EN_MASK GENMASK(1, 0)
+#define LDO1OUT_MASK GENMASK(6, 0)
+
+/* PF9453_REG_LDO2_VOLT bits */
+#define LDO2_EN_MASK GENMASK(1, 0)
+#define LDO2OUT_MASK GENMASK(6, 0)
+
+/* PF9453_REG_LDOSNVS_VOLT bits */
+#define LDOSNVS_EN_MASK GENMASK(0, 0)
+#define LDOSNVSCFG1_MASK GENMASK(6, 0)
+
+/* PF9453_REG_IRQ bits */
+#define IRQ_RSVD 0x80
+#define IRQ_RSTB 0x40
+#define IRQ_ONKEY 0x20
+#define IRQ_RESETKEY 0x10
+#define IRQ_VR_FLT1 0x08
+#define IRQ_LOWVSYS 0x04
+#define IRQ_THERM_100 0x02
+#define IRQ_THERM_80 0x01
+
+/* PF9453_REG_RESET_CTRL bits */
+#define WDOG_B_CFG_MASK GENMASK(7, 6)
+#define WDOG_B_CFG_NONE 0x00
+#define WDOG_B_CFG_WARM 0x40
+#define WDOG_B_CFG_COLD 0x80
+
+/* PF9453_REG_CONFIG2 bits */
+#define I2C_LT_MASK GENMASK(1, 0)
+#define I2C_LT_FORCE_DISABLE 0x00
+#define I2C_LT_ON_STANDBY_RUN 0x01
+#define I2C_LT_ON_RUN 0x02
+#define I2C_LT_FORCE_ENABLE 0x03
+
+static const struct regmap_range pf9453_status_range = {
+ .range_min = PF9453_REG_INT1,
+ .range_max = PF9453_REG_PWRON_STAT,
+};
+
+static const struct regmap_access_table pf9453_volatile_regs = {
+ .yes_ranges = &pf9453_status_range,
+ .n_yes_ranges = 1,
+};
+
+static const struct regmap_config pf9453_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &pf9453_volatile_regs,
+ .max_register = PF9453_MAX_REG - 1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+/*
+ * BUCK2
+ * BUCK2RAM[1:0] BUCK2 DVS ramp rate setting
+ * 00: 25mV/1usec
+ * 01: 25mV/2usec
+ * 10: 25mV/4usec
+ * 11: 25mV/8usec
+ */
+static const unsigned int pf9453_dvs_buck_ramp_table[] = {
+ 25000, 12500, 6250, 3125
+};
+
+static bool is_reg_protect(uint reg)
+{
+ switch (reg) {
+ case PF9453_REG_BUCK1OUT:
+ case PF9453_REG_BUCK2OUT:
+ case PF9453_REG_BUCK3OUT:
+ case PF9453_REG_BUCK4OUT:
+ case PF9453_REG_LDO1OUT_L:
+ case PF9453_REG_LDO1OUT_H:
+ case PF9453_REG_LDO2OUT:
+ case PF9453_REG_LDOSNVS_CFG1:
+ case PF9453_REG_BUCK2OUT_MAX_LIMIT:
+ case PF9453_REG_BUCK2OUT_MIN_LIMIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int pf9453_pmic_write(struct pf9453 *pf9453, unsigned int reg, u8 mask, unsigned int val)
+{
+ int ret = -EINVAL;
+ u8 data, key;
+ u32 rxBuf;
+
+ /* If not updating entire register, perform a read-mod-write */
+ data = val;
+ key = PF9453_UNLOCK_KEY;
+
+ if (mask != 0xffU) {
+ /* Read data */
+ ret = regmap_read(pf9453->regmap, reg, &rxBuf);
+ if (ret) {
+ dev_err(pf9453->dev, "Read reg=%0x error!\n", reg);
+ return ret;
+ }
+ data = (val & mask) | (rxBuf & (~mask));
+ }
+
+ if (reg < PF9453_MAX_REG) {
+ if (is_reg_protect(reg)) {
+ ret = regmap_raw_write(pf9453->regmap, PF9453_REG_LOCK, &key, 1U);
+ if (ret) {
+ dev_err(pf9453->dev, "Write reg=%0x error!\n", reg);
+ return ret;
+ }
+
+ ret = regmap_raw_write(pf9453->regmap, reg, &data, 1U);
+ if (ret) {
+ dev_err(pf9453->dev, "Write reg=%0x error!\n", reg);
+ return ret;
+ }
+
+ key = PF9453_LOCK_KEY;
+ ret = regmap_raw_write(pf9453->regmap, PF9453_REG_LOCK, &key, 1U);
+ if (ret) {
+ dev_err(pf9453->dev, "Write reg=%0x error!\n", reg);
+ return ret;
+ }
+ } else {
+ ret = regmap_raw_write(pf9453->regmap, reg, &data, 1U);
+ if (ret) {
+ dev_err(pf9453->dev, "Write reg=%0x error!\n", reg);
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * pf9453_regulator_enable_regmap for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their enable() operation, saving some code.
+ */
+static int pf9453_regulator_enable_regmap(struct regulator_dev *rdev)
+{
+ struct pf9453 *pf9453 = dev_get_drvdata(rdev->dev.parent);
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->disable_val;
+ } else {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ }
+
+ return pf9453_pmic_write(pf9453, rdev->desc->enable_reg, rdev->desc->enable_mask, val);
+}
+
+/**
+ * pf9453_regulator_disable_regmap for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their disable() operation, saving some code.
+ */
+static int pf9453_regulator_disable_regmap(struct regulator_dev *rdev)
+{
+ struct pf9453 *pf9453 = dev_get_drvdata(rdev->dev.parent);
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted) {
+ val = rdev->desc->enable_val;
+ if (!val)
+ val = rdev->desc->enable_mask;
+ } else {
+ val = rdev->desc->disable_val;
+ }
+
+ return pf9453_pmic_write(pf9453, rdev->desc->enable_reg, rdev->desc->enable_mask, val);
+}
+
+/**
+ * pf9453_regulator_set_voltage_sel_regmap for regmap users
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their set_voltage_vsel operation, saving some code.
+ */
+static int pf9453_regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned int sel)
+{
+ struct pf9453 *pf9453 = dev_get_drvdata(rdev->dev.parent);
+ int ret;
+
+ sel <<= ffs(rdev->desc->vsel_mask) - 1;
+ ret = pf9453_pmic_write(pf9453, rdev->desc->vsel_reg, rdev->desc->vsel_mask, sel);
+ if (ret)
+ return ret;
+
+ if (rdev->desc->apply_bit)
+ ret = pf9453_pmic_write(pf9453, rdev->desc->apply_reg,
+ rdev->desc->apply_bit, rdev->desc->apply_bit);
+ return ret;
+}
+
+static int find_closest_bigger(unsigned int target, const unsigned int *table,
+ unsigned int num_sel, unsigned int *sel)
+{
+ unsigned int s, tmp, max, maxsel = 0;
+ bool found = false;
+
+ max = table[0];
+
+ for (s = 0; s < num_sel; s++) {
+ if (table[s] > max) {
+ max = table[s];
+ maxsel = s;
+ }
+ if (table[s] >= target) {
+ if (!found || table[s] - target < tmp - target) {
+ tmp = table[s];
+ *sel = s;
+ found = true;
+ if (tmp == target)
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ *sel = maxsel;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * pf9453_regulator_set_ramp_delay_regmap
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the ramp_reg
+ * and ramp_mask fields in their descriptor and then use this as their
+ * set_ramp_delay operation, saving some code.
+ */
+static int pf9453_regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay)
+{
+ struct pf9453 *pf9453 = dev_get_drvdata(rdev->dev.parent);
+ unsigned int sel;
+ int ret;
+
+ if (WARN_ON(!rdev->desc->n_ramp_values || !rdev->desc->ramp_delay_table))
+ return -EINVAL;
+
+ ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table,
+ rdev->desc->n_ramp_values, &sel);
+
+ if (ret) {
+ dev_warn(rdev_get_dev(rdev),
+ "Can't set ramp-delay %u, setting %u\n", ramp_delay,
+ rdev->desc->ramp_delay_table[sel]);
+ }
+
+ sel <<= ffs(rdev->desc->ramp_mask) - 1;
+
+ return pf9453_pmic_write(pf9453, rdev->desc->ramp_reg,
+ rdev->desc->ramp_mask, sel);
+}
+
+static const struct regulator_ops pf9453_dvs_buck_regulator_ops = {
+ .enable = pf9453_regulator_enable_regmap,
+ .disable = pf9453_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = pf9453_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 = pf9453_regulator_set_ramp_delay_regmap,
+};
+
+static const struct regulator_ops pf9453_buck_regulator_ops = {
+ .enable = pf9453_regulator_enable_regmap,
+ .disable = pf9453_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = pf9453_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 pf9453_ldo_regulator_ops = {
+ .enable = pf9453_regulator_enable_regmap,
+ .disable = pf9453_regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = pf9453_regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+/*
+ * BUCK1/3/4
+ * 0.60 to 3.775V (25mV step)
+ */
+static const struct linear_range pf9453_buck134_volts[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x00, 0x7F, 25000),
+};
+
+/*
+ * BUCK2
+ * 0.60 to 2.1875V (12.5mV step)
+ */
+static const struct linear_range pf9453_buck2_volts[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x00, 0x7F, 12500),
+};
+
+/*
+ * LDO1
+ * 0.8 to 3.3V (25mV step)
+ */
+static const struct linear_range pf9453_ldo1_volts[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x64, 25000),
+};
+
+/*
+ * LDO2
+ * 0.5 to 1.95V (25mV step)
+ */
+static const struct linear_range pf9453_ldo2_volts[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x00, 0x3A, 25000),
+};
+
+/*
+ * LDOSNVS
+ * 1.2 to 3.4V (25mV step)
+ */
+static const struct linear_range pf9453_ldosnvs_volts[] = {
+ REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x58, 25000),
+};
+
+static int buck_set_dvs(const struct regulator_desc *desc,
+ struct device_node *np, struct pf9453 *pf9453,
+ char *prop, unsigned int reg, unsigned int mask)
+{
+ int ret, i;
+ u32 uv;
+
+ ret = of_property_read_u32(np, prop, &uv);
+ if (ret == -EINVAL)
+ return 0;
+ else if (ret)
+ return ret;
+
+ for (i = 0; i < desc->n_voltages; i++) {
+ ret = regulator_desc_list_voltage_linear_range(desc, i);
+ if (ret < 0)
+ continue;
+ if (ret == uv) {
+ i <<= ffs(desc->vsel_mask) - 1;
+ ret = pf9453_pmic_write(pf9453, reg, mask, i);
+ break;
+ }
+ }
+
+ if (ret == 0) {
+ struct pf9453_regulator_desc *regulator = container_of(desc,
+ struct pf9453_regulator_desc, desc);
+
+ /* Enable DVS control through PMIC_STBY_REQ for this BUCK */
+ ret = pf9453_pmic_write(pf9453, regulator->desc.enable_reg,
+ BUCK2_LPMODE, BUCK2_LPMODE);
+ }
+ return ret;
+}
+
+static int pf9453_set_dvs_levels(struct device_node *np, const struct regulator_desc *desc,
+ struct regulator_config *cfg)
+{
+ struct pf9453_regulator_desc *data = container_of(desc, struct pf9453_regulator_desc, desc);
+ struct pf9453 *pf9453 = dev_get_drvdata(cfg->dev);
+ const struct pf9453_dvs_config *dvs = &data->dvs;
+ unsigned int reg, mask;
+ int i, ret = 0;
+ char *prop;
+
+ for (i = 0; i < PF9453_DVS_LEVEL_MAX; i++) {
+ switch (i) {
+ case PF9453_DVS_LEVEL_RUN:
+ prop = "nxp,dvs-run-voltage";
+ reg = dvs->run_reg;
+ mask = dvs->run_mask;
+ break;
+ case PF9453_DVS_LEVEL_DPSTANDBY:
+ case PF9453_DVS_LEVEL_STANDBY:
+ prop = "nxp,dvs-standby-voltage";
+ reg = dvs->standby_reg;
+ mask = dvs->standby_mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = buck_set_dvs(desc, np, pf9453, prop, reg, mask);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static const struct pf9453_regulator_desc pf9453_regulators[] = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("BUCK1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_BUCK1,
+ .ops = &pf9453_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_BUCK1_VOLTAGE_NUM,
+ .linear_ranges = pf9453_buck134_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_buck134_volts),
+ .vsel_reg = PF9453_REG_BUCK1OUT,
+ .vsel_mask = BUCK1OUT_MASK,
+ .enable_reg = PF9453_REG_BUCK1CTRL,
+ .enable_mask = BUCK1_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("BUCK2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_BUCK2,
+ .ops = &pf9453_dvs_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_BUCK2_VOLTAGE_NUM,
+ .linear_ranges = pf9453_buck2_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_buck2_volts),
+ .vsel_reg = PF9453_REG_BUCK2OUT,
+ .vsel_mask = BUCK2OUT_MASK,
+ .enable_reg = PF9453_REG_BUCK2CTRL,
+ .enable_mask = BUCK2_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
+ .ramp_reg = PF9453_REG_BUCK2CTRL,
+ .ramp_mask = BUCK2_RAMP_MASK,
+ .ramp_delay_table = pf9453_dvs_buck_ramp_table,
+ .n_ramp_values = ARRAY_SIZE(pf9453_dvs_buck_ramp_table),
+ .owner = THIS_MODULE,
+ .of_parse_cb = pf9453_set_dvs_levels,
+ },
+ .dvs = {
+ .run_reg = PF9453_REG_BUCK2OUT,
+ .run_mask = BUCK2OUT_MASK,
+ .standby_reg = PF9453_REG_BUCK2OUT_STBY,
+ .standby_mask = BUCK2OUT_STBY_MASK,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck3",
+ .of_match = of_match_ptr("BUCK3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_BUCK3,
+ .ops = &pf9453_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_BUCK3_VOLTAGE_NUM,
+ .linear_ranges = pf9453_buck134_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_buck134_volts),
+ .vsel_reg = PF9453_REG_BUCK3OUT,
+ .vsel_mask = BUCK3OUT_MASK,
+ .enable_reg = PF9453_REG_BUCK3CTRL,
+ .enable_mask = BUCK3_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("BUCK4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_BUCK4,
+ .ops = &pf9453_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_BUCK4_VOLTAGE_NUM,
+ .linear_ranges = pf9453_buck134_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_buck134_volts),
+ .vsel_reg = PF9453_REG_BUCK4OUT,
+ .vsel_mask = BUCK4OUT_MASK,
+ .enable_reg = PF9453_REG_BUCK4CTRL,
+ .enable_mask = BUCK4_ENMODE_MASK,
+ .enable_val = BUCK_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_LDO1,
+ .ops = &pf9453_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_LDO1_VOLTAGE_NUM,
+ .linear_ranges = pf9453_ldo1_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_ldo1_volts),
+ .vsel_reg = PF9453_REG_LDO1OUT_H,
+ .vsel_mask = LDO1OUT_MASK,
+ .enable_reg = PF9453_REG_LDO1CFG,
+ .enable_mask = LDO1_EN_MASK,
+ .enable_val = LDO_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_LDO2,
+ .ops = &pf9453_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_LDO2_VOLTAGE_NUM,
+ .linear_ranges = pf9453_ldo2_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_ldo2_volts),
+ .vsel_reg = PF9453_REG_LDO2OUT,
+ .vsel_mask = LDO2OUT_MASK,
+ .enable_reg = PF9453_REG_LDO2CFG,
+ .enable_mask = LDO2_EN_MASK,
+ .enable_val = LDO_ENMODE_ONREQ,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .desc = {
+ .name = "ldosnvs",
+ .of_match = of_match_ptr("LDO-SNVS"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = PF9453_LDOSNVS,
+ .ops = &pf9453_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = PF9453_LDOSNVS_VOLTAGE_NUM,
+ .linear_ranges = pf9453_ldosnvs_volts,
+ .n_linear_ranges = ARRAY_SIZE(pf9453_ldosnvs_volts),
+ .vsel_reg = PF9453_REG_LDOSNVS_CFG1,
+ .vsel_mask = LDOSNVSCFG1_MASK,
+ .enable_reg = PF9453_REG_LDOSNVS_CFG2,
+ .enable_mask = LDOSNVS_EN_MASK,
+ .owner = THIS_MODULE,
+ },
+ },
+ { }
+};
+
+static irqreturn_t pf9453_irq_handler(int irq, void *data)
+{
+ struct pf9453 *pf9453 = data;
+ struct regmap *regmap = pf9453->regmap;
+ unsigned int status;
+ int ret;
+
+ ret = regmap_read(regmap, PF9453_REG_INT1, &status);
+ if (ret < 0) {
+ dev_err(pf9453->dev, "Failed to read INT1(%d)\n", ret);
+ return IRQ_NONE;
+ }
+
+ if (status & IRQ_RSTB)
+ dev_warn(pf9453->dev, "IRQ_RSTB interrupt.\n");
+
+ if (status & IRQ_ONKEY)
+ dev_warn(pf9453->dev, "IRQ_ONKEY interrupt.\n");
+
+ if (status & IRQ_VR_FLT1)
+ dev_warn(pf9453->dev, "VRFLT1 interrupt.\n");
+
+ if (status & IRQ_RESETKEY)
+ dev_warn(pf9453->dev, "IRQ_RESETKEY interrupt.\n");
+
+ if (status & IRQ_LOWVSYS)
+ dev_warn(pf9453->dev, "LOWVSYS interrupt.\n");
+
+ if (status & IRQ_THERM_100)
+ dev_warn(pf9453->dev, "IRQ_THERM_100 interrupt.\n");
+
+ if (status & IRQ_THERM_80)
+ dev_warn(pf9453->dev, "IRQ_THERM_80 interrupt.\n");
+
+ return IRQ_HANDLED;
+}
+
+static int pf9453_i2c_probe(struct i2c_client *i2c)
+{
+ const struct pf9453_regulator_desc *regulator_desc = of_device_get_match_data(&i2c->dev);
+ struct regulator_config config = { };
+ unsigned int reset_ctrl;
+ unsigned int device_id;
+ struct pf9453 *pf9453;
+ int ret;
+
+ if (!i2c->irq)
+ return dev_err_probe(&i2c->dev, -EINVAL, "No IRQ configured?\n");
+
+ pf9453 = devm_kzalloc(&i2c->dev, sizeof(struct pf9453), GFP_KERNEL);
+ if (!pf9453)
+ return -ENOMEM;
+
+ pf9453->regmap = devm_regmap_init_i2c(i2c, &pf9453_regmap_config);
+ if (IS_ERR(pf9453->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(pf9453->regmap),
+ "regmap initialization failed\n");
+
+ pf9453->irq = i2c->irq;
+ pf9453->dev = &i2c->dev;
+
+ dev_set_drvdata(&i2c->dev, pf9453);
+
+ ret = regmap_read(pf9453->regmap, PF9453_REG_DEV_ID, &device_id);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Read device id error\n");
+
+ /* Check your board and dts for match the right pmic */
+ if ((device_id >> 4) != 0xb)
+ return dev_err_probe(&i2c->dev, -EINVAL, "Device id(%x) mismatched\n",
+ device_id >> 4);
+
+ while (regulator_desc->desc.name) {
+ const struct regulator_desc *desc;
+ struct regulator_dev *rdev;
+
+ desc = &regulator_desc->desc;
+
+ config.regmap = pf9453->regmap;
+ config.dev = pf9453->dev;
+
+ rdev = devm_regulator_register(pf9453->dev, desc, &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(pf9453->dev, PTR_ERR(rdev),
+ "Failed to register regulator(%s)\n", desc->name);
+
+ regulator_desc++;
+ }
+
+ ret = devm_request_threaded_irq(pf9453->dev, pf9453->irq, NULL, pf9453_irq_handler,
+ (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
+ "pf9453-irq", pf9453);
+ if (ret)
+ return dev_err_probe(pf9453->dev, ret, "Failed to request IRQ: %d\n", pf9453->irq);
+
+ /* Unmask all interrupt except PWRON/WDOG/RSVD */
+ ret = pf9453_pmic_write(pf9453, PF9453_REG_INT1_MASK,
+ IRQ_ONKEY | IRQ_RESETKEY | IRQ_RSTB | IRQ_VR_FLT1
+ | IRQ_LOWVSYS | IRQ_THERM_100 | IRQ_THERM_80, IRQ_RSVD);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
+
+ if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset"))
+ reset_ctrl = WDOG_B_CFG_WARM;
+ else
+ reset_ctrl = WDOG_B_CFG_COLD;
+
+ /* Set reset behavior on assertion of WDOG_B signal */
+ ret = pf9453_pmic_write(pf9453, PF9453_REG_RESET_CTRL, WDOG_B_CFG_MASK, reset_ctrl);
+ if (ret)
+ return dev_err_probe(&i2c->dev, ret, "Failed to set WDOG_B reset behavior\n");
+
+ /*
+ * The driver uses the LDO1OUT_H register to control the LDO1 regulator.
+ * This is only valid if the SD_VSEL input of the PMIC is high. Let's
+ * check if the pin is available as GPIO and set it to high.
+ */
+ pf9453->sd_vsel_gpio = gpiod_get_optional(pf9453->dev, "sd-vsel", GPIOD_OUT_HIGH);
+
+ if (IS_ERR(pf9453->sd_vsel_gpio))
+ return dev_err_probe(&i2c->dev, PTR_ERR(pf9453->sd_vsel_gpio),
+ "Failed to get SD_VSEL GPIO\n");
+
+ return 0;
+}
+
+static const struct of_device_id pf9453_of_match[] = {
+ {
+ .compatible = "nxp,pf9453",
+ .data = pf9453_regulators,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pf9453_of_match);
+
+static struct i2c_driver pf9453_i2c_driver = {
+ .driver = {
+ .name = "nxp-pf9453",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = pf9453_of_match,
+ },
+ .probe = pf9453_i2c_probe,
+};
+
+module_i2c_driver(pf9453_i2c_driver);
+
+MODULE_AUTHOR("Joy Zou <joy.zou@nxp.com>");
+MODULE_DESCRIPTION("NXP PF9453 Power Management IC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/rtq6752-regulator.c b/drivers/regulator/rtq6752-regulator.c
index d35d844eff3b..618904ede72c 100644
--- a/drivers/regulator/rtq6752-regulator.c
+++ b/drivers/regulator/rtq6752-regulator.c
@@ -105,7 +105,7 @@ static int rtq6752_get_error_flags(struct regulator_dev *rdev,
unsigned int *flags)
{
unsigned int val, events = 0;
- const unsigned int fault_mask[] = {
+ static const unsigned int fault_mask[] = {
RTQ6752_PAVDDF_MASK, RTQ6752_NAVDDF_MASK };
int rid = rdev_get_id(rdev), ret;