[PATCH RESEND] hwmon: lm70: TI TMP121 support.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The Texas Instruments TMP121 is a SPI temperature sensor very similar
to the LM70, with slightly higher resolution.  This patch extends the
LM70 driver to support the TMP121.  Chip type is determined through
SPI platform data.

Signed-off-by: Manuel Lauss <mano at roarinelk.homelinux.net>
---
 Documentation/hwmon/lm70 |    7 +++++-
 drivers/hwmon/Kconfig    |    5 ++-
 drivers/hwmon/lm70.c     |   56 ++++++++++++++++++++++++++++++++++++++++-----
 include/linux/spi/lm70.h |   15 ++++++++++++
 4 files changed, 73 insertions(+), 10 deletions(-)
 create mode 100644 include/linux/spi/lm70.h

diff --git a/Documentation/hwmon/lm70 b/Documentation/hwmon/lm70
index 2bdd3fe..88f4322 100644
--- a/Documentation/hwmon/lm70
+++ b/Documentation/hwmon/lm70
@@ -1,9 +1,11 @@
 Kernel driver lm70
 ==================
 
-Supported chip:
+Supported chips:
   * National Semiconductor LM70
     Datasheet: http://www.national.com/pf/LM/LM70.html
+  * Texas Instruments TMP121/TMP123
+    Datasheet: http://www.ti.com/lit/gpn/tmp121
 
 Author:
         Kaiwan N Billimoria <kaiwan at designergraphix.com>
@@ -25,6 +27,9 @@ complement digital temperature (sent via the SIO line), is available in the
 driver for interpretation. This driver makes use of the kernel's in-core
 SPI support.
 
+The TMP121 is very similar; main differences are 4 wire SPI interface,
+and 13bit temperature data (0.0625 celsius resolution).
+
 Thanks to
 ---------
 Jean Delvare <khali at linux-fr.org> for mentoring the hwmon-side driver
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 6de1e0f..f86923d 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -407,11 +407,12 @@ config SENSORS_LM63
 	  will be called lm63.
 
 config SENSORS_LM70
-	tristate "National Semiconductor LM70"
+	tristate "National Semiconductor LM70 / Texas Instruments TMP121"
 	depends on SPI_MASTER && EXPERIMENTAL
 	help
 	  If you say yes here you get support for the National Semiconductor
-	  LM70 digital temperature sensor chip.
+	  LM70 and Texas Instruments TMP121/TMP123 digital temperature
+	  sensor chips.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm70.
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index d435f00..9ab0479 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -33,13 +33,14 @@
 #include <linux/hwmon.h>
 #include <linux/mutex.h>
 #include <linux/spi/spi.h>
-
+#include <linux/spi/lm70.h>
 
 #define DRVNAME		"lm70"
 
 struct lm70 {
 	struct device *hwmon_dev;
 	struct mutex lock;
+	unsigned int chip;
 };
 
 /* sysfs hook function */
@@ -67,10 +68,8 @@ static ssize_t lm70_sense_temp(struct device *dev,
 	}
 	dev_dbg(dev, "rxbuf[1] : 0x%x rxbuf[0] : 0x%x\n", rxbuf[1], rxbuf[0]);
 
-	raw = (rxbuf[1] << 8) + rxbuf[0];
-	dev_dbg(dev, "raw=0x%x\n", raw);
-
 	/*
+	 * LM70:
 	 * The "raw" temperature read into rxbuf[] is a 16-bit signed 2's
 	 * complement value. Only the MSB 11 bits (1 sign + 10 temperature
 	 * bits) are meaningful; the LSB 5 bits are to be discarded.
@@ -80,8 +79,27 @@ static ssize_t lm70_sense_temp(struct device *dev,
 	 * by 0.25. Also multiply by 1000 to represent in millidegrees
 	 * Celsius.
 	 * So it's equivalent to multiplying by 0.25 * 1000 = 250.
+	 *
+	 * TMP121:
+	 * 13bits of 2's complement data, discard lower 3 bits.  Chip
+	 * transmits high byte first.  Resolution 0.0625 celsius.
 	 */
-	val = ((int)raw/32) * 250;
+	switch (p_lm70->chip) {
+	case LM70_CHIP_LM70:
+		raw = (rxbuf[1] << 8) + rxbuf[0];
+		dev_dbg(dev, "raw=0x%x\n", raw);
+		val = ((int)raw/32) * 250;
+		break;
+
+	case LM70_CHIP_TMP121:
+		raw = (rxbuf[0] << 8) + rxbuf[1];
+		dev_dbg(dev, "raw=0x%x\n", raw);
+		val = (raw / 8) * 625 / 10;
+		break;
+
+	default:
+		raw = 0;
+	}
 	status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
 out:
 	mutex_unlock(&p_lm70->lock);
@@ -93,7 +111,21 @@ static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
 static ssize_t lm70_show_name(struct device *dev, struct device_attribute
 			      *devattr, char *buf)
 {
-	return sprintf(buf, "lm70\n");
+	struct spi_device *spi = to_spi_device(dev);
+	struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
+	int ret;
+
+	switch (p_lm70->chip) {
+	case LM70_CHIP_LM70:
+		ret = sprintf(buf, "lm70\n");
+		break;
+	case LM70_CHIP_TMP121:
+		ret = sprintf(buf, "tmp121\n");
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
 }
 
 static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
@@ -102,11 +134,20 @@ static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
 
 static int __devinit lm70_probe(struct spi_device *spi)
 {
+	struct lm70_platform_data *pdata;
 	struct lm70 *p_lm70;
 	int status;
+	unsigned int chip;
+
+	pdata = spi->dev.platform_data;
+	if (pdata)
+		chip = pdata->chip;
+	else
+		chip = LM70_CHIP_LM70;
 
 	/* signaling is SPI_MODE_0 on a 3-wire link (shared SI/SO) */
-	if ((spi->mode & (SPI_CPOL|SPI_CPHA)) || !(spi->mode & SPI_3WIRE))
+	if ((chip == LM70_CHIP_LM70) &&
+	    ((spi->mode & (SPI_CPOL|SPI_CPHA)) || !(spi->mode & SPI_3WIRE)))
 		return -EINVAL;
 
 	p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
@@ -114,6 +155,7 @@ static int __devinit lm70_probe(struct spi_device *spi)
 		return -ENOMEM;
 
 	mutex_init(&p_lm70->lock);
+	p_lm70->chip = chip;
 
 	/* sysfs hook */
 	p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
diff --git a/include/linux/spi/lm70.h b/include/linux/spi/lm70.h
new file mode 100644
index 0000000..986c35a
--- /dev/null
+++ b/include/linux/spi/lm70.h
@@ -0,0 +1,15 @@
+/*
+ * LM70 platform data
+ */
+
+#ifndef _LM70_H_
+#define _LM70_H_
+
+#define LM70_CHIP_LM70		0
+#define LM70_CHIP_TMP121	1
+
+struct lm70_platform_data {
+	unsigned int chip;
+};
+
+#endif
-- 
1.6.0.2





[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux