[PATCH 3/4] drivers/hwmon/lm80.c: added error handling

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

 



added error handling so if lm80_update_device fails
an error is returned when reading the value through sysfs
This is closely modeled after the way this is handled in ltc4261

Note: if update gets an error, this error is returned for all
registers and no further reads are done.
If a register is not accessible most likely the whole device
is broken or disconnected and it is definitely interesting to know.

Note2: I added a macro to read and handle errors. This was felt to
be the simplest. If someone feels it should be done using a
subroutine, be my guest.

Signed-off-by: Frans Meulenbroeks <fransmeulenbroeks@xxxxxxxxx>
---
patch is against the hwmon staging tree
git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
as retrieved on jan 2, 2012

 drivers/hwmon/lm80.c |   97 ++++++++++++++++++++++++++++++++++---------------
 1 files changed, 67 insertions(+), 30 deletions(-)

diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 18a0e6c..5283b27 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -168,6 +168,8 @@ static ssize_t show_in_##suffix(struct device *dev, struct device_attribute *att
 { \
 	int nr = to_sensor_dev_attr(attr)->index; \
 	struct lm80_data *data = lm80_update_device(dev); \
+	if (IS_ERR(data)) \
+		return PTR_ERR(data); \
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \
 }
 show_in(min, in_min)
@@ -197,6 +199,8 @@ static ssize_t show_fan_##suffix(struct device *dev, struct device_attribute *at
 { \
 	int nr = to_sensor_dev_attr(attr)->index; \
 	struct lm80_data *data = lm80_update_device(dev); \
+	if (IS_ERR(data)) \
+		return PTR_ERR(data); \
 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \
 		       DIV_FROM_REG(data->fan_div[nr]))); \
 }
@@ -208,6 +212,8 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
 {
 	int nr = to_sensor_dev_attr(attr)->index;
 	struct lm80_data *data = lm80_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
 }
 
@@ -271,6 +277,8 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
 static ssize_t show_temp_input1(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct lm80_data *data = lm80_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp));
 }
 
@@ -278,6 +286,8 @@ static ssize_t show_temp_input1(struct device *dev, struct device_attribute *att
 static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \
 { \
 	struct lm80_data *data = lm80_update_device(dev); \
+	if (IS_ERR(data)) \
+		return PTR_ERR(data); \
 	return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \
 }
 show_temp(hot_max, temp_hot_max);
@@ -308,6 +318,8 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
 	struct lm80_data *data = lm80_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 	return sprintf(buf, "%u\n", data->alarms);
 }
 
@@ -316,6 +328,8 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
 {
 	int bitnr = to_sensor_dev_attr(attr)->index;
 	struct lm80_data *data = lm80_update_device(dev);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
 }
 
@@ -544,55 +558,78 @@ static void lm80_init_client(struct i2c_client *client)
 	lm80_write_value(client, LM80_REG_CONFIG, 0x01);
 }
 
+/*
+   Note: safe_lm80_read_value is a helper macro for lm80_update_device
+	 It reads a value using lm80_read_value and jumps to abort
+	 in case of an error.
+	 Due to this jump and because it modifies the first arguement
+	 it has to be a macro
+*/
+#define safe_lm80_read_value(var, client, reg) \
+	{ \
+		status = lm80_read_value(client, reg); \
+		if (unlikely(status < 0)) { \
+			dev_dbg(dev, \
+				"LM80: Failed to read value: reg %d, error %d\n", \
+				reg, status); \
+			ret = ERR_PTR(status); \
+			data->valid = 0; \
+			goto abort; \
+		} \
+		else \
+			var = status; \
+	} 
+
 static struct lm80_data *lm80_update_device(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm80_data *data = i2c_get_clientdata(client);
+	struct lm80_data *ret = data;
 	int i;
+	int status;
+	int tmp1, tmp2;
 
 	mutex_lock(&data->update_lock);
 
+	if (!data->valid)
+	{
+		/* last time failed: re-initialize the LM80 chip */
+		lm80_init_client(client);
+	}
 	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
 		dev_dbg(&client->dev, "Starting lm80 update\n");
 		for (i = 0; i <= 6; i++) {
-			data->in[i] =
-			    lm80_read_value(client, LM80_REG_IN(i));
-			data->in_min[i] =
-			    lm80_read_value(client, LM80_REG_IN_MIN(i));
-			data->in_max[i] =
-			    lm80_read_value(client, LM80_REG_IN_MAX(i));
+			safe_lm80_read_value(data->in[i], client, LM80_REG_IN(i));
+			safe_lm80_read_value(data->in_min[i], client, LM80_REG_IN_MIN(i));
+			safe_lm80_read_value(data->in_max[i], client, LM80_REG_IN_MAX(i));
 		}
-		data->fan[0] = lm80_read_value(client, LM80_REG_FAN1);
-		data->fan_min[0] =
-		    lm80_read_value(client, LM80_REG_FAN_MIN(1));
-		data->fan[1] = lm80_read_value(client, LM80_REG_FAN2);
-		data->fan_min[1] =
-		    lm80_read_value(client, LM80_REG_FAN_MIN(2));
-
-		data->temp =
-		    (lm80_read_value(client, LM80_REG_TEMP) << 8) |
-		    (lm80_read_value(client, LM80_REG_RES) & 0xf0);
-		data->temp_os_max =
-		    lm80_read_value(client, LM80_REG_TEMP_OS_MAX);
-		data->temp_os_hyst =
-		    lm80_read_value(client, LM80_REG_TEMP_OS_HYST);
-		data->temp_hot_max =
-		    lm80_read_value(client, LM80_REG_TEMP_HOT_MAX);
-		data->temp_hot_hyst =
-		    lm80_read_value(client, LM80_REG_TEMP_HOT_HYST);
-
-		i = lm80_read_value(client, LM80_REG_FANDIV);
+		safe_lm80_read_value(data->fan[0], client, LM80_REG_FAN1);
+		safe_lm80_read_value(data->fan_min[0], client, LM80_REG_FAN_MIN(1));
+		safe_lm80_read_value(data->fan[1], client, LM80_REG_FAN2);
+		safe_lm80_read_value(data->fan_min[1], client, LM80_REG_FAN_MIN(2));
+
+		safe_lm80_read_value(tmp1, client, LM80_REG_TEMP);
+		safe_lm80_read_value(tmp2, client, LM80_REG_RES);
+		data->temp = (tmp1 << 8) | (tmp2 ^ 0xf0);
+
+		safe_lm80_read_value(data->temp_os_max, client, LM80_REG_TEMP_OS_MAX);
+		safe_lm80_read_value(data->temp_os_hyst, client, LM80_REG_TEMP_OS_HYST);
+		safe_lm80_read_value(data->temp_hot_max, client, LM80_REG_TEMP_HOT_MAX);
+		safe_lm80_read_value(data->temp_hot_hyst, client, LM80_REG_TEMP_HOT_HYST);
+
+		safe_lm80_read_value(i, client, LM80_REG_FANDIV);
 		data->fan_div[0] = (i >> 2) & 0x03;
 		data->fan_div[1] = (i >> 4) & 0x03;
-		data->alarms = lm80_read_value(client, LM80_REG_ALARM1) +
-		    (lm80_read_value(client, LM80_REG_ALARM2) << 8);
+		safe_lm80_read_value(tmp1, client, LM80_REG_ALARM1);
+		safe_lm80_read_value(tmp2, client, LM80_REG_ALARM2);
+		data->alarms = tmp1 + (tmp2 << 8);
 		data->last_updated = jiffies;
 		data->valid = 1;
 	}
 
+abort:
 	mutex_unlock(&data->update_lock);
-
-	return data;
+	return ret;
 }
 
 static int __init sensors_lm80_init(void)
-- 
1.7.0.4


_______________________________________________
lm-sensors mailing list
lm-sensors@xxxxxxxxxxxxxx
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors


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

  Powered by Linux