summaryrefslogtreecommitdiff
path: root/drivers/hwmon/tmp421.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/tmp421.c')
-rw-r--r--drivers/hwmon/tmp421.c71
1 files changed, 39 insertions, 32 deletions
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
index ede66ea6a730..b963a369c5ab 100644
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -100,71 +100,81 @@ struct tmp421_data {
s16 temp[4];
};
-static int temp_from_s16(s16 reg)
+static int temp_from_raw(u16 reg, bool extended)
{
/* Mask out status bits */
int temp = reg & ~0xf;
- return (temp * 1000 + 128) / 256;
-}
-
-static int temp_from_u16(u16 reg)
-{
- /* Mask out status bits */
- int temp = reg & ~0xf;
-
- /* Add offset for extended temperature range. */
- temp -= 64 * 256;
+ if (extended)
+ temp = temp - 64 * 256;
+ else
+ temp = (s16)temp;
- return (temp * 1000 + 128) / 256;
+ return DIV_ROUND_CLOSEST(temp * 1000, 256);
}
-static struct tmp421_data *tmp421_update_device(struct device *dev)
+static int tmp421_update_device(struct tmp421_data *data)
{
- struct tmp421_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
+ int ret = 0;
int i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + (HZ / 2)) ||
!data->valid) {
- data->config = i2c_smbus_read_byte_data(client,
- TMP421_CONFIG_REG_1);
+ ret = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
+ if (ret < 0)
+ goto exit;
+ data->config = ret;
for (i = 0; i < data->channels; i++) {
- data->temp[i] = i2c_smbus_read_byte_data(client,
- TMP421_TEMP_MSB[i]) << 8;
- data->temp[i] |= i2c_smbus_read_byte_data(client,
- TMP421_TEMP_LSB[i]);
+ ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_MSB[i]);
+ if (ret < 0)
+ goto exit;
+ data->temp[i] = ret << 8;
+
+ ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_LSB[i]);
+ if (ret < 0)
+ goto exit;
+ data->temp[i] |= ret;
}
data->last_updated = jiffies;
data->valid = 1;
}
+exit:
mutex_unlock(&data->update_lock);
- return data;
+ if (ret < 0) {
+ data->valid = 0;
+ return ret;
+ }
+
+ return 0;
}
static int tmp421_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
- struct tmp421_data *tmp421 = tmp421_update_device(dev);
+ struct tmp421_data *tmp421 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = tmp421_update_device(tmp421);
+ if (ret)
+ return ret;
switch (attr) {
case hwmon_temp_input:
- if (tmp421->config & TMP421_CONFIG_RANGE)
- *val = temp_from_u16(tmp421->temp[channel]);
- else
- *val = temp_from_s16(tmp421->temp[channel]);
+ *val = temp_from_raw(tmp421->temp[channel],
+ tmp421->config & TMP421_CONFIG_RANGE);
return 0;
case hwmon_temp_fault:
/*
- * The OPEN bit signals a fault. This is bit 0 of the temperature
- * register (low byte).
+ * Any of OPEN or /PVLD bits indicate a hardware mulfunction
+ * and the conversion result may be incorrect
*/
- *val = tmp421->temp[channel] & 0x01;
+ *val = !!(tmp421->temp[channel] & 0x03);
return 0;
default:
return -EOPNOTSUPP;
@@ -177,9 +187,6 @@ static umode_t tmp421_is_visible(const void *data, enum hwmon_sensor_types type,
{
switch (attr) {
case hwmon_temp_fault:
- if (channel == 0)
- return 0;
- return 0444;
case hwmon_temp_input:
return 0444;
default: