From: Stoyan Bogdanov <sbogdanov@baylibre.com>
To: jbrunet@baylibre.com, linux@roeck-us.net, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org, corbet@lwn.net,
skhan@linuxfoundation.org
Cc: linux-hwmon@vger.kernel.org, devicetree@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
Stoyan Bogdanov <sbogdanov@baylibre.com>
Subject: [PATCH v7 3/3] hwmon: (pmbus/tps25990): Add TPS1689 support
Date: Mon, 17 Aug 2026 13:14:45 +0300 [thread overview]
Message-ID: <20260817101455.3526260-4-sbogdanov@baylibre.com> (raw)
In-Reply-To: <20260817101455.3526260-1-sbogdanov@baylibre.com>
Extend the existing TPS25990 driver to support the TPS1689 eFuse,
as both devices share the same command interface and functionality.
Update the documentation to include TPS1689 support.
Signed-off-by: Stoyan Bogdanov <sbogdanov@baylibre.com>
---
Documentation/hwmon/tps25990.rst | 15 ++--
drivers/hwmon/pmbus/tps25990.c | 126 ++++++++++++++++++++++++++++---
2 files changed, 124 insertions(+), 17 deletions(-)
diff --git a/Documentation/hwmon/tps25990.rst b/Documentation/hwmon/tps25990.rst
index 04faec780d26..e8bc9a550bda 100644
--- a/Documentation/hwmon/tps25990.rst
+++ b/Documentation/hwmon/tps25990.rst
@@ -9,26 +9,31 @@ Supported chips:
Prefix: 'tps25990'
- * Datasheet
+ Datasheet: Publicly available at Texas Instruments website: https://www.ti.com/lit/gpn/tps25990
- Publicly available at Texas Instruments website: https://www.ti.com/lit/gpn/tps25990
+ * TI TPS1689
+
+ Prefix: 'tps1689'
+
+ Datasheet: Publicly available at Texas Instruments website: https://www.ti.com/lit/gpn/tps1689
Author:
Jerome Brunet <jbrunet@baylibre.com>
+ Stoyan Bogdanov <sbogdanov@baylibre.com>
Description
-----------
-This driver implements support for TI TPS25990 eFuse.
+This driver implements support for TI TPS25990 and TI TPS1689 eFuse chips.
This is an integrated, high-current circuit protection and power
management device with PMBUS interface
-Device compliant with:
+Devices are compliant with:
- PMBus rev 1.3 interface.
-Device supports direct format for reading input voltages,
+Devices supports direct format for reading input voltages,
output voltage, input current, input power and temperature.
Due to the specificities of the chip, all history reset attributes
diff --git a/drivers/hwmon/pmbus/tps25990.c b/drivers/hwmon/pmbus/tps25990.c
index 7634ac743025..0d5c99053f23 100644
--- a/drivers/hwmon/pmbus/tps25990.c
+++ b/drivers/hwmon/pmbus/tps25990.c
@@ -47,7 +47,14 @@
PK_MIN_AVG_RST_AVG | \
PK_MIN_AVG_RST_MIN)
+#define TPS1689_VIN_OV_RANGE_SEL_MASK GENMASK(7, 6)
+#define TPS1689_VIN_VOV_MASK GENMASK(5, 0)
+#define TPS1689_VIN_SCALING 251
+#define TPS1689_VIN_VOV_STEP_MV 250
+#define TPS1689_VIN_RANGE_SPAN_MV 16000
+
enum chips {
+ tps1689,
tps25990,
};
@@ -105,6 +112,8 @@ static int tps25990_mfr_write_protect_get(struct i2c_client *client)
static int tps25990_read_word_data(struct i2c_client *client,
int page, int phase, int reg)
{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct tps25990_data *data = container_of(info, struct tps25990_data, info);
int ret;
switch (reg) {
@@ -193,9 +202,18 @@ static int tps25990_read_word_data(struct i2c_client *client,
ret = pmbus_read_word_data(client, page, phase, reg);
if (ret < 0)
break;
- ret = DIV_ROUND_CLOSEST(ret * TPS25990_VIN_OVF_NUM,
- TPS25990_VIN_OVF_DIV);
- ret += TPS25990_VIN_OVF_OFF;
+ if (data->chip_id == tps25990) {
+ ret = DIV_ROUND_CLOSEST(ret * TPS25990_VIN_OVF_NUM,
+ TPS25990_VIN_OVF_DIV);
+ ret += TPS25990_VIN_OVF_OFF;
+ } else if (data->chip_id == tps1689) {
+ int rng = (FIELD_GET(TPS1689_VIN_OV_RANGE_SEL_MASK, ret) + 1) *
+ TPS1689_VIN_RANGE_SPAN_MV;
+ int vov = FIELD_GET(TPS1689_VIN_VOV_MASK, ret) * TPS1689_VIN_VOV_STEP_MV;
+
+ ret = DIV_ROUND_CLOSEST(rng + vov - TPS1689_VIN_RANGE_SPAN_MV,
+ TPS1689_VIN_SCALING);
+ }
break;
case PMBUS_IIN_OC_FAULT_LIMIT:
@@ -238,6 +256,8 @@ static int tps25990_read_word_data(struct i2c_client *client,
static int tps25990_write_word_data(struct i2c_client *client,
int page, int reg, u16 value)
{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct tps25990_data *data = container_of(info, struct tps25990_data, info);
int ret;
switch (reg) {
@@ -249,26 +269,52 @@ static int tps25990_write_word_data(struct i2c_client *client,
case PMBUS_OT_WARN_LIMIT:
case PMBUS_OT_FAULT_LIMIT:
case PMBUS_PIN_OP_WARN_LIMIT:
- value >>= TPS25990_8B_SHIFT;
+ value = clamp_val((s16)value, 0, S16_MAX) >> TPS25990_8B_SHIFT;
value = clamp_val(value, 0, 0xff);
ret = pmbus_write_word_data(client, page, reg, value);
break;
case PMBUS_VIN_OV_FAULT_LIMIT:
- value -= TPS25990_VIN_OVF_OFF;
- value = DIV_ROUND_CLOSEST(((unsigned int)value) * TPS25990_VIN_OVF_DIV,
- TPS25990_VIN_OVF_NUM);
- value = clamp_val(value, 0, 0xf);
+ if ((s16)value < 0)
+ return -EINVAL;
+
+ if (data->chip_id == tps25990) {
+ int tmp = (int)value - TPS25990_VIN_OVF_OFF;
+
+ tmp = clamp_val(tmp, 0, INT_MAX);
+ value = DIV_ROUND_CLOSEST((unsigned int)tmp * TPS25990_VIN_OVF_DIV,
+ TPS25990_VIN_OVF_NUM);
+ value = clamp_val(value, 0, 0xf);
+ } else if (data->chip_id == tps1689) {
+ u32 scaled_value = value * TPS1689_VIN_SCALING + TPS1689_VIN_RANGE_SPAN_MV;
+ u32 rng_idx = scaled_value / TPS1689_VIN_RANGE_SPAN_MV;
+ u32 ov_set;
+
+ rng_idx = clamp_val(rng_idx, 1,
+ FIELD_MAX(TPS1689_VIN_OV_RANGE_SEL_MASK) + 1);
+ ov_set = scaled_value - (TPS1689_VIN_RANGE_SPAN_MV * rng_idx);
+ ov_set = min_t(u32, ov_set / TPS1689_VIN_VOV_STEP_MV,
+ FIELD_MAX(TPS1689_VIN_VOV_MASK));
+ value = FIELD_PREP(TPS1689_VIN_OV_RANGE_SEL_MASK, rng_idx - 1) |
+ FIELD_PREP(TPS1689_VIN_VOV_MASK, ov_set);
+ }
ret = pmbus_write_word_data(client, page, reg, value);
break;
- case PMBUS_IIN_OC_FAULT_LIMIT:
- value -= TPS25990_IIN_OCF_OFF;
- value = DIV_ROUND_CLOSEST(((unsigned int)value) * TPS25990_IIN_OCF_DIV,
+ case PMBUS_IIN_OC_FAULT_LIMIT: {
+ int tmp;
+
+ if ((s16)value < 0)
+ return -EINVAL;
+
+ tmp = (int)value - TPS25990_IIN_OCF_OFF;
+ tmp = clamp_val(tmp, 0, INT_MAX);
+ value = DIV_ROUND_CLOSEST((unsigned int)tmp * TPS25990_IIN_OCF_DIV,
TPS25990_IIN_OCF_NUM);
value = clamp_val(value, 0, 0x3f);
ret = pmbus_write_byte_data(client, page, TPS25990_VIREF, value);
break;
+ }
case PMBUS_VIRT_SAMPLES:
value = clamp_val(value, 1, 1 << PK_MIN_AVG_AVG_CNT);
@@ -347,6 +393,60 @@ static const struct regulator_desc tps25990_reg_desc[] = {
#endif
static const struct pmbus_driver_info tps25990_base_info[] = {
+ [tps1689] = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = direct,
+ .m[PSC_VOLTAGE_IN] = 3984,
+ .b[PSC_VOLTAGE_IN] = -63750,
+ .R[PSC_VOLTAGE_IN] = -3,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .m[PSC_VOLTAGE_OUT] = 1166,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = -2,
+ .format[PSC_TEMPERATURE] = direct,
+ .m[PSC_TEMPERATURE] = 140,
+ .b[PSC_TEMPERATURE] = 32103,
+ .R[PSC_TEMPERATURE] = -2,
+ /*
+ * Current and Power measurement depends on the ohm value
+ * of Rimon. m is multiplied by 1000 below to have an integer
+ * and -3 is added to R to compensate.
+ */
+ .format[PSC_CURRENT_IN] = direct,
+ .m[PSC_CURRENT_IN] = 9548,
+ .b[PSC_CURRENT_IN] = 0,
+ .R[PSC_CURRENT_IN] = -6,
+ .format[PSC_CURRENT_OUT] = direct,
+ .m[PSC_CURRENT_OUT] = 24347,
+ .b[PSC_CURRENT_OUT] = 0,
+ .R[PSC_CURRENT_OUT] = -3,
+ .format[PSC_POWER] = direct,
+ .m[PSC_POWER] = 2775,
+ .b[PSC_POWER] = 0,
+ .R[PSC_POWER] = -4,
+ .func[0] = (PMBUS_HAVE_VIN |
+ PMBUS_HAVE_VOUT |
+ PMBUS_HAVE_VMON |
+ PMBUS_HAVE_IIN |
+ PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_PIN |
+ PMBUS_HAVE_TEMP |
+ PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_STATUS_INPUT |
+ PMBUS_HAVE_STATUS_TEMP |
+ PMBUS_HAVE_SAMPLES),
+
+ .read_word_data = tps25990_read_word_data,
+ .write_word_data = tps25990_write_word_data,
+ .read_byte_data = tps25990_read_byte_data,
+ .write_byte_data = tps25990_write_byte_data,
+
+#if IS_ENABLED(CONFIG_SENSORS_TPS25990_REGULATOR)
+ .reg_desc = tps25990_reg_desc,
+ .num_regulators = ARRAY_SIZE(tps25990_reg_desc),
+#endif
+ },
[tps25990] = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = direct,
@@ -389,7 +489,6 @@ static const struct pmbus_driver_info tps25990_base_info[] = {
.write_word_data = tps25990_write_word_data,
.read_byte_data = tps25990_read_byte_data,
.write_byte_data = tps25990_write_byte_data,
-
#if IS_ENABLED(CONFIG_SENSORS_TPS25990_REGULATOR)
.reg_desc = tps25990_reg_desc,
.num_regulators = ARRAY_SIZE(tps25990_reg_desc),
@@ -398,12 +497,14 @@ static const struct pmbus_driver_info tps25990_base_info[] = {
};
static const struct i2c_device_id tps25990_i2c_id[] = {
+ { .name = "tps1689", .driver_data = tps1689 },
{ .name = "tps25990", .driver_data = tps25990 },
{}
};
MODULE_DEVICE_TABLE(i2c, tps25990_i2c_id);
static const struct of_device_id tps25990_of_match[] = {
+ { .compatible = "ti,tps1689", .data = (void *)tps1689 },
{ .compatible = "ti,tps25990", .data = (void *)tps25990 },
{}
};
@@ -438,6 +539,7 @@ static int tps25990_probe(struct i2c_client *client)
/* Adapt the current and power scale for each instance */
tps25990_set_m(&data->info.m[PSC_CURRENT_IN], rimon);
+ tps25990_set_m(&data->info.m[PSC_CURRENT_OUT], rimon);
tps25990_set_m(&data->info.m[PSC_POWER], rimon);
return pmbus_do_probe(client, &data->info);
--
2.43.0
next prev parent reply other threads:[~2026-08-17 10:15 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-17 10:14 [PATCH v7 0/3] Rework TPS25990 direct conversions and add TPS1689 support Stoyan Bogdanov
2026-08-17 10:14 ` [PATCH v7 1/3] hwmon: (pmbus/tps25990): Rework driver for multi-device support Stoyan Bogdanov
2026-08-17 10:20 ` sashiko-bot
2026-08-18 23:37 ` Guenter Roeck
2026-08-17 10:14 ` [PATCH v7 2/3] dt-bindings: hwmon: pmbus/tps25990: Add TPS1689 Stoyan Bogdanov
2026-08-17 10:19 ` sashiko-bot
2026-08-18 23:37 ` Guenter Roeck
2026-08-17 10:14 ` Stoyan Bogdanov [this message]
2026-08-17 10:26 ` [PATCH v7 3/3] hwmon: (pmbus/tps25990): Add TPS1689 support sashiko-bot
2026-08-18 23:38 ` Guenter Roeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260817101455.3526260-4-sbogdanov@baylibre.com \
--to=sbogdanov@baylibre.com \
--cc=conor+dt@kernel.org \
--cc=corbet@lwn.net \
--cc=devicetree@vger.kernel.org \
--cc=jbrunet@baylibre.com \
--cc=krzk+dt@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=robh@kernel.org \
--cc=skhan@linuxfoundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.