]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
hwmon: (tmp108) Add support for P3T1035 and P3T2030
authorMayank Mahajan <mayankmahajan.x@nxp.com>
Mon, 19 Jan 2026 04:04:58 +0000 (09:34 +0530)
committerGuenter Roeck <linux@roeck-us.net>
Sat, 31 Jan 2026 15:38:33 +0000 (07:38 -0800)
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>
Link: https://lore.kernel.org/r/20260119040459.2898998-2-mayankmahajan.x@nxp.com
[groeck: Reordered include files to retain alphabetic order]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/Kconfig
drivers/hwmon/tmp108.c

index d9bac1e3057bae0f0242a685b1c4b62b2e4a701e..41c381764c2bc414a187941ec51720025786390a 100644 (file)
@@ -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.
index 60a237cbedbc147a4d77a03c436dca5f4c2272fd..3ea5f6485744d78ee0824be7d6c4374e1d8b3662 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2016 John Muir <john@jmuir.com>
  */
 
+#include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -17,6 +18,7 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
+#include <linux/util_macros.h>
 
 #define        DRIVER_NAME "tmp108"
 
 
 #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;
+       const struct tmp108_params *params;
+};
+
+struct tmp108_params {
+       bool config_reg_16bits;
+       const u16 *sample_times;
+       size_t n_sample_times;
+};
+
+static const u16 p3t1035_sample_times[] = {4000, 1000, 250, 125};
+static const u16 tmp108_sample_times[] = {4000, 1000, 250, 63};
+
+static const struct tmp108_params p3t1035_data = {
+       .sample_times = p3t1035_sample_times,
+       .n_sample_times  = ARRAY_SIZE(p3t1035_sample_times),
+       .config_reg_16bits = false,
+};
+
+static const struct tmp108_params tmp108_data = {
+       .sample_times = tmp108_sample_times,
+       .n_sample_times  = ARRAY_SIZE(tmp108_sample_times),
+       .config_reg_16bits = true,
 };
 
 /* convert 12-bit TMP108 register value to milliCelsius */
@@ -101,21 +129,8 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
                                          &regval);
                        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->params->sample_times[FIELD_GET(TMP108_CONF_CONVRATE_FLD,
+                                                                      regval)];
                        return 0;
                }
                return -EOPNOTSUPP;
@@ -192,22 +207,18 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
 {
        struct tmp108 *tmp108 = dev_get_drvdata(dev);
        u32 regval, mask;
+       size_t len;
+       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;
+                       len = tmp108->params->n_sample_times;
+                       index = find_closest_descending(temp, tmp108->params->sample_times, len);
                        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 +262,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 +277,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->params->config_reg_16bits)
+                       return 0;
                return 0644;
        default:
                return 0;
@@ -311,6 +327,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->params->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->params->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->params->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->params->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->params->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 +439,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,
+                              const struct tmp108_params *params)
 {
        struct device *hwmon_dev;
        struct tmp108 *tmp108;
@@ -340,6 +457,7 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
 
        dev_set_drvdata(dev, tmp108);
        tmp108->regmap = regmap;
+       tmp108->params = params;
 
        err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config);
        if (err < 0) {
@@ -351,7 +469,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;
 
@@ -386,15 +503,15 @@ static int tmp108_probe(struct i2c_client *client)
        struct regmap *regmap;
 
        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);
+       return tmp108_common_probe(dev, regmap, client->name, i2c_get_match_data(client));
 }
 
 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", (unsigned long)&p3t1035_data },
+       { "p3t1085", (unsigned long)&tmp108_data },
+       { "tmp108", (unsigned long)&tmp108_data },
+       {}
 };
 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 = &p3t1035_data },
+       { .compatible = "nxp,p3t1085", .data = &tmp108_data },
+       { .compatible = "ti,tmp108", .data = &tmp108_data },
        {}
 };
 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, &tmp108_data),
+       I3C_DEVICE(0x011B, 0x152B, &p3t1035_data),
        {}
 };
 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", id->data);
 }
 
 static struct i3c_driver p3t1085_driver = {