* [PATCH v4 1/3] dt-bindings: hwmon: ti,tmp108: Add P3T1035,P3T2030
@ 2026-01-16 11:35 Mayank Mahajan
2026-01-16 11:35 ` [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030 Mayank Mahajan
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Mayank Mahajan @ 2026-01-16 11:35 UTC (permalink / raw)
To: linux, corbet, robh, krzk+dt, conor+dt, linux-hwmon, devicetree,
linux-doc, linux-kernel
Cc: priyanka.jain, vikash.bansal, Mayank Mahajan
Document the NXP P3T1035 and P3T2030 compatibles in TMP108.
Signed-off-by: Mayank Mahajan <mayankmahajan.x@nxp.com>
---
V1 -> V2:
- No changes in v2.
V2 -> V3:
- Add P3T1035 fallback for P3T2030 as they are functionally identical.
- Add comment in the description explaining the use of P3T2030.
V3 -> V4:
- Remove comment in the description explaining the schema.
.../devicetree/bindings/hwmon/ti,tmp108.yaml | 21 ++++++++++++-------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml
index a6f9319e068d..9f6c9f6fa561 100644
--- a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml
+++ b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml
@@ -4,27 +4,32 @@
$id: http://devicetree.org/schemas/hwmon/ti,tmp108.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: TMP108/P3T1085(NXP) temperature sensor
+title: TMP108/P3T1035/P3T1085/P3T2030 temperature sensor
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
description: |
- The TMP108/P3T1085(NXP) is a digital-output temperature sensor with a
- dynamically-programmable limit window, and under- and overtemperature
- alert functions.
+ The TMP108 or NXP P3T Family (P3T1035, P3T1085 and P3T2030) is a digital-
+ output temperature sensor with a dynamically-programmable limit window,
+ and under- and over-temperature alert functions.
- P3T1085(NXP) support I3C.
+ NXP P3T Family (P3T1035, P3T1085 and P3T2030) supports I3C.
Datasheets:
https://www.ti.com/product/TMP108
https://www.nxp.com/docs/en/data-sheet/P3T1085UK.pdf
+ https://www.nxp.com/docs/en/data-sheet/P3T1035XUK_P3T2030XUK.pdf
properties:
compatible:
- enum:
- - nxp,p3t1085
- - ti,tmp108
+ oneOf:
+ - items:
+ - const: nxp,p3t2030
+ - const: nxp,p3t1035
+ - const: nxp,p3t1035
+ - const: nxp,p3t1085
+ - const: ti,tmp108
interrupts:
items:
base-commit: 983d014aafb14ee5e4915465bf8948e8f3a723b5
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030
2026-01-16 11:35 [PATCH v4 1/3] dt-bindings: hwmon: ti,tmp108: Add P3T1035,P3T2030 Mayank Mahajan
@ 2026-01-16 11:35 ` Mayank Mahajan
2026-01-16 21:37 ` kernel test robot
2026-01-16 22:28 ` Frank Li
2026-01-16 11:35 ` [PATCH v4 3/3] hwmon: (tmp108) Add P3T1035 and P3T2030 support Mayank Mahajan
2026-01-16 14:38 ` [PATCH v4 1/3] dt-bindings: hwmon: ti,tmp108: Add P3T1035,P3T2030 Krzysztof Kozlowski
2 siblings, 2 replies; 9+ messages in thread
From: Mayank Mahajan @ 2026-01-16 11:35 UTC (permalink / raw)
To: linux, corbet, robh, krzk+dt, conor+dt, linux-hwmon, devicetree,
linux-doc, linux-kernel
Cc: priyanka.jain, vikash.bansal, Mayank Mahajan
Add support for the P3T1035 & P3T2030 temperature sensor. While mostly
compatible with the TMP108, P3T1035 uses an 8-bit configuration register
instead of the 16-bit layout used by TMP108. Updated driver to handle
this difference during configuration read/write.
Signed-off-by: Mayank Mahajan <mayankmahajan.x@nxp.com>
---
V1 -> V2:
- Disabled hysteresis in is_visible function for P3T1035.
- Added tables for conversion rate similar to the LM75 driver.
- Implemented different bus access depending on the chip being used.
- Removed regmap for 8 bits; now we are using one regmap as before.
- Added read and write functions for i2c and i3c for use with regmap.
- Mapped the 8-bit configuration register to a 16 bit value for P3T1035.
V2 -> V3:
- Remove changes not relevant to adding a new device in the driver.
- Address warnings due to incorrect usage of casting operations.
- Remove the usage of P3T2030 as it's functionally identical to P3T1035.
V3 -> V4:
- Add GENMASK for getting mask for conversion rates.
- Add static arrays for containing sample times for different sensors.
- Remove redundant code such as checking for NULL pointer in probe.
- Improve readability by removing double negation.
- Remove type cast where not required; make reg_buf & val_buf local.
drivers/hwmon/Kconfig | 2 +-
drivers/hwmon/tmp108.c | 203 +++++++++++++++++++++++++++++++++--------
2 files changed, 164 insertions(+), 41 deletions(-)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 157678b821fc..31969bddc812 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -2398,7 +2398,7 @@ config SENSORS_TMP108
select REGMAP_I3C if I3C
help
If you say yes here you get support for Texas Instruments TMP108
- sensor chips and NXP P3T1085.
+ sensor chips, NXP temperature sensors P3T1035, P3T1085 and P3T2030.
This driver can also be built as a module. If so, the module
will be called tmp108.
diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c
index 60a237cbedbc..d308e2aed18a 100644
--- a/drivers/hwmon/tmp108.c
+++ b/drivers/hwmon/tmp108.c
@@ -17,9 +17,16 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/util_macros.h>
#define DRIVER_NAME "tmp108"
+enum tmp108_hw_id {
+ P3T1035_ID, /* For sensors p3t1035 and p3t2030 */
+ P3T1085_ID,
+ TMP108_ID,
+};
+
#define TMP108_REG_TEMP 0x00
#define TMP108_REG_CONF 0x01
#define TMP108_REG_TLOW 0x02
@@ -61,6 +68,7 @@
#define TMP108_CONVRATE_1HZ TMP108_CONF_CR0 /* Default */
#define TMP108_CONVRATE_4HZ TMP108_CONF_CR1
#define TMP108_CONVRATE_16HZ (TMP108_CONF_CR0|TMP108_CONF_CR1)
+#define TMP108_CONVRATE_SHIFT 13
#define TMP108_CONF_HYSTERESIS_MASK (TMP108_CONF_HYS0|TMP108_CONF_HYS1)
#define TMP108_HYSTERESIS_0C 0x0000
@@ -70,12 +78,23 @@
#define TMP108_CONVERSION_TIME_MS 30 /* in milli-seconds */
+#define TMP108_CONF_CR0_POS 13
+#define TMP108_CONF_CR1_POS 14
+#define TMP108_CONF_CONVRATE_FLD GENMASK(TMP108_CONF_CR1_POS, TMP108_CONF_CR0_POS)
+
struct tmp108 {
- struct regmap *regmap;
- u16 orig_config;
- unsigned long ready_time;
+ struct regmap *regmap;
+ u16 orig_config;
+ unsigned long ready_time;
+ enum tmp108_hw_id hw_id;
+ bool config_reg_16bits;
+ ushort *sample_times;
+ size_t n_sample_times;
};
+ushort p3t1035_sample_times[] = {4000, 1000, 250, 125};
+ushort tmp108_sample_times[] = {4000, 1000, 250, 63};
+
/* convert 12-bit TMP108 register value to milliCelsius */
static inline int tmp108_temp_reg_to_mC(s16 val)
{
@@ -101,21 +120,7 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
®val);
if (err < 0)
return err;
- switch (regval & TMP108_CONF_CONVRATE_MASK) {
- case TMP108_CONVRATE_0P25HZ:
- default:
- *temp = 4000;
- break;
- case TMP108_CONVRATE_1HZ:
- *temp = 1000;
- break;
- case TMP108_CONVRATE_4HZ:
- *temp = 250;
- break;
- case TMP108_CONVRATE_16HZ:
- *temp = 63;
- break;
- }
+ *temp = tmp108->sample_times[FIELD_GET(TMP108_CONF_CONVRATE_FLD, regval)];
return 0;
}
return -EOPNOTSUPP;
@@ -192,22 +197,17 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
{
struct tmp108 *tmp108 = dev_get_drvdata(dev);
u32 regval, mask;
+ u8 index;
int err;
if (type == hwmon_chip) {
if (attr == hwmon_chip_update_interval) {
- if (temp < 156)
- mask = TMP108_CONVRATE_16HZ;
- else if (temp < 625)
- mask = TMP108_CONVRATE_4HZ;
- else if (temp < 2500)
- mask = TMP108_CONVRATE_1HZ;
- else
- mask = TMP108_CONVRATE_0P25HZ;
+ index = find_closest_descending(temp, tmp108->sample_times,
+ tmp108->n_sample_times);
return regmap_update_bits(tmp108->regmap,
TMP108_REG_CONF,
TMP108_CONF_CONVRATE_MASK,
- mask);
+ FIELD_PREP(TMP108_CONF_CONVRATE_FLD, index));
}
return -EOPNOTSUPP;
}
@@ -251,6 +251,8 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
+ const struct tmp108 *tmp108 = data;
+
if (type == hwmon_chip && attr == hwmon_chip_update_interval)
return 0644;
@@ -264,8 +266,11 @@ static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
return 0444;
case hwmon_temp_min:
case hwmon_temp_max:
+ return 0644;
case hwmon_temp_min_hyst:
case hwmon_temp_max_hyst:
+ if (tmp108->hw_id == P3T1035_ID)
+ return 0;
return 0644;
default:
return 0;
@@ -311,6 +316,106 @@ static bool tmp108_is_volatile_reg(struct device *dev, unsigned int reg)
return reg == TMP108_REG_TEMP || reg == TMP108_REG_CONF;
}
+static int tmp108_i2c_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct i2c_client *client = context;
+ struct tmp108 *tmp108 = i2c_get_clientdata(client);
+ int ret;
+
+ if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits) {
+ ret = i2c_smbus_read_byte_data(client, TMP108_REG_CONF);
+ if (ret < 0)
+ return ret;
+ *val = ret << 8;
+ return 0;
+ }
+
+ ret = i2c_smbus_read_word_swapped(client, reg);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return 0;
+}
+
+static int tmp108_i2c_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct i2c_client *client = context;
+ struct tmp108 *tmp108 = i2c_get_clientdata(client);
+
+ if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
+ return i2c_smbus_write_byte_data(client, reg, val >> 8);
+ return i2c_smbus_write_word_swapped(client, reg, val);
+}
+
+static const struct regmap_bus tmp108_i2c_regmap_bus = {
+ .reg_read = tmp108_i2c_reg_read,
+ .reg_write = tmp108_i2c_reg_write,
+};
+
+static int tmp108_i3c_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct i3c_device *i3cdev = context;
+ struct tmp108 *tmp108 = i3cdev_get_drvdata(i3cdev);
+ u8 reg_buf[1], val_buf[2];
+ struct i3c_xfer xfers[] = {
+ {
+ .rnw = false,
+ .len = 1,
+ .data.out = reg_buf,
+ },
+ {
+ .rnw = true,
+ .len = 2,
+ .data.in = val_buf,
+ },
+ };
+ int ret;
+
+ reg_buf[0] = reg;
+
+ if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
+ xfers[1].len--;
+
+ ret = i3c_device_do_xfers(i3cdev, xfers, 2, I3C_SDR);
+ if (ret < 0)
+ return ret;
+
+ *val = val_buf[0] << 8;
+ if (reg != TMP108_REG_CONF || tmp108->config_reg_16bits)
+ *val |= val_buf[1];
+
+ return 0;
+}
+
+static int tmp108_i3c_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct i3c_device *i3cdev = context;
+ struct tmp108 *tmp108 = i3cdev_get_drvdata(i3cdev);
+ u8 val_buf[3];
+ struct i3c_xfer xfers[] = {
+ {
+ .rnw = false,
+ .len = 3,
+ .data.out = val_buf,
+ },
+ };
+
+ val_buf[0] = reg;
+ val_buf[1] = (val >> 8) & 0xff;
+
+ if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
+ xfers[0].len--;
+ else
+ val_buf[2] = val & 0xff;
+
+ return i3c_device_do_xfers(i3cdev, xfers, 1, I3C_SDR);
+}
+
+static const struct regmap_bus tmp108_i3c_regmap_bus = {
+ .reg_read = tmp108_i3c_reg_read,
+ .reg_write = tmp108_i3c_reg_write,
+};
+
static const struct regmap_config tmp108_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
@@ -323,7 +428,8 @@ static const struct regmap_config tmp108_regmap_config = {
.use_single_write = true,
};
-static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name)
+static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name,
+ enum tmp108_hw_id hw_id)
{
struct device *hwmon_dev;
struct tmp108 *tmp108;
@@ -340,6 +446,15 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
dev_set_drvdata(dev, tmp108);
tmp108->regmap = regmap;
+ tmp108->hw_id = hw_id;
+ tmp108->config_reg_16bits = (hw_id == P3T1035_ID) ? false : true;
+ if (hw_id == P3T1035_ID) {
+ tmp108->sample_times = p3t1035_sample_times;
+ tmp108->n_sample_times = ARRAY_SIZE(p3t1035_sample_times);
+ } else {
+ tmp108->sample_times = tmp108_sample_times;
+ tmp108->n_sample_times = ARRAY_SIZE(tmp108_sample_times);
+ }
err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config);
if (err < 0) {
@@ -351,7 +466,6 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
/* Only continuous mode is supported. */
config &= ~TMP108_CONF_MODE_MASK;
config |= TMP108_MODE_CONTINUOUS;
-
/* Only comparator mode is supported. */
config &= ~TMP108_CONF_TM;
@@ -384,17 +498,20 @@ static int tmp108_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct regmap *regmap;
+ enum tmp108_hw_id hw_id;
if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_WORD_DATA))
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
return dev_err_probe(dev, -ENODEV,
"adapter doesn't support SMBus word transactions\n");
- regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config);
+ regmap = devm_regmap_init(dev, &tmp108_i2c_regmap_bus, client, &tmp108_regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed");
- return tmp108_common_probe(dev, regmap, client->name);
+ hw_id = (unsigned long)i2c_get_match_data(client);
+
+ return tmp108_common_probe(dev, regmap, client->name, hw_id);
}
static int tmp108_suspend(struct device *dev)
@@ -420,15 +537,17 @@ static int tmp108_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume);
static const struct i2c_device_id tmp108_i2c_ids[] = {
- { "p3t1085" },
- { "tmp108" },
- { }
+ { "p3t1035", P3T1035_ID },
+ { "p3t1085", P3T1085_ID },
+ { "tmp108", TMP108_ID },
+ {}
};
MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids);
static const struct of_device_id tmp108_of_ids[] = {
- { .compatible = "nxp,p3t1085", },
- { .compatible = "ti,tmp108", },
+ { .compatible = "nxp,p3t1035", .data = (void *)(uintptr_t)P3T1035_ID },
+ { .compatible = "nxp,p3t1085", .data = (void *)(uintptr_t)P3T1085_ID },
+ { .compatible = "ti,tmp108", .data = (void *)(uintptr_t)TMP108_ID },
{}
};
MODULE_DEVICE_TABLE(of, tmp108_of_ids);
@@ -444,7 +563,8 @@ static struct i2c_driver tmp108_driver = {
};
static const struct i3c_device_id p3t1085_i3c_ids[] = {
- I3C_DEVICE(0x011b, 0x1529, NULL),
+ I3C_DEVICE(0x011B, 0x1529, (void *)P3T1085_ID),
+ I3C_DEVICE(0x011B, 0x152B, (void *)P3T1035_ID),
{}
};
MODULE_DEVICE_TABLE(i3c, p3t1085_i3c_ids);
@@ -453,13 +573,16 @@ static int p3t1085_i3c_probe(struct i3c_device *i3cdev)
{
struct device *dev = i3cdev_to_dev(i3cdev);
struct regmap *regmap;
+ const struct i3c_device_id *id;
- regmap = devm_regmap_init_i3c(i3cdev, &tmp108_regmap_config);
+ regmap = devm_regmap_init(dev, &tmp108_i3c_regmap_bus, i3cdev, &tmp108_regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to register i3c regmap\n");
- return tmp108_common_probe(dev, regmap, "p3t1085_i3c");
+ id = i3c_device_match_id(i3cdev, p3t1085_i3c_ids);
+
+ return tmp108_common_probe(dev, regmap, "p3t1085_i3c", (unsigned long)id->data);
}
static struct i3c_driver p3t1085_driver = {
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 3/3] hwmon: (tmp108) Add P3T1035 and P3T2030 support
2026-01-16 11:35 [PATCH v4 1/3] dt-bindings: hwmon: ti,tmp108: Add P3T1035,P3T2030 Mayank Mahajan
2026-01-16 11:35 ` [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030 Mayank Mahajan
@ 2026-01-16 11:35 ` Mayank Mahajan
2026-01-16 14:38 ` [PATCH v4 1/3] dt-bindings: hwmon: ti,tmp108: Add P3T1035,P3T2030 Krzysztof Kozlowski
2 siblings, 0 replies; 9+ messages in thread
From: Mayank Mahajan @ 2026-01-16 11:35 UTC (permalink / raw)
To: linux, corbet, robh, krzk+dt, conor+dt, linux-hwmon, devicetree,
linux-doc, linux-kernel
Cc: priyanka.jain, vikash.bansal, Mayank Mahajan
Update the hwmon driver documentation for sensors: P3T1035 and P3T2030.
Signed-off-by: Mayank Mahajan <mayankmahajan.x@nxp.com>
---
V1 -> V2:
- No changes in v2.
V2 -> V3:
- No changes in v3.
V3 -> V4:
- No changes in v4.
Documentation/hwmon/tmp108.rst | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/Documentation/hwmon/tmp108.rst b/Documentation/hwmon/tmp108.rst
index bc4941d98268..c218ea333dd6 100644
--- a/Documentation/hwmon/tmp108.rst
+++ b/Documentation/hwmon/tmp108.rst
@@ -3,6 +3,15 @@ Kernel driver tmp108
Supported chips:
+ * NXP P3T1035
+
+ Prefix: 'p3t1035'
+
+ Addresses scanned: none
+
+ Datasheet: https://www.nxp.com/docs/en/data-sheet/P3T1035XUK_P3T2030XUK.pdf
+
+
* NXP P3T1085
Prefix: 'p3t1085'
@@ -11,6 +20,14 @@ Supported chips:
Datasheet: https://www.nxp.com/docs/en/data-sheet/P3T1085UK.pdf
+ * NXP P3T2030
+
+ Prefix: 'p3t2030'
+
+ Addresses scanned: none
+
+ Datasheet: https://www.nxp.com/docs/en/data-sheet/P3T1035XUK_P3T2030XUK.pdf
+
* Texas Instruments TMP108
Prefix: 'tmp108'
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] dt-bindings: hwmon: ti,tmp108: Add P3T1035,P3T2030
2026-01-16 11:35 [PATCH v4 1/3] dt-bindings: hwmon: ti,tmp108: Add P3T1035,P3T2030 Mayank Mahajan
2026-01-16 11:35 ` [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030 Mayank Mahajan
2026-01-16 11:35 ` [PATCH v4 3/3] hwmon: (tmp108) Add P3T1035 and P3T2030 support Mayank Mahajan
@ 2026-01-16 14:38 ` Krzysztof Kozlowski
2 siblings, 0 replies; 9+ messages in thread
From: Krzysztof Kozlowski @ 2026-01-16 14:38 UTC (permalink / raw)
To: Mayank Mahajan, linux, corbet, robh, krzk+dt, conor+dt,
linux-hwmon, devicetree, linux-doc, linux-kernel
Cc: priyanka.jain, vikash.bansal
On 16/01/2026 12:35, Mayank Mahajan wrote:
> Document the NXP P3T1035 and P3T2030 compatibles in TMP108.
>
> Signed-off-by: Mayank Mahajan <mayankmahajan.x@nxp.com>
Read carefully replies you receive.
<form letter>
This is a friendly reminder during the review process.
It looks like you received a tag and forgot to add it.
If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions
of patchset, under or above your Signed-off-by tag, unless patch changed
significantly (e.g. new properties added to the DT bindings). Tag is
"received", when provided in a message replied to you on the mailing
list. Tools like b4 can help here. However, there's no need to repost
patches *only* to add the tags. The upstream maintainer will do that for
tags received on the version they apply.
Please read:
https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
If a tag was not added on purpose, please state why and what changed.
</form letter>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030
2026-01-16 11:35 ` [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030 Mayank Mahajan
@ 2026-01-16 21:37 ` kernel test robot
2026-01-16 22:28 ` Frank Li
1 sibling, 0 replies; 9+ messages in thread
From: kernel test robot @ 2026-01-16 21:37 UTC (permalink / raw)
To: Mayank Mahajan, linux, corbet, robh, krzk+dt, conor+dt,
linux-hwmon, devicetree, linux-doc, linux-kernel
Cc: llvm, oe-kbuild-all, priyanka.jain, vikash.bansal, Mayank Mahajan
Hi Mayank,
kernel test robot noticed the following build errors:
[auto build test ERROR on 983d014aafb14ee5e4915465bf8948e8f3a723b5]
url: https://github.com/intel-lab-lkp/linux/commits/Mayank-Mahajan/hwmon-tmp108-Add-support-for-P3T1035-and-P3T2030/20260116-193800
base: 983d014aafb14ee5e4915465bf8948e8f3a723b5
patch link: https://lore.kernel.org/r/20260116113554.986-2-mayankmahajan.x%40nxp.com
patch subject: [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030
config: i386-buildonly-randconfig-004-20260117 (https://download.01.org/0day-ci/archive/20260117/202601170516.uQw9DKHB-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260117/202601170516.uQw9DKHB-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601170516.uQw9DKHB-lkp@intel.com/
All errors (new ones prefixed by >>):
>> drivers/hwmon/tmp108.c:123:33: error: call to undeclared function 'FIELD_GET'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
123 | *temp = tmp108->sample_times[FIELD_GET(TMP108_CONF_CONVRATE_FLD, regval)];
| ^
>> drivers/hwmon/tmp108.c:210:9: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
210 | FIELD_PREP(TMP108_CONF_CONVRATE_FLD, index));
| ^
2 errors generated.
vim +/FIELD_GET +123 drivers/hwmon/tmp108.c
109
110 static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
111 u32 attr, int channel, long *temp)
112 {
113 struct tmp108 *tmp108 = dev_get_drvdata(dev);
114 unsigned int regval;
115 int err, hyst;
116
117 if (type == hwmon_chip) {
118 if (attr == hwmon_chip_update_interval) {
119 err = regmap_read(tmp108->regmap, TMP108_REG_CONF,
120 ®val);
121 if (err < 0)
122 return err;
> 123 *temp = tmp108->sample_times[FIELD_GET(TMP108_CONF_CONVRATE_FLD, regval)];
124 return 0;
125 }
126 return -EOPNOTSUPP;
127 }
128
129 switch (attr) {
130 case hwmon_temp_input:
131 /* Is it too early to return a conversion ? */
132 if (time_before(jiffies, tmp108->ready_time)) {
133 dev_dbg(dev, "%s: Conversion not ready yet..\n",
134 __func__);
135 return -EAGAIN;
136 }
137 err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, ®val);
138 if (err < 0)
139 return err;
140 *temp = tmp108_temp_reg_to_mC(regval);
141 break;
142 case hwmon_temp_min:
143 case hwmon_temp_max:
144 err = regmap_read(tmp108->regmap, attr == hwmon_temp_min ?
145 TMP108_REG_TLOW : TMP108_REG_THIGH, ®val);
146 if (err < 0)
147 return err;
148 *temp = tmp108_temp_reg_to_mC(regval);
149 break;
150 case hwmon_temp_min_alarm:
151 case hwmon_temp_max_alarm:
152 err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val);
153 if (err < 0)
154 return err;
155 *temp = !!(regval & (attr == hwmon_temp_min_alarm ?
156 TMP108_CONF_FL : TMP108_CONF_FH));
157 break;
158 case hwmon_temp_min_hyst:
159 case hwmon_temp_max_hyst:
160 err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val);
161 if (err < 0)
162 return err;
163 switch (regval & TMP108_CONF_HYSTERESIS_MASK) {
164 case TMP108_HYSTERESIS_0C:
165 default:
166 hyst = 0;
167 break;
168 case TMP108_HYSTERESIS_1C:
169 hyst = 1000;
170 break;
171 case TMP108_HYSTERESIS_2C:
172 hyst = 2000;
173 break;
174 case TMP108_HYSTERESIS_4C:
175 hyst = 4000;
176 break;
177 }
178 err = regmap_read(tmp108->regmap, attr == hwmon_temp_min_hyst ?
179 TMP108_REG_TLOW : TMP108_REG_THIGH, ®val);
180 if (err < 0)
181 return err;
182 *temp = tmp108_temp_reg_to_mC(regval);
183 if (attr == hwmon_temp_min_hyst)
184 *temp += hyst;
185 else
186 *temp -= hyst;
187 break;
188 default:
189 return -EOPNOTSUPP;
190 }
191
192 return 0;
193 }
194
195 static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
196 u32 attr, int channel, long temp)
197 {
198 struct tmp108 *tmp108 = dev_get_drvdata(dev);
199 u32 regval, mask;
200 u8 index;
201 int err;
202
203 if (type == hwmon_chip) {
204 if (attr == hwmon_chip_update_interval) {
205 index = find_closest_descending(temp, tmp108->sample_times,
206 tmp108->n_sample_times);
207 return regmap_update_bits(tmp108->regmap,
208 TMP108_REG_CONF,
209 TMP108_CONF_CONVRATE_MASK,
> 210 FIELD_PREP(TMP108_CONF_CONVRATE_FLD, index));
211 }
212 return -EOPNOTSUPP;
213 }
214
215 switch (attr) {
216 case hwmon_temp_min:
217 case hwmon_temp_max:
218 temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC);
219 return regmap_write(tmp108->regmap,
220 attr == hwmon_temp_min ?
221 TMP108_REG_TLOW : TMP108_REG_THIGH,
222 tmp108_mC_to_temp_reg(temp));
223 case hwmon_temp_min_hyst:
224 case hwmon_temp_max_hyst:
225 temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC);
226 err = regmap_read(tmp108->regmap,
227 attr == hwmon_temp_min_hyst ?
228 TMP108_REG_TLOW : TMP108_REG_THIGH,
229 ®val);
230 if (err < 0)
231 return err;
232 if (attr == hwmon_temp_min_hyst)
233 temp -= tmp108_temp_reg_to_mC(regval);
234 else
235 temp = tmp108_temp_reg_to_mC(regval) - temp;
236 if (temp < 500)
237 mask = TMP108_HYSTERESIS_0C;
238 else if (temp < 1500)
239 mask = TMP108_HYSTERESIS_1C;
240 else if (temp < 3000)
241 mask = TMP108_HYSTERESIS_2C;
242 else
243 mask = TMP108_HYSTERESIS_4C;
244 return regmap_update_bits(tmp108->regmap, TMP108_REG_CONF,
245 TMP108_CONF_HYSTERESIS_MASK, mask);
246 default:
247 return -EOPNOTSUPP;
248 }
249 }
250
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030
2026-01-16 11:35 ` [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030 Mayank Mahajan
2026-01-16 21:37 ` kernel test robot
@ 2026-01-16 22:28 ` Frank Li
2026-01-17 0:36 ` Guenter Roeck
1 sibling, 1 reply; 9+ messages in thread
From: Frank Li @ 2026-01-16 22:28 UTC (permalink / raw)
To: Mayank Mahajan
Cc: linux, corbet, robh, krzk+dt, conor+dt, linux-hwmon, devicetree,
linux-doc, linux-kernel, priyanka.jain, vikash.bansal
On Fri, Jan 16, 2026 at 05:05:53PM +0530, Mayank Mahajan wrote:
> Add support for the P3T1035 & P3T2030 temperature sensor. While mostly
> compatible with the TMP108, P3T1035 uses an 8-bit configuration register
> instead of the 16-bit layout used by TMP108. Updated driver to handle
> this difference during configuration read/write.
>
> Signed-off-by: Mayank Mahajan <mayankmahajan.x@nxp.com>
> ---
> V1 -> V2:
> - Disabled hysteresis in is_visible function for P3T1035.
> - Added tables for conversion rate similar to the LM75 driver.
> - Implemented different bus access depending on the chip being used.
> - Removed regmap for 8 bits; now we are using one regmap as before.
> - Added read and write functions for i2c and i3c for use with regmap.
> - Mapped the 8-bit configuration register to a 16 bit value for P3T1035.
> V2 -> V3:
> - Remove changes not relevant to adding a new device in the driver.
> - Address warnings due to incorrect usage of casting operations.
> - Remove the usage of P3T2030 as it's functionally identical to P3T1035.
> V3 -> V4:
> - Add GENMASK for getting mask for conversion rates.
> - Add static arrays for containing sample times for different sensors.
> - Remove redundant code such as checking for NULL pointer in probe.
> - Improve readability by removing double negation.
> - Remove type cast where not required; make reg_buf & val_buf local.
>
> drivers/hwmon/Kconfig | 2 +-
> drivers/hwmon/tmp108.c | 203 +++++++++++++++++++++++++++++++++--------
> 2 files changed, 164 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 157678b821fc..31969bddc812 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -2398,7 +2398,7 @@ config SENSORS_TMP108
> select REGMAP_I3C if I3C
> help
> If you say yes here you get support for Texas Instruments TMP108
> - sensor chips and NXP P3T1085.
> + sensor chips, NXP temperature sensors P3T1035, P3T1085 and P3T2030.
>
> This driver can also be built as a module. If so, the module
> will be called tmp108.
> diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c
> index 60a237cbedbc..d308e2aed18a 100644
> --- a/drivers/hwmon/tmp108.c
> +++ b/drivers/hwmon/tmp108.c
> @@ -17,9 +17,16 @@
> #include <linux/regmap.h>
> #include <linux/regulator/consumer.h>
> #include <linux/slab.h>
> +#include <linux/util_macros.h>
>
> #define DRIVER_NAME "tmp108"
>
> +enum tmp108_hw_id {
> + P3T1035_ID, /* For sensors p3t1035 and p3t2030 */
> + P3T1085_ID,
> + TMP108_ID,
> +};
> +
> #define TMP108_REG_TEMP 0x00
> #define TMP108_REG_CONF 0x01
> #define TMP108_REG_TLOW 0x02
> @@ -61,6 +68,7 @@
> #define TMP108_CONVRATE_1HZ TMP108_CONF_CR0 /* Default */
> #define TMP108_CONVRATE_4HZ TMP108_CONF_CR1
> #define TMP108_CONVRATE_16HZ (TMP108_CONF_CR0|TMP108_CONF_CR1)
> +#define TMP108_CONVRATE_SHIFT 13
>
> #define TMP108_CONF_HYSTERESIS_MASK (TMP108_CONF_HYS0|TMP108_CONF_HYS1)
> #define TMP108_HYSTERESIS_0C 0x0000
> @@ -70,12 +78,23 @@
>
> #define TMP108_CONVERSION_TIME_MS 30 /* in milli-seconds */
>
> +#define TMP108_CONF_CR0_POS 13
> +#define TMP108_CONF_CR1_POS 14
> +#define TMP108_CONF_CONVRATE_FLD GENMASK(TMP108_CONF_CR1_POS, TMP108_CONF_CR0_POS)
> +
> struct tmp108 {
> - struct regmap *regmap;
> - u16 orig_config;
> - unsigned long ready_time;
> + struct regmap *regmap;
> + u16 orig_config;
> + unsigned long ready_time;
don't mix format change in this patch.
Now prefer orignial format, just one space between type and field.
> + enum tmp108_hw_id hw_id;
> + bool config_reg_16bits;
> + ushort *sample_times;
> + size_t n_sample_times;
> };
>
> +ushort p3t1035_sample_times[] = {4000, 1000, 250, 125};
> +ushort tmp108_sample_times[] = {4000, 1000, 250, 63};
> +
> /* convert 12-bit TMP108 register value to milliCelsius */
> static inline int tmp108_temp_reg_to_mC(s16 val)
> {
> @@ -101,21 +120,7 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
> ®val);
> if (err < 0)
> return err;
> - switch (regval & TMP108_CONF_CONVRATE_MASK) {
> - case TMP108_CONVRATE_0P25HZ:
> - default:
> - *temp = 4000;
> - break;
> - case TMP108_CONVRATE_1HZ:
> - *temp = 1000;
> - break;
> - case TMP108_CONVRATE_4HZ:
> - *temp = 250;
> - break;
> - case TMP108_CONVRATE_16HZ:
> - *temp = 63;
> - break;
> - }
> + *temp = tmp108->sample_times[FIELD_GET(TMP108_CONF_CONVRATE_FLD, regval)];
This code optimation need seperate patch.
> return 0;
> }
> return -EOPNOTSUPP;
> @@ -192,22 +197,17 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
> {
> struct tmp108 *tmp108 = dev_get_drvdata(dev);
> u32 regval, mask;
> + u8 index;
> int err;
>
> if (type == hwmon_chip) {
> if (attr == hwmon_chip_update_interval) {
> - if (temp < 156)
> - mask = TMP108_CONVRATE_16HZ;
> - else if (temp < 625)
> - mask = TMP108_CONVRATE_4HZ;
> - else if (temp < 2500)
> - mask = TMP108_CONVRATE_1HZ;
> - else
> - mask = TMP108_CONVRATE_0P25HZ;
> + index = find_closest_descending(temp, tmp108->sample_times,
> + tmp108->n_sample_times);
Need seperate patch for the code cleanup.
> return regmap_update_bits(tmp108->regmap,
> TMP108_REG_CONF,
> TMP108_CONF_CONVRATE_MASK,
> - mask);
> + FIELD_PREP(TMP108_CONF_CONVRATE_FLD, index));
> }
> return -EOPNOTSUPP;
> }
> @@ -251,6 +251,8 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
> static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
> u32 attr, int channel)
> {
> + const struct tmp108 *tmp108 = data;
> +
> if (type == hwmon_chip && attr == hwmon_chip_update_interval)
> return 0644;
>
> @@ -264,8 +266,11 @@ static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
> return 0444;
> case hwmon_temp_min:
> case hwmon_temp_max:
> + return 0644;
> case hwmon_temp_min_hyst:
> case hwmon_temp_max_hyst:
> + if (tmp108->hw_id == P3T1035_ID)
> + return 0;
> return 0644;
> default:
> return 0;
> @@ -311,6 +316,106 @@ static bool tmp108_is_volatile_reg(struct device *dev, unsigned int reg)
> return reg == TMP108_REG_TEMP || reg == TMP108_REG_CONF;
> }
>
> +static int tmp108_i2c_reg_read(void *context, unsigned int reg, unsigned int *val)
> +{
> + struct i2c_client *client = context;
> + struct tmp108 *tmp108 = i2c_get_clientdata(client);
> + int ret;
> +
> + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits) {
> + ret = i2c_smbus_read_byte_data(client, TMP108_REG_CONF);
> + if (ret < 0)
> + return ret;
> + *val = ret << 8;
> + return 0;
> + }
> +
> + ret = i2c_smbus_read_word_swapped(client, reg);
> + if (ret < 0)
> + return ret;
> + *val = ret;
> + return 0;
> +}
> +
> +static int tmp108_i2c_reg_write(void *context, unsigned int reg, unsigned int val)
> +{
> + struct i2c_client *client = context;
> + struct tmp108 *tmp108 = i2c_get_clientdata(client);
> +
> + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
> + return i2c_smbus_write_byte_data(client, reg, val >> 8);
> + return i2c_smbus_write_word_swapped(client, reg, val);
> +}
> +
> +static const struct regmap_bus tmp108_i2c_regmap_bus = {
> + .reg_read = tmp108_i2c_reg_read,
> + .reg_write = tmp108_i2c_reg_write,
> +};
> +
> +static int tmp108_i3c_reg_read(void *context, unsigned int reg, unsigned int *val)
> +{
> + struct i3c_device *i3cdev = context;
> + struct tmp108 *tmp108 = i3cdev_get_drvdata(i3cdev);
> + u8 reg_buf[1], val_buf[2];
> + struct i3c_xfer xfers[] = {
> + {
> + .rnw = false,
> + .len = 1,
> + .data.out = reg_buf,
> + },
> + {
> + .rnw = true,
> + .len = 2,
> + .data.in = val_buf,
> + },
> + };
> + int ret;
> +
> + reg_buf[0] = reg;
> +
> + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
> + xfers[1].len--;
> +
> + ret = i3c_device_do_xfers(i3cdev, xfers, 2, I3C_SDR);
> + if (ret < 0)
> + return ret;
> +
> + *val = val_buf[0] << 8;
> + if (reg != TMP108_REG_CONF || tmp108->config_reg_16bits)
> + *val |= val_buf[1];
> +
> + return 0;
> +}
> +
> +static int tmp108_i3c_reg_write(void *context, unsigned int reg, unsigned int val)
> +{
> + struct i3c_device *i3cdev = context;
> + struct tmp108 *tmp108 = i3cdev_get_drvdata(i3cdev);
> + u8 val_buf[3];
> + struct i3c_xfer xfers[] = {
> + {
> + .rnw = false,
> + .len = 3,
> + .data.out = val_buf,
> + },
> + };
> +
> + val_buf[0] = reg;
> + val_buf[1] = (val >> 8) & 0xff;
> +
> + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
> + xfers[0].len--;
> + else
> + val_buf[2] = val & 0xff;
> +
> + return i3c_device_do_xfers(i3cdev, xfers, 1, I3C_SDR);
> +}
> +
> +static const struct regmap_bus tmp108_i3c_regmap_bus = {
> + .reg_read = tmp108_i3c_reg_read,
> + .reg_write = tmp108_i3c_reg_write,
> +};
> +
> static const struct regmap_config tmp108_regmap_config = {
> .reg_bits = 8,
> .val_bits = 16,
> @@ -323,7 +428,8 @@ static const struct regmap_config tmp108_regmap_config = {
> .use_single_write = true,
> };
>
> -static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name)
> +static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name,
> + enum tmp108_hw_id hw_id)
> {
> struct device *hwmon_dev;
> struct tmp108 *tmp108;
> @@ -340,6 +446,15 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
>
> dev_set_drvdata(dev, tmp108);
> tmp108->regmap = regmap;
> + tmp108->hw_id = hw_id;
> + tmp108->config_reg_16bits = (hw_id == P3T1035_ID) ? false : true;
> + if (hw_id == P3T1035_ID) {
> + tmp108->sample_times = p3t1035_sample_times;
> + tmp108->n_sample_times = ARRAY_SIZE(p3t1035_sample_times);
> + } else {
> + tmp108->sample_times = tmp108_sample_times;
> + tmp108->n_sample_times = ARRAY_SIZE(tmp108_sample_times);
> + }
>
> err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config);
> if (err < 0) {
> @@ -351,7 +466,6 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
> /* Only continuous mode is supported. */
> config &= ~TMP108_CONF_MODE_MASK;
> config |= TMP108_MODE_CONTINUOUS;
> -
> /* Only comparator mode is supported. */
> config &= ~TMP108_CONF_TM;
>
> @@ -384,17 +498,20 @@ static int tmp108_probe(struct i2c_client *client)
> {
> struct device *dev = &client->dev;
> struct regmap *regmap;
> + enum tmp108_hw_id hw_id;
>
> if (!i2c_check_functionality(client->adapter,
> - I2C_FUNC_SMBUS_WORD_DATA))
> + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
> return dev_err_probe(dev, -ENODEV,
> "adapter doesn't support SMBus word transactions\n");
>
> - regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config);
> + regmap = devm_regmap_init(dev, &tmp108_i2c_regmap_bus, client, &tmp108_regmap_config);
> if (IS_ERR(regmap))
> return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed");
>
> - return tmp108_common_probe(dev, regmap, client->name);
> + hw_id = (unsigned long)i2c_get_match_data(client);
> +
> + return tmp108_common_probe(dev, regmap, client->name, hw_id);
> }
>
> static int tmp108_suspend(struct device *dev)
> @@ -420,15 +537,17 @@ static int tmp108_resume(struct device *dev)
> static DEFINE_SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume);
>
> static const struct i2c_device_id tmp108_i2c_ids[] = {
> - { "p3t1085" },
> - { "tmp108" },
> - { }
> + { "p3t1035", P3T1035_ID },
> + { "p3t1085", P3T1085_ID },
> + { "tmp108", TMP108_ID },
> + {}
> };
> MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids);
>
> static const struct of_device_id tmp108_of_ids[] = {
> - { .compatible = "nxp,p3t1085", },
> - { .compatible = "ti,tmp108", },
> + { .compatible = "nxp,p3t1035", .data = (void *)(uintptr_t)P3T1035_ID },
> + { .compatible = "nxp,p3t1085", .data = (void *)(uintptr_t)P3T1085_ID },
> + { .compatible = "ti,tmp108", .data = (void *)(uintptr_t)TMP108_ID },
Do not use device ID, define struct drvdata
struct tmp108_drvdata
{
.samples = p3t1035_sample_times;
.reg_width = 16,
...
}
Frank
> {}
> };
> MODULE_DEVICE_TABLE(of, tmp108_of_ids);
> @@ -444,7 +563,8 @@ static struct i2c_driver tmp108_driver = {
> };
>
> static const struct i3c_device_id p3t1085_i3c_ids[] = {
> - I3C_DEVICE(0x011b, 0x1529, NULL),
> + I3C_DEVICE(0x011B, 0x1529, (void *)P3T1085_ID),
> + I3C_DEVICE(0x011B, 0x152B, (void *)P3T1035_ID),
> {}
> };
> MODULE_DEVICE_TABLE(i3c, p3t1085_i3c_ids);
> @@ -453,13 +573,16 @@ static int p3t1085_i3c_probe(struct i3c_device *i3cdev)
> {
> struct device *dev = i3cdev_to_dev(i3cdev);
> struct regmap *regmap;
> + const struct i3c_device_id *id;
>
> - regmap = devm_regmap_init_i3c(i3cdev, &tmp108_regmap_config);
> + regmap = devm_regmap_init(dev, &tmp108_i3c_regmap_bus, i3cdev, &tmp108_regmap_config);
> if (IS_ERR(regmap))
> return dev_err_probe(dev, PTR_ERR(regmap),
> "Failed to register i3c regmap\n");
>
> - return tmp108_common_probe(dev, regmap, "p3t1085_i3c");
> + id = i3c_device_match_id(i3cdev, p3t1085_i3c_ids);
> +
> + return tmp108_common_probe(dev, regmap, "p3t1085_i3c", (unsigned long)id->data);
> }
>
> static struct i3c_driver p3t1085_driver = {
> --
> 2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030
2026-01-16 22:28 ` Frank Li
@ 2026-01-17 0:36 ` Guenter Roeck
2026-01-18 17:30 ` Frank Li
0 siblings, 1 reply; 9+ messages in thread
From: Guenter Roeck @ 2026-01-17 0:36 UTC (permalink / raw)
To: Frank Li, Mayank Mahajan
Cc: corbet, robh, krzk+dt, conor+dt, linux-hwmon, devicetree,
linux-doc, linux-kernel, priyanka.jain, vikash.bansal
On 1/16/26 14:28, Frank Li wrote:
> On Fri, Jan 16, 2026 at 05:05:53PM +0530, Mayank Mahajan wrote:
>> Add support for the P3T1035 & P3T2030 temperature sensor. While mostly
>> compatible with the TMP108, P3T1035 uses an 8-bit configuration register
>> instead of the 16-bit layout used by TMP108. Updated driver to handle
>> this difference during configuration read/write.
>>
>> Signed-off-by: Mayank Mahajan <mayankmahajan.x@nxp.com>
>> ---
>> V1 -> V2:
>> - Disabled hysteresis in is_visible function for P3T1035.
>> - Added tables for conversion rate similar to the LM75 driver.
>> - Implemented different bus access depending on the chip being used.
>> - Removed regmap for 8 bits; now we are using one regmap as before.
>> - Added read and write functions for i2c and i3c for use with regmap.
>> - Mapped the 8-bit configuration register to a 16 bit value for P3T1035.
>> V2 -> V3:
>> - Remove changes not relevant to adding a new device in the driver.
>> - Address warnings due to incorrect usage of casting operations.
>> - Remove the usage of P3T2030 as it's functionally identical to P3T1035.
>> V3 -> V4:
>> - Add GENMASK for getting mask for conversion rates.
>> - Add static arrays for containing sample times for different sensors.
>> - Remove redundant code such as checking for NULL pointer in probe.
>> - Improve readability by removing double negation.
>> - Remove type cast where not required; make reg_buf & val_buf local.
>>
>> drivers/hwmon/Kconfig | 2 +-
>> drivers/hwmon/tmp108.c | 203 +++++++++++++++++++++++++++++++++--------
>> 2 files changed, 164 insertions(+), 41 deletions(-)
>>
>> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
>> index 157678b821fc..31969bddc812 100644
>> --- a/drivers/hwmon/Kconfig
>> +++ b/drivers/hwmon/Kconfig
>> @@ -2398,7 +2398,7 @@ config SENSORS_TMP108
>> select REGMAP_I3C if I3C
>> help
>> If you say yes here you get support for Texas Instruments TMP108
>> - sensor chips and NXP P3T1085.
>> + sensor chips, NXP temperature sensors P3T1035, P3T1085 and P3T2030.
>>
>> This driver can also be built as a module. If so, the module
>> will be called tmp108.
>> diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c
>> index 60a237cbedbc..d308e2aed18a 100644
>> --- a/drivers/hwmon/tmp108.c
>> +++ b/drivers/hwmon/tmp108.c
>> @@ -17,9 +17,16 @@
>> #include <linux/regmap.h>
>> #include <linux/regulator/consumer.h>
>> #include <linux/slab.h>
>> +#include <linux/util_macros.h>
>>
>> #define DRIVER_NAME "tmp108"
>>
>> +enum tmp108_hw_id {
>> + P3T1035_ID, /* For sensors p3t1035 and p3t2030 */
>> + P3T1085_ID,
>> + TMP108_ID,
>> +};
>> +
>> #define TMP108_REG_TEMP 0x00
>> #define TMP108_REG_CONF 0x01
>> #define TMP108_REG_TLOW 0x02
>> @@ -61,6 +68,7 @@
>> #define TMP108_CONVRATE_1HZ TMP108_CONF_CR0 /* Default */
>> #define TMP108_CONVRATE_4HZ TMP108_CONF_CR1
>> #define TMP108_CONVRATE_16HZ (TMP108_CONF_CR0|TMP108_CONF_CR1)
>> +#define TMP108_CONVRATE_SHIFT 13
>>
>> #define TMP108_CONF_HYSTERESIS_MASK (TMP108_CONF_HYS0|TMP108_CONF_HYS1)
>> #define TMP108_HYSTERESIS_0C 0x0000
>> @@ -70,12 +78,23 @@
>>
>> #define TMP108_CONVERSION_TIME_MS 30 /* in milli-seconds */
>>
>> +#define TMP108_CONF_CR0_POS 13
>> +#define TMP108_CONF_CR1_POS 14
>> +#define TMP108_CONF_CONVRATE_FLD GENMASK(TMP108_CONF_CR1_POS, TMP108_CONF_CR0_POS)
>> +
>> struct tmp108 {
>> - struct regmap *regmap;
>> - u16 orig_config;
>> - unsigned long ready_time;
>> + struct regmap *regmap;
>> + u16 orig_config;
>> + unsigned long ready_time;
>
> don't mix format change in this patch.
> Now prefer orignial format, just one space between type and field.
>
>> + enum tmp108_hw_id hw_id;
>> + bool config_reg_16bits;
>> + ushort *sample_times;
>> + size_t n_sample_times;
>> };
>>
>> +ushort p3t1035_sample_times[] = {4000, 1000, 250, 125};
>> +ushort tmp108_sample_times[] = {4000, 1000, 250, 63};
>> +
>> /* convert 12-bit TMP108 register value to milliCelsius */
>> static inline int tmp108_temp_reg_to_mC(s16 val)
>> {
>> @@ -101,21 +120,7 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
>> ®val);
>> if (err < 0)
>> return err;
>> - switch (regval & TMP108_CONF_CONVRATE_MASK) {
>> - case TMP108_CONVRATE_0P25HZ:
>> - default:
>> - *temp = 4000;
>> - break;
>> - case TMP108_CONVRATE_1HZ:
>> - *temp = 1000;
>> - break;
>> - case TMP108_CONVRATE_4HZ:
>> - *temp = 250;
>> - break;
>> - case TMP108_CONVRATE_16HZ:
>> - *temp = 63;
>> - break;
>> - }
>> + *temp = tmp108->sample_times[FIELD_GET(TMP108_CONF_CONVRATE_FLD, regval)];
>
> This code optimation need seperate patch.
>
No, There are now two ranges, not just one.
>> return 0;
>> }
>> return -EOPNOTSUPP;
>> @@ -192,22 +197,17 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
>> {
>> struct tmp108 *tmp108 = dev_get_drvdata(dev);
>> u32 regval, mask;
>> + u8 index;
>> int err;
>>
>> if (type == hwmon_chip) {
>> if (attr == hwmon_chip_update_interval) {
>> - if (temp < 156)
>> - mask = TMP108_CONVRATE_16HZ;
>> - else if (temp < 625)
>> - mask = TMP108_CONVRATE_4HZ;
>> - else if (temp < 2500)
>> - mask = TMP108_CONVRATE_1HZ;
>> - else
>> - mask = TMP108_CONVRATE_0P25HZ;
>> + index = find_closest_descending(temp, tmp108->sample_times,
>> + tmp108->n_sample_times);
>
> Need seperate patch for the code cleanup.
>
No. There are now two ranges, not just one. That is not a code cleanup,
it is a change necessary to support multiple sets of ranges.
Guenter
>> return regmap_update_bits(tmp108->regmap,
>> TMP108_REG_CONF,
>> TMP108_CONF_CONVRATE_MASK,
>> - mask);
>> + FIELD_PREP(TMP108_CONF_CONVRATE_FLD, index));
>> }
>> return -EOPNOTSUPP;
>> }
>> @@ -251,6 +251,8 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
>> static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
>> u32 attr, int channel)
>> {
>> + const struct tmp108 *tmp108 = data;
>> +
>> if (type == hwmon_chip && attr == hwmon_chip_update_interval)
>> return 0644;
>>
>> @@ -264,8 +266,11 @@ static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
>> return 0444;
>> case hwmon_temp_min:
>> case hwmon_temp_max:
>> + return 0644;
>> case hwmon_temp_min_hyst:
>> case hwmon_temp_max_hyst:
>> + if (tmp108->hw_id == P3T1035_ID)
>> + return 0;
>> return 0644;
>> default:
>> return 0;
>> @@ -311,6 +316,106 @@ static bool tmp108_is_volatile_reg(struct device *dev, unsigned int reg)
>> return reg == TMP108_REG_TEMP || reg == TMP108_REG_CONF;
>> }
>>
>> +static int tmp108_i2c_reg_read(void *context, unsigned int reg, unsigned int *val)
>> +{
>> + struct i2c_client *client = context;
>> + struct tmp108 *tmp108 = i2c_get_clientdata(client);
>> + int ret;
>> +
>> + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits) {
>> + ret = i2c_smbus_read_byte_data(client, TMP108_REG_CONF);
>> + if (ret < 0)
>> + return ret;
>> + *val = ret << 8;
>> + return 0;
>> + }
>> +
>> + ret = i2c_smbus_read_word_swapped(client, reg);
>> + if (ret < 0)
>> + return ret;
>> + *val = ret;
>> + return 0;
>> +}
>> +
>> +static int tmp108_i2c_reg_write(void *context, unsigned int reg, unsigned int val)
>> +{
>> + struct i2c_client *client = context;
>> + struct tmp108 *tmp108 = i2c_get_clientdata(client);
>> +
>> + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
>> + return i2c_smbus_write_byte_data(client, reg, val >> 8);
>> + return i2c_smbus_write_word_swapped(client, reg, val);
>> +}
>> +
>> +static const struct regmap_bus tmp108_i2c_regmap_bus = {
>> + .reg_read = tmp108_i2c_reg_read,
>> + .reg_write = tmp108_i2c_reg_write,
>> +};
>> +
>> +static int tmp108_i3c_reg_read(void *context, unsigned int reg, unsigned int *val)
>> +{
>> + struct i3c_device *i3cdev = context;
>> + struct tmp108 *tmp108 = i3cdev_get_drvdata(i3cdev);
>> + u8 reg_buf[1], val_buf[2];
>> + struct i3c_xfer xfers[] = {
>> + {
>> + .rnw = false,
>> + .len = 1,
>> + .data.out = reg_buf,
>> + },
>> + {
>> + .rnw = true,
>> + .len = 2,
>> + .data.in = val_buf,
>> + },
>> + };
>> + int ret;
>> +
>> + reg_buf[0] = reg;
>> +
>> + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
>> + xfers[1].len--;
>> +
>> + ret = i3c_device_do_xfers(i3cdev, xfers, 2, I3C_SDR);
>> + if (ret < 0)
>> + return ret;
>> +
>> + *val = val_buf[0] << 8;
>> + if (reg != TMP108_REG_CONF || tmp108->config_reg_16bits)
>> + *val |= val_buf[1];
>> +
>> + return 0;
>> +}
>> +
>> +static int tmp108_i3c_reg_write(void *context, unsigned int reg, unsigned int val)
>> +{
>> + struct i3c_device *i3cdev = context;
>> + struct tmp108 *tmp108 = i3cdev_get_drvdata(i3cdev);
>> + u8 val_buf[3];
>> + struct i3c_xfer xfers[] = {
>> + {
>> + .rnw = false,
>> + .len = 3,
>> + .data.out = val_buf,
>> + },
>> + };
>> +
>> + val_buf[0] = reg;
>> + val_buf[1] = (val >> 8) & 0xff;
>> +
>> + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
>> + xfers[0].len--;
>> + else
>> + val_buf[2] = val & 0xff;
>> +
>> + return i3c_device_do_xfers(i3cdev, xfers, 1, I3C_SDR);
>> +}
>> +
>> +static const struct regmap_bus tmp108_i3c_regmap_bus = {
>> + .reg_read = tmp108_i3c_reg_read,
>> + .reg_write = tmp108_i3c_reg_write,
>> +};
>> +
>> static const struct regmap_config tmp108_regmap_config = {
>> .reg_bits = 8,
>> .val_bits = 16,
>> @@ -323,7 +428,8 @@ static const struct regmap_config tmp108_regmap_config = {
>> .use_single_write = true,
>> };
>>
>> -static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name)
>> +static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name,
>> + enum tmp108_hw_id hw_id)
>> {
>> struct device *hwmon_dev;
>> struct tmp108 *tmp108;
>> @@ -340,6 +446,15 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
>>
>> dev_set_drvdata(dev, tmp108);
>> tmp108->regmap = regmap;
>> + tmp108->hw_id = hw_id;
>> + tmp108->config_reg_16bits = (hw_id == P3T1035_ID) ? false : true;
>> + if (hw_id == P3T1035_ID) {
>> + tmp108->sample_times = p3t1035_sample_times;
>> + tmp108->n_sample_times = ARRAY_SIZE(p3t1035_sample_times);
>> + } else {
>> + tmp108->sample_times = tmp108_sample_times;
>> + tmp108->n_sample_times = ARRAY_SIZE(tmp108_sample_times);
>> + }
>>
>> err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config);
>> if (err < 0) {
>> @@ -351,7 +466,6 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
>> /* Only continuous mode is supported. */
>> config &= ~TMP108_CONF_MODE_MASK;
>> config |= TMP108_MODE_CONTINUOUS;
>> -
>> /* Only comparator mode is supported. */
>> config &= ~TMP108_CONF_TM;
>>
>> @@ -384,17 +498,20 @@ static int tmp108_probe(struct i2c_client *client)
>> {
>> struct device *dev = &client->dev;
>> struct regmap *regmap;
>> + enum tmp108_hw_id hw_id;
>>
>> if (!i2c_check_functionality(client->adapter,
>> - I2C_FUNC_SMBUS_WORD_DATA))
>> + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
>> return dev_err_probe(dev, -ENODEV,
>> "adapter doesn't support SMBus word transactions\n");
>>
>> - regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config);
>> + regmap = devm_regmap_init(dev, &tmp108_i2c_regmap_bus, client, &tmp108_regmap_config);
>> if (IS_ERR(regmap))
>> return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed");
>>
>> - return tmp108_common_probe(dev, regmap, client->name);
>> + hw_id = (unsigned long)i2c_get_match_data(client);
>> +
>> + return tmp108_common_probe(dev, regmap, client->name, hw_id);
>> }
>>
>> static int tmp108_suspend(struct device *dev)
>> @@ -420,15 +537,17 @@ static int tmp108_resume(struct device *dev)
>> static DEFINE_SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume);
>>
>> static const struct i2c_device_id tmp108_i2c_ids[] = {
>> - { "p3t1085" },
>> - { "tmp108" },
>> - { }
>> + { "p3t1035", P3T1035_ID },
>> + { "p3t1085", P3T1085_ID },
>> + { "tmp108", TMP108_ID },
>> + {}
>> };
>> MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids);
>>
>> static const struct of_device_id tmp108_of_ids[] = {
>> - { .compatible = "nxp,p3t1085", },
>> - { .compatible = "ti,tmp108", },
>> + { .compatible = "nxp,p3t1035", .data = (void *)(uintptr_t)P3T1035_ID },
>> + { .compatible = "nxp,p3t1085", .data = (void *)(uintptr_t)P3T1085_ID },
>> + { .compatible = "ti,tmp108", .data = (void *)(uintptr_t)TMP108_ID },
>
> Do not use device ID, define struct drvdata
>
> struct tmp108_drvdata
> {
> .samples = p3t1035_sample_times;
> .reg_width = 16,
> ...
> }
>
> Frank
>> {}
>> };
>> MODULE_DEVICE_TABLE(of, tmp108_of_ids);
>> @@ -444,7 +563,8 @@ static struct i2c_driver tmp108_driver = {
>> };
>>
>> static const struct i3c_device_id p3t1085_i3c_ids[] = {
>> - I3C_DEVICE(0x011b, 0x1529, NULL),
>> + I3C_DEVICE(0x011B, 0x1529, (void *)P3T1085_ID),
>> + I3C_DEVICE(0x011B, 0x152B, (void *)P3T1035_ID),
>> {}
>> };
>> MODULE_DEVICE_TABLE(i3c, p3t1085_i3c_ids);
>> @@ -453,13 +573,16 @@ static int p3t1085_i3c_probe(struct i3c_device *i3cdev)
>> {
>> struct device *dev = i3cdev_to_dev(i3cdev);
>> struct regmap *regmap;
>> + const struct i3c_device_id *id;
>>
>> - regmap = devm_regmap_init_i3c(i3cdev, &tmp108_regmap_config);
>> + regmap = devm_regmap_init(dev, &tmp108_i3c_regmap_bus, i3cdev, &tmp108_regmap_config);
>> if (IS_ERR(regmap))
>> return dev_err_probe(dev, PTR_ERR(regmap),
>> "Failed to register i3c regmap\n");
>>
>> - return tmp108_common_probe(dev, regmap, "p3t1085_i3c");
>> + id = i3c_device_match_id(i3cdev, p3t1085_i3c_ids);
>> +
>> + return tmp108_common_probe(dev, regmap, "p3t1085_i3c", (unsigned long)id->data);
>> }
>>
>> static struct i3c_driver p3t1085_driver = {
>> --
>> 2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030
2026-01-17 0:36 ` Guenter Roeck
@ 2026-01-18 17:30 ` Frank Li
2026-01-19 1:45 ` Guenter Roeck
0 siblings, 1 reply; 9+ messages in thread
From: Frank Li @ 2026-01-18 17:30 UTC (permalink / raw)
To: Guenter Roeck
Cc: Mayank Mahajan, corbet, robh, krzk+dt, conor+dt, linux-hwmon,
devicetree, linux-doc, linux-kernel, priyanka.jain,
vikash.bansal
On Fri, Jan 16, 2026 at 04:36:59PM -0800, Guenter Roeck wrote:
> On 1/16/26 14:28, Frank Li wrote:
> > On Fri, Jan 16, 2026 at 05:05:53PM +0530, Mayank Mahajan wrote:
> > > Add support for the P3T1035 & P3T2030 temperature sensor. While mostly
> > > compatible with the TMP108, P3T1035 uses an 8-bit configuration register
> > > instead of the 16-bit layout used by TMP108. Updated driver to handle
> > > this difference during configuration read/write.
> > >
> > > Signed-off-by: Mayank Mahajan <mayankmahajan.x@nxp.com>
> > > ---
> > > V1 -> V2:
> > > - Disabled hysteresis in is_visible function for P3T1035.
> > > - Added tables for conversion rate similar to the LM75 driver.
> > > - Implemented different bus access depending on the chip being used.
> > > - Removed regmap for 8 bits; now we are using one regmap as before.
> > > - Added read and write functions for i2c and i3c for use with regmap.
> > > - Mapped the 8-bit configuration register to a 16 bit value for P3T1035.
> > > V2 -> V3:
> > > - Remove changes not relevant to adding a new device in the driver.
> > > - Address warnings due to incorrect usage of casting operations.
> > > - Remove the usage of P3T2030 as it's functionally identical to P3T1035.
> > > V3 -> V4:
> > > - Add GENMASK for getting mask for conversion rates.
> > > - Add static arrays for containing sample times for different sensors.
> > > - Remove redundant code such as checking for NULL pointer in probe.
> > > - Improve readability by removing double negation.
> > > - Remove type cast where not required; make reg_buf & val_buf local.
> > >
> > > drivers/hwmon/Kconfig | 2 +-
> > > drivers/hwmon/tmp108.c | 203 +++++++++++++++++++++++++++++++++--------
> > > 2 files changed, 164 insertions(+), 41 deletions(-)
> > >
> > > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> > > index 157678b821fc..31969bddc812 100644
> > > --- a/drivers/hwmon/Kconfig
> > > +++ b/drivers/hwmon/Kconfig
> > > @@ -2398,7 +2398,7 @@ config SENSORS_TMP108
> > > select REGMAP_I3C if I3C
> > > help
> > > If you say yes here you get support for Texas Instruments TMP108
> > > - sensor chips and NXP P3T1085.
> > > + sensor chips, NXP temperature sensors P3T1035, P3T1085 and P3T2030.
> > >
> > > This driver can also be built as a module. If so, the module
> > > will be called tmp108.
> > > diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c
> > > index 60a237cbedbc..d308e2aed18a 100644
> > > --- a/drivers/hwmon/tmp108.c
> > > +++ b/drivers/hwmon/tmp108.c
> > > @@ -17,9 +17,16 @@
> > > #include <linux/regmap.h>
> > > #include <linux/regulator/consumer.h>
> > > #include <linux/slab.h>
> > > +#include <linux/util_macros.h>
> > >
> > > #define DRIVER_NAME "tmp108"
> > >
> > > +enum tmp108_hw_id {
> > > + P3T1035_ID, /* For sensors p3t1035 and p3t2030 */
> > > + P3T1085_ID,
> > > + TMP108_ID,
> > > +};
> > > +
> > > #define TMP108_REG_TEMP 0x00
> > > #define TMP108_REG_CONF 0x01
> > > #define TMP108_REG_TLOW 0x02
> > > @@ -61,6 +68,7 @@
> > > #define TMP108_CONVRATE_1HZ TMP108_CONF_CR0 /* Default */
> > > #define TMP108_CONVRATE_4HZ TMP108_CONF_CR1
> > > #define TMP108_CONVRATE_16HZ (TMP108_CONF_CR0|TMP108_CONF_CR1)
> > > +#define TMP108_CONVRATE_SHIFT 13
> > >
> > > #define TMP108_CONF_HYSTERESIS_MASK (TMP108_CONF_HYS0|TMP108_CONF_HYS1)
> > > #define TMP108_HYSTERESIS_0C 0x0000
> > > @@ -70,12 +78,23 @@
> > >
> > > #define TMP108_CONVERSION_TIME_MS 30 /* in milli-seconds */
> > >
> > > +#define TMP108_CONF_CR0_POS 13
> > > +#define TMP108_CONF_CR1_POS 14
> > > +#define TMP108_CONF_CONVRATE_FLD GENMASK(TMP108_CONF_CR1_POS, TMP108_CONF_CR0_POS)
> > > +
> > > struct tmp108 {
> > > - struct regmap *regmap;
> > > - u16 orig_config;
> > > - unsigned long ready_time;
> > > + struct regmap *regmap;
> > > + u16 orig_config;
> > > + unsigned long ready_time;
> >
> > don't mix format change in this patch.
> > Now prefer orignial format, just one space between type and field.
> >
> > > + enum tmp108_hw_id hw_id;
> > > + bool config_reg_16bits;
> > > + ushort *sample_times;
> > > + size_t n_sample_times;
> > > };
> > >
> > > +ushort p3t1035_sample_times[] = {4000, 1000, 250, 125};
> > > +ushort tmp108_sample_times[] = {4000, 1000, 250, 63};
> > > +
> > > /* convert 12-bit TMP108 register value to milliCelsius */
> > > static inline int tmp108_temp_reg_to_mC(s16 val)
> > > {
> > > @@ -101,21 +120,7 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
> > > ®val);
> > > if (err < 0)
> > > return err;
> > > - switch (regval & TMP108_CONF_CONVRATE_MASK) {
> > > - case TMP108_CONVRATE_0P25HZ:
> > > - default:
> > > - *temp = 4000;
> > > - break;
> > > - case TMP108_CONVRATE_1HZ:
> > > - *temp = 1000;
> > > - break;
> > > - case TMP108_CONVRATE_4HZ:
> > > - *temp = 250;
> > > - break;
> > > - case TMP108_CONVRATE_16HZ:
> > > - *temp = 63;
> > > - break;
> > > - }
> > > + *temp = tmp108->sample_times[FIELD_GET(TMP108_CONF_CONVRATE_FLD, regval)];
> >
> > This code optimation need seperate patch.
> >
> No, There are now two ranges, not just one.
Previous code use swtich case to handle sample. now convert to use a map
array tmp108_sample_times[].
My means use a small patch convert existed switch case to map array firstly
, then add second range, which make code easy to review.
>
> > > return 0;
> > > }
> > > return -EOPNOTSUPP;
> > > @@ -192,22 +197,17 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
> > > {
> > > struct tmp108 *tmp108 = dev_get_drvdata(dev);
> > > u32 regval, mask;
> > > + u8 index;
> > > int err;
> > >
> > > if (type == hwmon_chip) {
> > > if (attr == hwmon_chip_update_interval) {
> > > - if (temp < 156)
> > > - mask = TMP108_CONVRATE_16HZ;
> > > - else if (temp < 625)
> > > - mask = TMP108_CONVRATE_4HZ;
> > > - else if (temp < 2500)
> > > - mask = TMP108_CONVRATE_1HZ;
> > > - else
> > > - mask = TMP108_CONVRATE_0P25HZ;
> > > + index = find_closest_descending(temp, tmp108->sample_times,
> > > + tmp108->n_sample_times);
> >
> > Need seperate patch for the code cleanup.
> >
>
> No. There are now two ranges, not just one. That is not a code cleanup,
> it is a change necessary to support multiple sets of ranges.
The smae here, this code just convert if else to helper function
find_closest_descending(), which is not related work, which add new
part support.
Frank
>
> Guenter
>
> > > return regmap_update_bits(tmp108->regmap,
> > > TMP108_REG_CONF,
> > > TMP108_CONF_CONVRATE_MASK,
> > > - mask);
> > > + FIELD_PREP(TMP108_CONF_CONVRATE_FLD, index));
> > > }
> > > return -EOPNOTSUPP;
> > > }
> > > @@ -251,6 +251,8 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
> > > static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
> > > u32 attr, int channel)
> > > {
> > > + const struct tmp108 *tmp108 = data;
> > > +
> > > if (type == hwmon_chip && attr == hwmon_chip_update_interval)
> > > return 0644;
> > >
> > > @@ -264,8 +266,11 @@ static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
> > > return 0444;
> > > case hwmon_temp_min:
> > > case hwmon_temp_max:
> > > + return 0644;
> > > case hwmon_temp_min_hyst:
> > > case hwmon_temp_max_hyst:
> > > + if (tmp108->hw_id == P3T1035_ID)
> > > + return 0;
> > > return 0644;
> > > default:
> > > return 0;
> > > @@ -311,6 +316,106 @@ static bool tmp108_is_volatile_reg(struct device *dev, unsigned int reg)
> > > return reg == TMP108_REG_TEMP || reg == TMP108_REG_CONF;
> > > }
> > >
> > > +static int tmp108_i2c_reg_read(void *context, unsigned int reg, unsigned int *val)
> > > +{
> > > + struct i2c_client *client = context;
> > > + struct tmp108 *tmp108 = i2c_get_clientdata(client);
> > > + int ret;
> > > +
> > > + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits) {
> > > + ret = i2c_smbus_read_byte_data(client, TMP108_REG_CONF);
> > > + if (ret < 0)
> > > + return ret;
> > > + *val = ret << 8;
> > > + return 0;
> > > + }
> > > +
> > > + ret = i2c_smbus_read_word_swapped(client, reg);
> > > + if (ret < 0)
> > > + return ret;
> > > + *val = ret;
> > > + return 0;
> > > +}
> > > +
> > > +static int tmp108_i2c_reg_write(void *context, unsigned int reg, unsigned int val)
> > > +{
> > > + struct i2c_client *client = context;
> > > + struct tmp108 *tmp108 = i2c_get_clientdata(client);
> > > +
> > > + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
> > > + return i2c_smbus_write_byte_data(client, reg, val >> 8);
> > > + return i2c_smbus_write_word_swapped(client, reg, val);
> > > +}
> > > +
> > > +static const struct regmap_bus tmp108_i2c_regmap_bus = {
> > > + .reg_read = tmp108_i2c_reg_read,
> > > + .reg_write = tmp108_i2c_reg_write,
> > > +};
> > > +
> > > +static int tmp108_i3c_reg_read(void *context, unsigned int reg, unsigned int *val)
> > > +{
> > > + struct i3c_device *i3cdev = context;
> > > + struct tmp108 *tmp108 = i3cdev_get_drvdata(i3cdev);
> > > + u8 reg_buf[1], val_buf[2];
> > > + struct i3c_xfer xfers[] = {
> > > + {
> > > + .rnw = false,
> > > + .len = 1,
> > > + .data.out = reg_buf,
> > > + },
> > > + {
> > > + .rnw = true,
> > > + .len = 2,
> > > + .data.in = val_buf,
> > > + },
> > > + };
> > > + int ret;
> > > +
> > > + reg_buf[0] = reg;
> > > +
> > > + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
> > > + xfers[1].len--;
> > > +
> > > + ret = i3c_device_do_xfers(i3cdev, xfers, 2, I3C_SDR);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + *val = val_buf[0] << 8;
> > > + if (reg != TMP108_REG_CONF || tmp108->config_reg_16bits)
> > > + *val |= val_buf[1];
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int tmp108_i3c_reg_write(void *context, unsigned int reg, unsigned int val)
> > > +{
> > > + struct i3c_device *i3cdev = context;
> > > + struct tmp108 *tmp108 = i3cdev_get_drvdata(i3cdev);
> > > + u8 val_buf[3];
> > > + struct i3c_xfer xfers[] = {
> > > + {
> > > + .rnw = false,
> > > + .len = 3,
> > > + .data.out = val_buf,
> > > + },
> > > + };
> > > +
> > > + val_buf[0] = reg;
> > > + val_buf[1] = (val >> 8) & 0xff;
> > > +
> > > + if (reg == TMP108_REG_CONF && !tmp108->config_reg_16bits)
> > > + xfers[0].len--;
> > > + else
> > > + val_buf[2] = val & 0xff;
> > > +
> > > + return i3c_device_do_xfers(i3cdev, xfers, 1, I3C_SDR);
> > > +}
> > > +
> > > +static const struct regmap_bus tmp108_i3c_regmap_bus = {
> > > + .reg_read = tmp108_i3c_reg_read,
> > > + .reg_write = tmp108_i3c_reg_write,
> > > +};
> > > +
> > > static const struct regmap_config tmp108_regmap_config = {
> > > .reg_bits = 8,
> > > .val_bits = 16,
> > > @@ -323,7 +428,8 @@ static const struct regmap_config tmp108_regmap_config = {
> > > .use_single_write = true,
> > > };
> > >
> > > -static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name)
> > > +static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name,
> > > + enum tmp108_hw_id hw_id)
> > > {
> > > struct device *hwmon_dev;
> > > struct tmp108 *tmp108;
> > > @@ -340,6 +446,15 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
> > >
> > > dev_set_drvdata(dev, tmp108);
> > > tmp108->regmap = regmap;
> > > + tmp108->hw_id = hw_id;
> > > + tmp108->config_reg_16bits = (hw_id == P3T1035_ID) ? false : true;
> > > + if (hw_id == P3T1035_ID) {
> > > + tmp108->sample_times = p3t1035_sample_times;
> > > + tmp108->n_sample_times = ARRAY_SIZE(p3t1035_sample_times);
> > > + } else {
> > > + tmp108->sample_times = tmp108_sample_times;
> > > + tmp108->n_sample_times = ARRAY_SIZE(tmp108_sample_times);
> > > + }
> > >
> > > err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config);
> > > if (err < 0) {
> > > @@ -351,7 +466,6 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
> > > /* Only continuous mode is supported. */
> > > config &= ~TMP108_CONF_MODE_MASK;
> > > config |= TMP108_MODE_CONTINUOUS;
> > > -
> > > /* Only comparator mode is supported. */
> > > config &= ~TMP108_CONF_TM;
> > >
> > > @@ -384,17 +498,20 @@ static int tmp108_probe(struct i2c_client *client)
> > > {
> > > struct device *dev = &client->dev;
> > > struct regmap *regmap;
> > > + enum tmp108_hw_id hw_id;
> > >
> > > if (!i2c_check_functionality(client->adapter,
> > > - I2C_FUNC_SMBUS_WORD_DATA))
> > > + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
> > > return dev_err_probe(dev, -ENODEV,
> > > "adapter doesn't support SMBus word transactions\n");
> > >
> > > - regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config);
> > > + regmap = devm_regmap_init(dev, &tmp108_i2c_regmap_bus, client, &tmp108_regmap_config);
> > > if (IS_ERR(regmap))
> > > return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed");
> > >
> > > - return tmp108_common_probe(dev, regmap, client->name);
> > > + hw_id = (unsigned long)i2c_get_match_data(client);
> > > +
> > > + return tmp108_common_probe(dev, regmap, client->name, hw_id);
> > > }
> > >
> > > static int tmp108_suspend(struct device *dev)
> > > @@ -420,15 +537,17 @@ static int tmp108_resume(struct device *dev)
> > > static DEFINE_SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume);
> > >
> > > static const struct i2c_device_id tmp108_i2c_ids[] = {
> > > - { "p3t1085" },
> > > - { "tmp108" },
> > > - { }
> > > + { "p3t1035", P3T1035_ID },
> > > + { "p3t1085", P3T1085_ID },
> > > + { "tmp108", TMP108_ID },
> > > + {}
> > > };
> > > MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids);
> > >
> > > static const struct of_device_id tmp108_of_ids[] = {
> > > - { .compatible = "nxp,p3t1085", },
> > > - { .compatible = "ti,tmp108", },
> > > + { .compatible = "nxp,p3t1035", .data = (void *)(uintptr_t)P3T1035_ID },
> > > + { .compatible = "nxp,p3t1085", .data = (void *)(uintptr_t)P3T1085_ID },
> > > + { .compatible = "ti,tmp108", .data = (void *)(uintptr_t)TMP108_ID },
> >
> > Do not use device ID, define struct drvdata
> >
> > struct tmp108_drvdata
> > {
> > .samples = p3t1035_sample_times;
> > .reg_width = 16,
> > ...
> > }
> >
> > Frank
> > > {}
> > > };
> > > MODULE_DEVICE_TABLE(of, tmp108_of_ids);
> > > @@ -444,7 +563,8 @@ static struct i2c_driver tmp108_driver = {
> > > };
> > >
> > > static const struct i3c_device_id p3t1085_i3c_ids[] = {
> > > - I3C_DEVICE(0x011b, 0x1529, NULL),
> > > + I3C_DEVICE(0x011B, 0x1529, (void *)P3T1085_ID),
> > > + I3C_DEVICE(0x011B, 0x152B, (void *)P3T1035_ID),
> > > {}
> > > };
> > > MODULE_DEVICE_TABLE(i3c, p3t1085_i3c_ids);
> > > @@ -453,13 +573,16 @@ static int p3t1085_i3c_probe(struct i3c_device *i3cdev)
> > > {
> > > struct device *dev = i3cdev_to_dev(i3cdev);
> > > struct regmap *regmap;
> > > + const struct i3c_device_id *id;
> > >
> > > - regmap = devm_regmap_init_i3c(i3cdev, &tmp108_regmap_config);
> > > + regmap = devm_regmap_init(dev, &tmp108_i3c_regmap_bus, i3cdev, &tmp108_regmap_config);
> > > if (IS_ERR(regmap))
> > > return dev_err_probe(dev, PTR_ERR(regmap),
> > > "Failed to register i3c regmap\n");
> > >
> > > - return tmp108_common_probe(dev, regmap, "p3t1085_i3c");
> > > + id = i3c_device_match_id(i3cdev, p3t1085_i3c_ids);
> > > +
> > > + return tmp108_common_probe(dev, regmap, "p3t1085_i3c", (unsigned long)id->data);
> > > }
> > >
> > > static struct i3c_driver p3t1085_driver = {
> > > --
> > > 2.34.1
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030
2026-01-18 17:30 ` Frank Li
@ 2026-01-19 1:45 ` Guenter Roeck
0 siblings, 0 replies; 9+ messages in thread
From: Guenter Roeck @ 2026-01-19 1:45 UTC (permalink / raw)
To: Frank Li
Cc: Mayank Mahajan, corbet, robh, krzk+dt, conor+dt, linux-hwmon,
devicetree, linux-doc, linux-kernel, priyanka.jain,
vikash.bansal
Frank,
On 1/18/26 09:30, Frank Li wrote:
...
>>>> @@ -101,21 +120,7 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
>>>> ®val);
>>>> if (err < 0)
>>>> return err;
>>>> - switch (regval & TMP108_CONF_CONVRATE_MASK) {
>>>> - case TMP108_CONVRATE_0P25HZ:
>>>> - default:
>>>> - *temp = 4000;
>>>> - break;
>>>> - case TMP108_CONVRATE_1HZ:
>>>> - *temp = 1000;
>>>> - break;
>>>> - case TMP108_CONVRATE_4HZ:
>>>> - *temp = 250;
>>>> - break;
>>>> - case TMP108_CONVRATE_16HZ:
>>>> - *temp = 63;
>>>> - break;
>>>> - }
>>>> + *temp = tmp108->sample_times[FIELD_GET(TMP108_CONF_CONVRATE_FLD, regval)];
>>>
>>> This code optimation need seperate patch.
>>>
>> No, There are now two ranges, not just one.
>
> Previous code use swtich case to handle sample. now convert to use a map
> array tmp108_sample_times[].
>
> My means use a small patch convert existed switch case to map array firstly
> , then add second range, which make code easy to review.
>
You are not signed up as reviewer of this driver. I am, and I don't want to see
a separate patch just for this because it means extra work for me.
Thanks,
Guenter
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-01-19 1:45 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-16 11:35 [PATCH v4 1/3] dt-bindings: hwmon: ti,tmp108: Add P3T1035,P3T2030 Mayank Mahajan
2026-01-16 11:35 ` [PATCH v4 2/3] hwmon: (tmp108) Add support for P3T1035 and P3T2030 Mayank Mahajan
2026-01-16 21:37 ` kernel test robot
2026-01-16 22:28 ` Frank Li
2026-01-17 0:36 ` Guenter Roeck
2026-01-18 17:30 ` Frank Li
2026-01-19 1:45 ` Guenter Roeck
2026-01-16 11:35 ` [PATCH v4 3/3] hwmon: (tmp108) Add P3T1035 and P3T2030 support Mayank Mahajan
2026-01-16 14:38 ` [PATCH v4 1/3] dt-bindings: hwmon: ti,tmp108: Add P3T1035,P3T2030 Krzysztof Kozlowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®