From: Jerome Neanne <jneanne@baylibre.com>
This patch adds support for TPS6594 regulators (bucks and LDOs).
The output voltages are configurable and are meant to supply power
to the main processor and other components.
Bucks can be used in single or multiphase mode, depending on PMIC
part number.
Signed-off-by: Jerome Neanne <jneanne@baylibre.com>
Signed-off-by: Esteban Blanc <eblanc@baylibre.com>
---
drivers/regulator/Kconfig | 13 +
drivers/regulator/Makefile | 1 +
drivers/regulator/tps6594-regulator.c | 628 ++++++++++++++++++++++++++
3 files changed, 642 insertions(+)
create mode 100644 drivers/regulator/tps6594-regulator.c
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index aae28d0a489c..5f01132b04e1 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1440,6 +1440,19 @@ config REGULATOR_TPS65219
voltage regulators. It supports software based voltage control
for different voltage domains.
+config REGULATOR_TPS6594
+ tristate "TI TPS6594 Power regulators"
+ depends on MFD_TPS6594 && OF
+ default MFD_TPS6594
+ help
+ This driver supports TPS6594 voltage regulator chips.
+ TPS6594 series of PMICs have 5 BUCKs and 4 LDOs
+ voltage regulators.
+ BUCKs 1,2,3,4 can be used in single phase or multiphase mode.
+ Part number defines which single or multiphase mode is i used.
+ It supports software based voltage control
+ for different voltage domains.
+
config REGULATOR_TPS6524X
tristate "TI TPS6524X Power regulators"
depends on SPI
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ee383d8fc835..cb420adf7670 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -172,6 +172,7 @@ obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
+obj-$(CONFIG_REGULATOR_TPS6594) += tps6594-regulator.o
obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o
obj-$(CONFIG_REGULATOR_TPS68470) += tps68470-regulator.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o
diff --git a/drivers/regulator/tps6594-regulator.c b/drivers/regulator/tps6594-regulator.c
new file mode 100644
index 000000000000..f8d5a78f93f2
--- /dev/null
+++ b/drivers/regulator/tps6594-regulator.c
@@ -0,0 +1,628 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Regulator driver for tps6594 PMIC
+//
+// Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#include <linux/mfd/tps6594.h>
+
+#define BUCK_NB 5
+#define LDO_NB 4
+#define MULTI_PHASE_NB 4
+#define REGS_INT_NB 4
+
+enum tps6594_regulator_id {
+ /* DCDC's */
+ TPS6594_BUCK_1,
+ TPS6594_BUCK_2,
+ TPS6594_BUCK_3,
+ TPS6594_BUCK_4,
+ TPS6594_BUCK_5,
+
+ /* LDOs */
+ TPS6594_LDO_1,
+ TPS6594_LDO_2,
+ TPS6594_LDO_3,
+ TPS6594_LDO_4,
+};
+
+enum tps6594_multi_regulator_id {
+ /* Multi-phase DCDC's */
+ TPS6594_BUCK_12,
+ TPS6594_BUCK_34,
+ TPS6594_BUCK_123,
+ TPS6594_BUCK_1234,
+};
+
+struct tps6594_regulator_irq_type {
+ const char *irq_name;
+ const char *regulator_name;
+ const char *event_name;
+ unsigned long event;
+};
+
+static struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = {
+ { TPS6594_IRQ_NAME_VCCA_OV, "VCCA", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_VCCA_UV, "VCCA", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_VMON1_OV, "VMON1", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_VMON1_UV, "VMON1", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_VMON1_RV, "VMON1", "residual voltage",
+ REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_VMON2_OV, "VMON2", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_VMON2_UV, "VMON2", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_VMON2_RV, "VMON2", "residual voltage",
+ REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+};
+
+struct tps6594_regulator_irq_data {
+ struct device *dev;
+ struct tps6594_regulator_irq_type *type;
+ struct regulator_dev *rdev;
+};
+
+struct tps6594_ext_regulator_irq_data {
+ struct device *dev;
+ struct tps6594_regulator_irq_type *type;
+};
+
+#define TPS6594_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \
+ _em, _cr, _cm, _lr, _nlr, _delay, _fuv, \
+ _ct, _ncl, _bpm) \
+ { \
+ .name = _name, \
+ .of_match = _of, \
+ .regulators_node = of_match_ptr("regulators"), \
+ .supply_name = _of, \
+ .id = _id, \
+ .ops = &(_ops), \
+ .n_voltages = _n, \
+ .type = _type, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = _vr, \
+ .vsel_mask = _vm, \
+ .csel_reg = _cr, \
+ .csel_mask = _cm, \
+ .curr_table = _ct, \
+ .n_current_limits = _ncl, \
+ .enable_reg = _er, \
+ .enable_mask = _em, \
+ .volt_table = NULL, \
+ .linear_ranges = _lr, \
+ .n_linear_ranges = _nlr, \
+ .ramp_delay = _delay, \
+ .fixed_uV = _fuv, \
+ .bypass_reg = _vr, \
+ .bypass_mask = _bpm, \
+ } \
+
+static const struct linear_range bucks_ranges[] = {
+ REGULATOR_LINEAR_RANGE(300000, 0x0, 0xe, 20000),
+ REGULATOR_LINEAR_RANGE(600000, 0xf, 0x72, 5000),
+ REGULATOR_LINEAR_RANGE(1100000, 0x73, 0xaa, 10000),
+ REGULATOR_LINEAR_RANGE(1660000, 0xab, 0xff, 20000),
+};
+
+static const struct linear_range ldos_1_2_3_ranges[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x4, 0x3a, 50000),
+};
+
+static const struct linear_range ldos_4_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1200000, 0x20, 0x74, 25000),
+};
+
+/* Operations permitted on BUCK1/2/3/4/5 */
+static const struct regulator_ops tps6594_bucks_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_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+
+};
+
+/* Operations permitted on LDO1/2/3 */
+static const struct regulator_ops tps6594_ldos_1_2_3_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_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_bypass = regulator_set_bypass_regmap,
+ .get_bypass = regulator_get_bypass_regmap,
+};
+
+/* Operations permitted on LDO4 */
+static const struct regulator_ops tps6594_ldos_4_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_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+};
+
+static const struct regulator_desc buck_regs[] = {
+ TPS6594_REGULATOR("BUCK1", "buck1", TPS6594_BUCK_1,
+ REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_VOUT_1(0),
+ TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_CTRL(0),
+ TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges,
+ 4, 0, 0, NULL, 0, 0),
+ TPS6594_REGULATOR("BUCK2", "buck2", TPS6594_BUCK_2,
+ REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_VOUT_1(1),
+ TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_CTRL(1),
+ TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges,
+ 4, 0, 0, NULL, 0, 0),
+ TPS6594_REGULATOR("BUCK3", "buck3", TPS6594_BUCK_3,
+ REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_VOUT_1(2),
+ TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_CTRL(2),
+ TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges,
+ 4, 0, 0, NULL, 0, 0),
+ TPS6594_REGULATOR("BUCK4", "buck4", TPS6594_BUCK_4,
+ REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_VOUT_1(3),
+ TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_CTRL(3),
+ TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges,
+ 4, 0, 0, NULL, 0, 0),
+ TPS6594_REGULATOR("BUCK5", "buck5", TPS6594_BUCK_5,
+ REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_VOUT_1(4),
+ TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_CTRL(4),
+ TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges,
+ 4, 0, 0, NULL, 0, 0),
+};
+
+static struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = {
+ { TPS6594_IRQ_NAME_BUCK1_OV, "BUCK1", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_BUCK1_UV, "BUCK1", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_BUCK1_SC, "BUCK1", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
+ { TPS6594_IRQ_NAME_BUCK1_ILIM, "BUCK1", "reach ilim, overcurrent",
+ REGULATOR_EVENT_OVER_CURRENT },
+};
+
+static struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = {
+ { TPS6594_IRQ_NAME_BUCK2_OV, "BUCK2", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_BUCK2_UV, "BUCK2", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_BUCK2_SC, "BUCK2", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
+ { TPS6594_IRQ_NAME_BUCK2_ILIM, "BUCK2", "reach ilim, overcurrent",
+ REGULATOR_EVENT_OVER_CURRENT },
+};
+
+static struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = {
+ { TPS6594_IRQ_NAME_BUCK3_OV, "BUCK3", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_BUCK3_UV, "BUCK3", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_BUCK3_SC, "BUCK3", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
+ { TPS6594_IRQ_NAME_BUCK3_ILIM, "BUCK3", "reach ilim, overcurrent",
+ REGULATOR_EVENT_OVER_CURRENT },
+};
+
+static struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = {
+ { TPS6594_IRQ_NAME_BUCK4_OV, "BUCK4", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_BUCK4_UV, "BUCK4", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_BUCK4_SC, "BUCK4", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
+ { TPS6594_IRQ_NAME_BUCK4_ILIM, "BUCK4", "reach ilim, overcurrent",
+ REGULATOR_EVENT_OVER_CURRENT },
+};
+
+static struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = {
+ { TPS6594_IRQ_NAME_BUCK5_OV, "BUCK5", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_BUCK5_UV, "BUCK5", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_BUCK5_SC, "BUCK5", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
+ { TPS6594_IRQ_NAME_BUCK5_ILIM, "BUCK5", "reach ilim, overcurrent",
+ REGULATOR_EVENT_OVER_CURRENT },
+};
+
+static struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = {
+ { TPS6594_IRQ_NAME_LDO1_OV, "LDO1", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_LDO1_UV, "LDO1", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_LDO1_SC, "LDO1", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
+ { TPS6594_IRQ_NAME_LDO1_ILIM, "LDO1", "reach ilim, overcurrent",
+ REGULATOR_EVENT_OVER_CURRENT },
+};
+
+static struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = {
+ { TPS6594_IRQ_NAME_LDO2_OV, "LDO2", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_LDO2_UV, "LDO2", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_LDO2_SC, "LDO2", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
+ { TPS6594_IRQ_NAME_LDO2_ILIM, "LDO2", "reach ilim, overcurrent",
+ REGULATOR_EVENT_OVER_CURRENT },
+};
+
+static struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = {
+ { TPS6594_IRQ_NAME_LDO3_OV, "LDO3", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_LDO3_UV, "LDO3", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_LDO3_SC, "LDO3", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
+ { TPS6594_IRQ_NAME_LDO3_ILIM, "LDO3", "reach ilim, overcurrent",
+ REGULATOR_EVENT_OVER_CURRENT },
+};
+
+static struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = {
+ { TPS6594_IRQ_NAME_LDO4_OV, "LDO4", "overvoltage", REGULATOR_EVENT_OVER_VOLTAGE_WARN },
+ { TPS6594_IRQ_NAME_LDO4_UV, "LDO4", "undervoltage", REGULATOR_EVENT_UNDER_VOLTAGE },
+ { TPS6594_IRQ_NAME_LDO4_SC, "LDO4", "short circuit", REGULATOR_EVENT_REGULATION_OUT },
+ { TPS6594_IRQ_NAME_LDO4_ILIM, "LDO4", "reach ilim, overcurrent",
+ REGULATOR_EVENT_OVER_CURRENT },
+};
+
+static struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = {
+ tps6594_buck1_irq_types,
+ tps6594_buck2_irq_types,
+ tps6594_buck3_irq_types,
+ tps6594_buck4_irq_types,
+ tps6594_buck5_irq_types,
+};
+
+static struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = {
+ tps6594_ldo1_irq_types,
+ tps6594_ldo2_irq_types,
+ tps6594_ldo3_irq_types,
+ tps6594_ldo4_irq_types,
+};
+
+static const struct regulator_desc multi_regs[] = {
+ TPS6594_REGULATOR("BUCK12", "buck12", TPS6594_BUCK_1,
+ REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_VOUT_1(1),
+ TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_CTRL(1),
+ TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges,
+ 4, 4000, 0, NULL, 0, 0),
+ TPS6594_REGULATOR("BUCK34", "buck34", TPS6594_BUCK_3,
+ REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_VOUT_1(3),
+ TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_CTRL(3),
+ TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges,
+ 4, 0, 0, NULL, 0, 0),
+ TPS6594_REGULATOR("BUCK123", "buck123", TPS6594_BUCK_1,
+ REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_VOUT_1(1),
+ TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_CTRL(1),
+ TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges,
+ 4, 4000, 0, NULL, 0, 0),
+ TPS6594_REGULATOR("BUCK1234", "buck1234", TPS6594_BUCK_1,
+ REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_VOUT_1(1),
+ TPS6594_MASK_BUCKS_VSET,
+ TPS6594_REG_BUCKX_CTRL(1),
+ TPS6594_BIT_BUCK_EN, 0, 0, bucks_ranges,
+ 4, 4000, 0, NULL, 0, 0),
+};
+
+static const struct regulator_desc ldo_regs[] = {
+ TPS6594_REGULATOR("LDO1", "ldo1", TPS6594_LDO_1,
+ REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET,
+ TPS6594_REG_LDOX_VOUT(0),
+ TPS6594_MASK_LDO123_VSET,
+ TPS6594_REG_LDOX_CTRL(0),
+ TPS6594_BIT_LDO_EN, 0, 0, ldos_1_2_3_ranges,
+ 1, 0, 0, NULL, 0, TPS6594_BIT_LDO_BYPASS),
+ TPS6594_REGULATOR("LDO2", "ldo2", TPS6594_LDO_2,
+ REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET,
+ TPS6594_REG_LDOX_VOUT(1),
+ TPS6594_MASK_LDO123_VSET,
+ TPS6594_REG_LDOX_CTRL(1),
+ TPS6594_BIT_LDO_EN, 0, 0, ldos_1_2_3_ranges,
+ 1, 0, 0, NULL, 0, TPS6594_BIT_LDO_BYPASS),
+ TPS6594_REGULATOR("LDO3", "ldo3", TPS6594_LDO_3,
+ REGULATOR_VOLTAGE, tps6594_ldos_1_2_3_ops, TPS6594_MASK_LDO123_VSET,
+ TPS6594_REG_LDOX_VOUT(2),
+ TPS6594_MASK_LDO123_VSET,
+ TPS6594_REG_LDOX_CTRL(2),
+ TPS6594_BIT_LDO_EN, 0, 0, ldos_1_2_3_ranges,
+ 1, 0, 0, NULL, 0, TPS6594_BIT_LDO_BYPASS),
+ TPS6594_REGULATOR("LDO4", "ldo4", TPS6594_LDO_4,
+ REGULATOR_VOLTAGE, tps6594_ldos_4_ops, TPS6594_MASK_LDO4_VSET >> 1,
+ TPS6594_REG_LDOX_VOUT(3),
+ TPS6594_MASK_LDO4_VSET,
+ TPS6594_REG_LDOX_CTRL(3),
+ TPS6594_BIT_LDO_EN, 0, 0, ldos_4_ranges,
+ 1, 0, 0, NULL, 0, 0),
+};
+
+static irqreturn_t tps6594_regulator_irq_handler(int irq, void *data)
+{
+ struct tps6594_regulator_irq_data *irq_data = data;
+
+ if (irq_data->type->event_name[0] == '\0') {
+ /* This is the timeout interrupt no specific regulator */
+ dev_err(irq_data->dev,
+ "System was put in shutdown due to timeout during an active or standby transition.\n");
+ return IRQ_HANDLED;
+ }
+
+ dev_err(irq_data->dev, "Error IRQ trap %s for %s\n",
+ irq_data->type->event_name, irq_data->type->regulator_name);
+
+ regulator_notifier_call_chain(irq_data->rdev,
+ irq_data->type->event, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static int tps6594_request_reg_irqs(struct platform_device *pdev,
+ struct regulator_dev *rdev,
+ struct tps6594_regulator_irq_data *irq_data,
+ struct tps6594_regulator_irq_type *tps6594_regs_irq_types,
+ int *irq_idx)
+{
+ struct tps6594_regulator_irq_type *irq_type;
+ struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
+ int j;
+ int irq;
+ int error;
+
+ for (j = 0; j < REGS_INT_NB; j++) {
+ irq_type = &tps6594_regs_irq_types[j];
+ irq = platform_get_irq_byname(pdev, irq_type->irq_name);
+ if (irq < 0)
+ return -EINVAL;
+
+ irq_data[*irq_idx + j].dev = tps->dev;
+ irq_data[*irq_idx + j].type = irq_type;
+ irq_data[*irq_idx + j].rdev = rdev;
+
+ error = devm_request_threaded_irq(tps->dev, irq, NULL,
+ tps6594_regulator_irq_handler,
+ IRQF_ONESHOT,
+ irq_type->irq_name,
+ &irq_data[*irq_idx]);
+ (*irq_idx)++;
+ if (error) {
+ dev_err(tps->dev, "tps6594 failed to request %s IRQ %d: %d\n",
+ irq_type->irq_name, irq, error);
+ return error;
+ }
+ }
+ return 0;
+}
+
+static int tps6594_regulator_probe(struct platform_device *pdev)
+{
+ struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_dev *rdev;
+ struct regulator_config config = {};
+ u8 buck_configured[BUCK_NB] = { 0 };
+ u8 buck_multi[MULTI_PHASE_NB] = { 0 };
+ int i, nranges;
+ int irq_idx = 0;
+ int buck_idx = 0;
+ int error, irq;
+ int ext_reg_irq_nb = 2;
+ struct tps6594_regulator_irq_data *irq_data;
+ struct tps6594_ext_regulator_irq_data *irq_ext_reg_data;
+ struct tps6594_regulator_irq_type *irq_type;
+ struct regulator_dev *rdevbucktbl[BUCK_NB];
+ struct regulator_dev *rdevmultitbl[MULTI_PHASE_NB];
+ struct regulator_dev *rdevldotbl[LDO_NB];
+ u32 multi_phase_id;
+ u32 multi_phase_id_tbl[2];
+
+ config.dev = tps->dev;
+ config.driver_data = tps;
+ config.regmap = tps->regmap;
+
+ /*
+ * Switch case defines different possible multi phase config
+ * This is based on dts custom property: multi-phase-id
+ * Using compatible or device rev is a too complex alternative
+ * Default case is no Multiphase buck.
+ * In case of Multiphase configuration, value should be defined for
+ * buck_configured to avoid creating bucks for every buck in multiphase
+ */
+
+ if (device_property_present(tps->dev, "ti,multi-phase-id")) {
+ nranges = device_property_count_u32(tps->dev, "ti,multi-phase-id");
+ if (nranges < 1 || nranges > 2) {
+ dev_err(tps->dev, "%s port range: '%s' property\n",
+ nranges == -EINVAL ? "Missing" : "Invalid",
+ "ti,multi-phase-id");
+ return -EINVAL;
+ }
+ error = device_property_read_u32_array(tps->dev, "ti,multi-phase-id",
+ multi_phase_id_tbl, nranges);
+ if (error) {
+ dev_err(tps->dev, "failed to parse '%s' property: %d\n",
+ "ti,multi-phase-id", error);
+ return error;
+ }
+ multi_phase_id = multi_phase_id_tbl[0];
+ /* Only configuration multiphase buck12 & buck34 requires 2 arguments */
+ if (nranges > 1 && multi_phase_id != 34)
+ multi_phase_id = multi_phase_id_tbl[1];
+
+ switch (multi_phase_id) {
+ case 12:
+ buck_multi[0] = 1;
+ buck_configured[0] = 1;
+ buck_configured[1] = 1;
+ break;
+ /* multiphase buck34 is supported only with buck12 */
+ case 34:
+ buck_multi[0] = 1;
+ buck_configured[0] = 1;
+ buck_configured[1] = 1;
+ buck_multi[1] = 1;
+ buck_configured[2] = 1;
+ buck_configured[3] = 1;
+ break;
+ case 123:
+ buck_multi[2] = 1;
+ buck_configured[0] = 1;
+ buck_configured[1] = 1;
+ buck_configured[2] = 1;
+ break;
+ case 1234:
+ buck_multi[3] = 1;
+ buck_configured[0] = 1;
+ buck_configured[1] = 1;
+ buck_configured[2] = 1;
+ buck_configured[3] = 1;
+ break;
+ }
+ }
+
+ if (tps->chip_id == LP8764X)
+ /* There is only 4 buck on LP8764X */
+ buck_configured[4] = 1;
+
+ irq_data = devm_kmalloc(tps->dev,
+ ARRAY_SIZE(tps6594_bucks_irq_types) *
+ REGS_INT_NB *
+ sizeof(struct tps6594_regulator_irq_data) +
+ ARRAY_SIZE(tps6594_ldos_irq_types) *
+ REGS_INT_NB *
+ sizeof(struct tps6594_regulator_irq_data),
+ GFP_KERNEL);
+ if (!irq_data)
+ return -ENOMEM;
+
+ for (i = 0; i < MULTI_PHASE_NB; i++) {
+ if (buck_multi[i] == 0)
+ continue;
+
+ rdev = devm_regulator_register(&pdev->dev, &multi_regs[i], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+ rdevmultitbl[i] = rdev;
+ /* config multiphase buck12+buck34 */
+ if (i == 1)
+ buck_idx = 2;
+ error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
+ tps6594_bucks_irq_types[buck_idx], &irq_idx);
+ if (error)
+ return error;
+ error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
+ tps6594_bucks_irq_types[buck_idx + 1], &irq_idx);
+ if (error)
+ return error;
+
+ if (i == 2 || i == 3) {
+ error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
+ tps6594_bucks_irq_types[buck_idx + 2],
+ &irq_idx);
+ if (error)
+ return error;
+ }
+ if (i == 3) {
+ error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
+ tps6594_bucks_irq_types[buck_idx + 3],
+ &irq_idx);
+ if (error)
+ return error;
+ }
+ }
+
+ for (i = 0; i < BUCK_NB; i++) {
+ if (buck_configured[i] == 1)
+ continue;
+
+ rdev = devm_regulator_register(&pdev->dev, &buck_regs[i], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+ rdevbucktbl[i] = rdev;
+
+ error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
+ tps6594_bucks_irq_types[i], &irq_idx);
+ if (error)
+ return error;
+ }
+
+ /* LP8764X dosen't have LDO */
+ if (tps->chip_id != LP8764X) {
+ for (i = 0; i < ARRAY_SIZE(ldo_regs); i++) {
+ rdev = devm_regulator_register(&pdev->dev, &ldo_regs[i], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev,
+ "failed to register %s regulator\n",
+ pdev->name);
+ return PTR_ERR(rdev);
+ }
+ rdevldotbl[i] = rdev;
+ error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
+ tps6594_ldos_irq_types[i],
+ &irq_idx);
+ if (error)
+ return error;
+ }
+ }
+
+ if (tps->chip_id == LP8764X)
+ ext_reg_irq_nb = ARRAY_SIZE(tps6594_ext_regulator_irq_types);
+
+ irq_ext_reg_data = devm_kmalloc(tps->dev,
+ ext_reg_irq_nb *
+ sizeof(struct tps6594_ext_regulator_irq_data),
+ GFP_KERNEL);
+ if (!irq_ext_reg_data)
+ return -ENOMEM;
+
+ for (i = 0; i < ext_reg_irq_nb; ++i) {
+ irq_type = &tps6594_ext_regulator_irq_types[i];
+
+ irq = platform_get_irq_byname(pdev, irq_type->irq_name);
+ if (irq < 0)
+ return -EINVAL;
+
+ irq_ext_reg_data[i].dev = tps->dev;
+ irq_ext_reg_data[i].type = irq_type;
+
+ error = devm_request_threaded_irq(tps->dev, irq, NULL,
+ tps6594_regulator_irq_handler,
+ IRQF_ONESHOT,
+ irq_type->irq_name,
+ &irq_ext_reg_data[i]);
+ if (error) {
+ dev_err(tps->dev, "failed to request %s IRQ %d: %d\n",
+ irq_type->irq_name, irq, error);
+ return error;
+ }
+ }
+ return 0;
+}
+
+static struct platform_driver tps6594_regulator_driver = {
+ .driver = {
+ .name = "tps6594-regulator",
+ },
+ .probe = tps6594_regulator_probe,
+};
+
+module_platform_driver(tps6594_regulator_driver);
+
+MODULE_ALIAS("platform:tps6594-regulator");
+MODULE_AUTHOR("Jerome Neanne <jneanne@baylibre.com>");
+MODULE_DESCRIPTION("TPS6594 voltage regulator driver");
+MODULE_LICENSE("GPL");
--
2.39.2
Hi Esteban,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on linusw-pinctrl/devel]
[also build test WARNING on linusw-pinctrl/for-next broonie-regulator/for-next abelloni/rtc-next linus/master v6.3-rc4 next-20230328]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Esteban-Blanc/rtc-tps6594-add-driver-for-TPS6594-PMIC-RTC/20230328-171612
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git devel
patch link: https://lore.kernel.org/r/20230328091448.648452-4-eblanc%40baylibre.com
patch subject: [PATCH v2 3/3] regulator: tps6594-regulator: Add driver for TI TPS6594 regulators
config: loongarch-allyesconfig (https://download.01.org/0day-ci/archive/20230329/202303290336.bSKllPZi-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/842fe9039c5ca8c856ee7433c0dff43ee7f52cfe
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Esteban-Blanc/rtc-tps6594-add-driver-for-TPS6594-PMIC-RTC/20230328-171612
git checkout 842fe9039c5ca8c856ee7433c0dff43ee7f52cfe
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=loongarch olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=loongarch SHELL=/bin/bash drivers/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202303290336.bSKllPZi-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/regulator/tps6594-regulator.c: In function 'tps6594_regulator_probe':
>> drivers/regulator/tps6594-regulator.c:423:31: warning: variable 'rdevldotbl' set but not used [-Wunused-but-set-variable]
423 | struct regulator_dev *rdevldotbl[LDO_NB];
| ^~~~~~~~~~
>> drivers/regulator/tps6594-regulator.c:422:31: warning: variable 'rdevmultitbl' set but not used [-Wunused-but-set-variable]
422 | struct regulator_dev *rdevmultitbl[MULTI_PHASE_NB];
| ^~~~~~~~~~~~
>> drivers/regulator/tps6594-regulator.c:421:31: warning: variable 'rdevbucktbl' set but not used [-Wunused-but-set-variable]
421 | struct regulator_dev *rdevbucktbl[BUCK_NB];
| ^~~~~~~~~~~
vim +/rdevldotbl +423 drivers/regulator/tps6594-regulator.c
405
406 static int tps6594_regulator_probe(struct platform_device *pdev)
407 {
408 struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
409 struct regulator_dev *rdev;
410 struct regulator_config config = {};
411 u8 buck_configured[BUCK_NB] = { 0 };
412 u8 buck_multi[MULTI_PHASE_NB] = { 0 };
413 int i, nranges;
414 int irq_idx = 0;
415 int buck_idx = 0;
416 int error, irq;
417 int ext_reg_irq_nb = 2;
418 struct tps6594_regulator_irq_data *irq_data;
419 struct tps6594_ext_regulator_irq_data *irq_ext_reg_data;
420 struct tps6594_regulator_irq_type *irq_type;
> 421 struct regulator_dev *rdevbucktbl[BUCK_NB];
> 422 struct regulator_dev *rdevmultitbl[MULTI_PHASE_NB];
> 423 struct regulator_dev *rdevldotbl[LDO_NB];
424 u32 multi_phase_id;
425 u32 multi_phase_id_tbl[2];
426
427 config.dev = tps->dev;
428 config.driver_data = tps;
429 config.regmap = tps->regmap;
430
431 /*
432 * Switch case defines different possible multi phase config
433 * This is based on dts custom property: multi-phase-id
434 * Using compatible or device rev is a too complex alternative
435 * Default case is no Multiphase buck.
436 * In case of Multiphase configuration, value should be defined for
437 * buck_configured to avoid creating bucks for every buck in multiphase
438 */
439
440 if (device_property_present(tps->dev, "ti,multi-phase-id")) {
441 nranges = device_property_count_u32(tps->dev, "ti,multi-phase-id");
442 if (nranges < 1 || nranges > 2) {
443 dev_err(tps->dev, "%s port range: '%s' property\n",
444 nranges == -EINVAL ? "Missing" : "Invalid",
445 "ti,multi-phase-id");
446 return -EINVAL;
447 }
448 error = device_property_read_u32_array(tps->dev, "ti,multi-phase-id",
449 multi_phase_id_tbl, nranges);
450 if (error) {
451 dev_err(tps->dev, "failed to parse '%s' property: %d\n",
452 "ti,multi-phase-id", error);
453 return error;
454 }
455 multi_phase_id = multi_phase_id_tbl[0];
456 /* Only configuration multiphase buck12 & buck34 requires 2 arguments */
457 if (nranges > 1 && multi_phase_id != 34)
458 multi_phase_id = multi_phase_id_tbl[1];
459
460 switch (multi_phase_id) {
461 case 12:
462 buck_multi[0] = 1;
463 buck_configured[0] = 1;
464 buck_configured[1] = 1;
465 break;
466 /* multiphase buck34 is supported only with buck12 */
467 case 34:
468 buck_multi[0] = 1;
469 buck_configured[0] = 1;
470 buck_configured[1] = 1;
471 buck_multi[1] = 1;
472 buck_configured[2] = 1;
473 buck_configured[3] = 1;
474 break;
475 case 123:
476 buck_multi[2] = 1;
477 buck_configured[0] = 1;
478 buck_configured[1] = 1;
479 buck_configured[2] = 1;
480 break;
481 case 1234:
482 buck_multi[3] = 1;
483 buck_configured[0] = 1;
484 buck_configured[1] = 1;
485 buck_configured[2] = 1;
486 buck_configured[3] = 1;
487 break;
488 }
489 }
490
491 if (tps->chip_id == LP8764X)
492 /* There is only 4 buck on LP8764X */
493 buck_configured[4] = 1;
494
495 irq_data = devm_kmalloc(tps->dev,
496 ARRAY_SIZE(tps6594_bucks_irq_types) *
497 REGS_INT_NB *
498 sizeof(struct tps6594_regulator_irq_data) +
499 ARRAY_SIZE(tps6594_ldos_irq_types) *
500 REGS_INT_NB *
501 sizeof(struct tps6594_regulator_irq_data),
502 GFP_KERNEL);
503 if (!irq_data)
504 return -ENOMEM;
505
506 for (i = 0; i < MULTI_PHASE_NB; i++) {
507 if (buck_multi[i] == 0)
508 continue;
509
510 rdev = devm_regulator_register(&pdev->dev, &multi_regs[i], &config);
511 if (IS_ERR(rdev)) {
512 dev_err(tps->dev, "failed to register %s regulator\n",
513 pdev->name);
514 return PTR_ERR(rdev);
515 }
516 rdevmultitbl[i] = rdev;
517 /* config multiphase buck12+buck34 */
518 if (i == 1)
519 buck_idx = 2;
520 error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
521 tps6594_bucks_irq_types[buck_idx], &irq_idx);
522 if (error)
523 return error;
524 error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
525 tps6594_bucks_irq_types[buck_idx + 1], &irq_idx);
526 if (error)
527 return error;
528
529 if (i == 2 || i == 3) {
530 error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
531 tps6594_bucks_irq_types[buck_idx + 2],
532 &irq_idx);
533 if (error)
534 return error;
535 }
536 if (i == 3) {
537 error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
538 tps6594_bucks_irq_types[buck_idx + 3],
539 &irq_idx);
540 if (error)
541 return error;
542 }
543 }
544
545 for (i = 0; i < BUCK_NB; i++) {
546 if (buck_configured[i] == 1)
547 continue;
548
549 rdev = devm_regulator_register(&pdev->dev, &buck_regs[i], &config);
550 if (IS_ERR(rdev)) {
551 dev_err(tps->dev, "failed to register %s regulator\n",
552 pdev->name);
553 return PTR_ERR(rdev);
554 }
555 rdevbucktbl[i] = rdev;
556
557 error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
558 tps6594_bucks_irq_types[i], &irq_idx);
559 if (error)
560 return error;
561 }
562
563 /* LP8764X dosen't have LDO */
564 if (tps->chip_id != LP8764X) {
565 for (i = 0; i < ARRAY_SIZE(ldo_regs); i++) {
566 rdev = devm_regulator_register(&pdev->dev, &ldo_regs[i], &config);
567 if (IS_ERR(rdev)) {
568 dev_err(tps->dev,
569 "failed to register %s regulator\n",
570 pdev->name);
571 return PTR_ERR(rdev);
572 }
573 rdevldotbl[i] = rdev;
574 error = tps6594_request_reg_irqs(pdev, rdev, irq_data,
575 tps6594_ldos_irq_types[i],
576 &irq_idx);
577 if (error)
578 return error;
579 }
580 }
581
582 if (tps->chip_id == LP8764X)
583 ext_reg_irq_nb = ARRAY_SIZE(tps6594_ext_regulator_irq_types);
584
585 irq_ext_reg_data = devm_kmalloc(tps->dev,
586 ext_reg_irq_nb *
587 sizeof(struct tps6594_ext_regulator_irq_data),
588 GFP_KERNEL);
589 if (!irq_ext_reg_data)
590 return -ENOMEM;
591
592 for (i = 0; i < ext_reg_irq_nb; ++i) {
593 irq_type = &tps6594_ext_regulator_irq_types[i];
594
595 irq = platform_get_irq_byname(pdev, irq_type->irq_name);
596 if (irq < 0)
597 return -EINVAL;
598
599 irq_ext_reg_data[i].dev = tps->dev;
600 irq_ext_reg_data[i].type = irq_type;
601
602 error = devm_request_threaded_irq(tps->dev, irq, NULL,
603 tps6594_regulator_irq_handler,
604 IRQF_ONESHOT,
605 irq_type->irq_name,
606 &irq_ext_reg_data[i]);
607 if (error) {
608 dev_err(tps->dev, "failed to request %s IRQ %d: %d\n",
609 irq_type->irq_name, irq, error);
610 return error;
611 }
612 }
613 return 0;
614 }
615
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests
© 2016 - 2026 Red Hat, Inc.