[PATCH 2/3] lm90: Support MAX6646, MAX6647 and MAX6649

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

 



These Maxim chips are similar to MAX6657 but use unsigned temperature
values to allow for readings up to 145 degrees.

Signed-off-by: Ben Hutchings <bhutchings at solarflare.com>
---
 drivers/hwmon/Kconfig |    3 +-
 drivers/hwmon/lm90.c  |   67 ++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 55 insertions(+), 15 deletions(-)

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index b8ab275..cc40c88 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -485,7 +485,8 @@ config SENSORS_LM90
 	help
 	  If you say yes here you get support for National Semiconductor LM90,
 	  LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, and Maxim
-	  MAX6657, MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips.
+	  MAX6646, MAX6647, MAX6649, MAX6657, MAX6658, MAX6659, MAX6680 and
+	  MAX6681 sensor chips.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm90.
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 9ee7e3a..dbf0dfe 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -25,9 +25,10 @@
  * that are not handled by this driver. Among others, it has a higher
  * accuracy than the LM90, much like the LM86 does.
  *
- * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor
- * chips made by Maxim. These chips are similar to the LM86.
- * Note that there is no easy way to differentiate between the three
+ * This driver also supports the MAX6646, MAX6647, MAX6649, MAX6657,
+ * MAX6658 and MAX6659 sensor chips made by Maxim. These chips are
+ * similar to the LM86.
+ * Note that there is no easy way to differentiate between the MAX665x
  * variants. The extra address and features of the MAX6659 are not
  * supported by this driver. These chips lack the remote temperature
  * offset feature.
@@ -76,9 +77,10 @@
  * Addresses to scan
  * Address is fully defined internally and cannot be changed except for
  * MAX6659, MAX6680 and MAX6681.
- * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658
- * have address 0x4c.
- * ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d.
+ * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6649, MAX6657
+ * and MAX6658 have address 0x4c.
+ * ADM1032-2, ADT7461-2, LM89-1, LM99-1 and MAX6646 have address 0x4d.
+ * MAX6647 has address 0x4e.
  * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported).
  * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
  * 0x4c, 0x4d or 0x4e.
@@ -91,7 +93,8 @@ static const unsigned short normal_i2c[] = {
  * Insmod parameters
  */
 
-I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
+I2C_CLIENT_INSMOD_8(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680,
+		    max6646);
 
 /*
  * The LM90 registers
@@ -132,7 +135,7 @@ I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
 #define LM90_REG_R_TCRIT_HYST		0x21
 #define LM90_REG_W_TCRIT_HYST		0x21
 
-/* MAX6657-specific registers */
+/* MAX6646/6647/6649/6657/6658/6659 registers */
 
 #define MAX6657_REG_R_LOCAL_TEMPL	0x11
 
@@ -185,7 +188,7 @@ struct lm90_data {
 	s16 temp11[5];	/* 0: remote input
 			   1: remote low limit
 			   2: remote high limit
-			   3: remote offset (except max6657)
+			   3: remote offset (except max6646 and max6657)
 			   4: local input */
 	u8 temp_hyst;
 	u8 alarms; /* bitvector */
@@ -197,6 +200,8 @@ struct lm90_data {
  * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius.
  * For remote temperatures and limits, it uses signed 11-bit values with
  * LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
+ * Some Maxim chips use 16-bit signed or unsigned values for local and
+ * both remote temperatures.
  */
 
 static inline int temp_from_s8(s8 val)
@@ -204,11 +209,21 @@ static inline int temp_from_s8(s8 val)
 	return val * 1000;
 }
 
+static inline int temp_from_u8(u8 val)
+{
+	return val * 1000;
+}
+
 static inline int temp_from_s16(s16 val)
 {
 	return val / 32 * 125;
 }
 
+static inline int temp_from_u16(u16 val)
+{
+	return val / 32 * 125;
+}
+
 static s8 temp_to_s8(long val)
 {
 	if (val <= -128000)
@@ -220,6 +235,15 @@ static s8 temp_to_s8(long val)
 	return (val + 500) / 1000;
 }
 
+static u8 temp_to_u8(long val)
+{
+	if (val <= 0)
+		return 0;
+	if (val >= 255000)
+		return 255;
+	return (val + 500) / 1000;
+}
+
 static s16 temp_to_s16(long val)
 {
 	if (val <= -128000)
@@ -311,6 +335,8 @@ static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
 
 	if (data->kind == adt7461)
 		temp = temp_from_u8_adt7461(data, data->temp8[attr->index]);
+	else if (data->kind == max6646)
+		temp = temp_from_u8(data->temp8[attr->index]);
 	else
 		temp = temp_from_s8(data->temp8[attr->index]);
 
@@ -336,6 +362,8 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
 	mutex_lock(&data->update_lock);
 	if (data->kind == adt7461)
 		data->temp8[nr] = temp_to_u8_adt7461(data, val);
+	else if (data->kind == max6646)
+		data->temp8[nr] = temp_to_u8(val);
 	else
 		data->temp8[nr] = temp_to_s8(val);
 	i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]);
@@ -352,6 +380,8 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
 
 	if (data->kind == adt7461)
 		temp = temp_from_u16_adt7461(data, data->temp11[attr->index]);
+	else if (data->kind == max6646)
+		temp = temp_from_u16(data->temp11[attr->index]);
 	else
 		temp = temp_from_s16(data->temp11[attr->index]);
 
@@ -381,12 +411,15 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
 		data->temp11[nr] = temp_to_u16_adt7461(data, val);
 	else if (data->kind == max6657 || data->kind == max6680)
 		data->temp11[nr] = temp_to_s8(val) << 8;
+	else if (data->kind == max6646)
+		data->temp11[nr] = temp_to_u8(val) << 8;
 	else
 		data->temp11[nr] = temp_to_s16(val);
 
 	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
 				  data->temp11[nr] >> 8);
-	if (data->kind != max6657 && data->kind != max6680)
+	if (data->kind != max6657 && data->kind != max6680
+	    && data->kind != max6646)
 		i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
 					  data->temp11[nr] & 0xff);
 	mutex_unlock(&data->update_lock);
@@ -696,6 +729,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
 			 && (reg_config1 & 0x03) == 0x00
 			 && reg_convrate <= 0x07) {
 			 	kind = max6680;
+			} else if (chip_id == 0x59) {
+				kind = max6646;
 			}
 		}
 
@@ -725,6 +760,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
 		name = "max6680";
 	} else if (kind == adt7461) {
 		name = "adt7461";
+	} else if (kind == max6646) {
+		name = "max6646";
 	}
 
 	/* We can fill in the remaining client fields */
@@ -748,7 +785,7 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
 					      &dev_attr_pec)))
 			goto exit_remove_files;
 	}
-	if (data->kind != max6657) {
+	if (data->kind != max6657 && data->kind != max6646) {
 		if ((err = device_create_file(&new_client->dev,
 				&sensor_dev_attr_temp2_offset.dev_attr)))
 			goto exit_remove_files;
@@ -811,7 +848,7 @@ static int lm90_detach_client(struct i2c_client *client)
 	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &lm90_group);
 	device_remove_file(&client->dev, &dev_attr_pec);
-	if (data->kind != max6657)
+	if (data->kind != max6657 && data->kind != max6646)
 		device_remove_file(&client->dev,
 				   &sensor_dev_attr_temp2_offset.dev_attr);
 
@@ -871,7 +908,7 @@ static struct lm90_data *lm90_update_device(struct device *dev)
 		lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[3]);
 		lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst);
 
-		if (data->kind == max6657) {
+		if (data->kind == max6657 || data->kind == max6646) {
 			lm90_read16(client, LM90_REG_R_LOCAL_TEMP,
 				    MAX6657_REG_R_LOCAL_TEMPL,
 				    &data->temp11[4]);
@@ -886,6 +923,7 @@ static struct lm90_data *lm90_update_device(struct device *dev)
 		if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) == 0) {
 			data->temp11[1] = h << 8;
 			if (data->kind != max6657 && data->kind != max6680
+			 && data->kind != max6646
 			 && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL,
 					  &l) == 0)
 				data->temp11[1] |= l;
@@ -893,12 +931,13 @@ static struct lm90_data *lm90_update_device(struct device *dev)
 		if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) == 0) {
 			data->temp11[2] = h << 8;
 			if (data->kind != max6657 && data->kind != max6680
+			 && data->kind != max6646
 			 && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL,
 					  &l) == 0)
 				data->temp11[2] |= l;
 		}
 
-		if (data->kind != max6657) {
+		if (data->kind != max6657 && data->kind != max6646) {
 			if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH,
 					  &h) == 0
 			 && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL,
-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.




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

  Powered by Linux