diff options
-rw-r--r-- | Documentation/hwmon/lm90 | 12 | ||||
-rw-r--r-- | drivers/hwmon/lm90.c | 63 |
2 files changed, 75 insertions, 0 deletions
diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index 08106ad7089c..6a03dd4bcc94 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 @@ -173,6 +173,18 @@ The lm90 driver will not update its values more frequently than every other second; reading them more often will do no harm, but will return 'old' values. +SMBus Alert Support +------------------- + +This driver has basic support for SMBus alert. When an alert is received, +the status register is read and the faulty temperature channel is logged. + +The Analog Devices chips (ADM1032 and ADT7461) do not implement the SMBus +alert protocol properly so additional care is needed: the ALERT output is +disabled when an alert is received, and is re-enabled only when the alarm +is gone. Otherwise the chip would block alerts from other chips in the bus +as long as the alarm is active. + PEC Support ----------- diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 4cbbf1563de6..7cc2708871ab 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -152,6 +152,7 @@ static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info); static int lm90_probe(struct i2c_client *client, const struct i2c_device_id *id); static void lm90_init_client(struct i2c_client *client); +static void lm90_alert(struct i2c_client *client, unsigned int flag); static int lm90_remove(struct i2c_client *client); static struct lm90_data *lm90_update_device(struct device *dev); @@ -186,6 +187,7 @@ static struct i2c_driver lm90_driver = { }, .probe = lm90_probe, .remove = lm90_remove, + .alert = lm90_alert, .id_table = lm90_id, .detect = lm90_detect, .address_list = normal_i2c, @@ -204,6 +206,7 @@ struct lm90_data { int flags; u8 config_orig; /* Original configuration register value */ + u8 alert_alarms; /* Which alarm bits trigger ALERT# */ /* registers values */ s8 temp8[4]; /* 0: local low limit @@ -806,6 +809,19 @@ static int lm90_probe(struct i2c_client *new_client, new_client->flags &= ~I2C_CLIENT_PEC; } + /* Different devices have different alarm bits triggering the + * ALERT# output */ + switch (data->kind) { + case lm90: + case lm99: + case lm86: + data->alert_alarms = 0x7b; + break; + default: + data->alert_alarms = 0x7c; + break; + } + /* Initialize the LM90 chip */ lm90_init_client(new_client); @@ -895,6 +911,38 @@ static int lm90_remove(struct i2c_client *client) return 0; } +static void lm90_alert(struct i2c_client *client, unsigned int flag) +{ + struct lm90_data *data = i2c_get_clientdata(client); + u8 config, alarms; + + lm90_read_reg(client, LM90_REG_R_STATUS, &alarms); + if ((alarms & 0x7f) == 0) { + dev_info(&client->dev, "Everything OK\n"); + } else { + if (alarms & 0x61) + dev_warn(&client->dev, + "temp%d out of range, please check!\n", 1); + if (alarms & 0x1a) + dev_warn(&client->dev, + "temp%d out of range, please check!\n", 2); + if (alarms & 0x04) + dev_warn(&client->dev, + "temp%d diode open, please check!\n", 2); + + /* Disable ALERT# output, because these chips don't implement + SMBus alert correctly; they should only hold the alert line + low briefly. */ + if ((data->kind == adm1032 || data->kind == adt7461) + && (alarms & data->alert_alarms)) { + dev_dbg(&client->dev, "Disabling ALERT#\n"); + lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, + config | 0x80); + } + } +} + static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value) { int err; @@ -982,6 +1030,21 @@ static struct lm90_data *lm90_update_device(struct device *dev) } lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); + /* Re-enable ALERT# output if it was originally enabled and + * relevant alarms are all clear */ + if ((data->config_orig & 0x80) == 0 + && (data->alarms & data->alert_alarms) == 0) { + u8 config; + + lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); + if (config & 0x80) { + dev_dbg(&client->dev, "Re-enabling ALERT#\n"); + i2c_smbus_write_byte_data(client, + LM90_REG_W_CONFIG1, + config & ~0x80); + } + } + data->last_updated = jiffies; data->valid = 1; } |