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