This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/TMP101: Linux driver for TMP101

Part Number: TMP101
Other Parts Discussed in Thread: TMP102,

Tool/software: Linux

Here is a patch for existing TMP102 Linux driver to support TMP101.

To use it, just define the device in the device tree as compatible with "ti,tmp101"  and in the kernel config do not select other drivers compatible with the same ID (such as LM75).

I made it because the other alternative - LM75 driver - claims to handle many compatible devices, its detection code is complicated and failed on my board.

OTOH, the TMP102 driver is simple and clean, but is not compatible with TMP101 as is.

So I made a small change to the 102 driver to support TMP101 as well. If the device actually is TMP102, it is run in TMP101 compatible mode,

which limits its temperature range to +128 C (like in LM75 and TMP101).

Regards,

-- Pavel A.

--- linux-4.19/drivers/hwmon/tmp102.c	2018-10-28 00:10:13.000000000 +0300
+++ linux-4.19/drivers/hwmon/tmp102.c	2018-10-28 00:20:24.000000000 +0300
@@ -1,9 +1,10 @@
 /* Texas Instruments TMP102 SMBus temperature sensor driver
  *
  * Copyright (C) 2010 Steven King <sfking@fdwdc.com>
+ * Quick hack for TMP101 -- pavel_a@fastmail.fm, Oct. 2018
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
@@ -52,34 +53,54 @@
 				 TMP102_CONF_F1 | TMP102_CONF_OS | \
 				 TMP102_CONF_EM | TMP102_CONF_AL | \
 				 TMP102_CONF_CR0 | TMP102_CONF_CR1)
 
 #define TMP102_CONFIG_CLEAR	(TMP102_CONF_SD | TMP102_CONF_OS | \
 				 TMP102_CONF_CR0)
+#if 0 /* Extended 13 bit mode, for temperatures > 128C */
 #define TMP102_CONFIG_SET	(TMP102_CONF_TM | TMP102_CONF_EM | \
 				 TMP102_CONF_CR1)
+#else /* Use 12-bit mode compatible with tmp101, LM75 */
+#define TMP102_CONFIG_SET	(TMP102_CONF_TM | TMP102_CONF_CR1)
+#endif
 
+#define TMP101_CONF_DEF (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_F0)
+
 #define CONVERSION_TIME_MS		35	/* in milli-seconds */
 
 struct tmp102 {
 	struct regmap *regmap;
 	u16 config_orig;
 	unsigned long ready_time;
 };
 
+#if 0
 /* convert left adjusted 13-bit TMP102 register value to milliCelsius */
 static inline int tmp102_reg_to_mC(s16 val)
 {
 	return ((val & ~0x01) * 1000) / 128;
 }
 
 /* convert milliCelsius to left adjusted 13-bit TMP102 register value */
 static inline u16 tmp102_mC_to_reg(int val)
 {
 	return (val * 128) / 1000;
 }
+#else
+/* convert left adjusted 12-bit TMP101 register value to milliCelsius */
+static inline int tmp102_reg_to_mC(s16 val)
+{
+	return ((val & ~0x01) * 1000) / 256;
+}
+
+/* convert milliCelsius to left adjusted 12-bit TMP101 register value */
+static inline u16 tmp102_mC_to_reg(int val)
+{
+	return (val * 256) / 1000;
+}
+#endif
 
 static int tmp102_read(struct device *dev, enum hwmon_sensor_types type,
 		       u32 attr, int channel, long *temp)
 {
 	struct tmp102 *tmp102 = dev_get_drvdata(dev);
 	unsigned int regval;
@@ -246,14 +267,33 @@
 		dev_err(dev, "error reading config register\n");
 		return err;
 	}
 
 	if ((regval & ~TMP102_CONFREG_MASK) !=
 	    (TMP102_CONF_R0 | TMP102_CONF_R1)) {
-		dev_err(dev, "unexpected config register value\n");
-		return -ENODEV;
+		dev_err(dev, "unexpected config register value, assume tmp101\n");
+
+		// Assume this is TMP101. Set resolution 12 bit, which is TMP102 default.
+		regval = TMP101_CONF_DEF;
+		err = regmap_write(tmp102->regmap, TMP102_CONF_REG, regval);
+		if (err < 0) {
+			dev_err(dev, "error writing config register\n");
+			return err;
+		}
+
+		// Read back, ignore CFG low byte (non existing in 101):
+		err = regmap_read(tmp102->regmap, TMP102_CONF_REG, &regval);
+		if (err < 0) {
+			dev_err(dev, "error reading config register\n");
+			return err;
+		}
+
+		if ((regval & 0xFF00) != (TMP101_CONF_DEF & 0xFF00)) {
+			dev_err(dev, "Cannot configure as TMP101\n");
+			return -ENODEV;
+		}
 	}
 
 	tmp102->config_orig = regval;
 
 	err = devm_add_action_or_reset(dev, tmp102_restore_config, tmp102);
 	if (err)
@@ -276,13 +316,13 @@
 
 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
 							 tmp102,
 							 &tmp102_chip_info,
 							 NULL);
 	if (IS_ERR(hwmon_dev)) {
-		dev_dbg(dev, "unable to register hwmon device\n");
+		dev_err(dev, "unable to register hwmon device\n");
 		return PTR_ERR(hwmon_dev);
 	}
 	dev_info(dev, "initialized\n");
 
 	return 0;
 }
@@ -318,13 +358,13 @@
 	{ "tmp102", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, tmp102_id);
 
 static const struct of_device_id tmp102_of_match[] = {
-	{ .compatible = "ti,tmp102" },
+	{ .compatible = "ti,tmp102" }, { .compatible = "ti,tmp101" },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, tmp102_of_match);
 
 static struct i2c_driver tmp102_driver = {
 	.driver.name	= DRIVER_NAME,