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 | |||
173 | other second; reading them more often will do no harm, but will return | 173 | other second; reading them more often will do no harm, but will return |
174 | 'old' values. | 174 | 'old' values. |
175 | 175 | ||
176 | SMBus Alert Support | ||
177 | ------------------- | ||
178 | |||
179 | This driver has basic support for SMBus alert. When an alert is received, | ||
180 | the status register is read and the faulty temperature channel is logged. | ||
181 | |||
182 | The Analog Devices chips (ADM1032 and ADT7461) do not implement the SMBus | ||
183 | alert protocol properly so additional care is needed: the ALERT output is | ||
184 | disabled when an alert is received, and is re-enabled only when the alarm | ||
185 | is gone. Otherwise the chip would block alerts from other chips in the bus | ||
186 | as long as the alarm is active. | ||
187 | |||
176 | PEC Support | 188 | PEC Support |
177 | ----------- | 189 | ----------- |
178 | 190 | ||
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); | |||
152 | static int lm90_probe(struct i2c_client *client, | 152 | static int lm90_probe(struct i2c_client *client, |
153 | const struct i2c_device_id *id); | 153 | const struct i2c_device_id *id); |
154 | static void lm90_init_client(struct i2c_client *client); | 154 | static void lm90_init_client(struct i2c_client *client); |
155 | static void lm90_alert(struct i2c_client *client, unsigned int flag); | ||
155 | static int lm90_remove(struct i2c_client *client); | 156 | static int lm90_remove(struct i2c_client *client); |
156 | static struct lm90_data *lm90_update_device(struct device *dev); | 157 | static struct lm90_data *lm90_update_device(struct device *dev); |
157 | 158 | ||
@@ -186,6 +187,7 @@ static struct i2c_driver lm90_driver = { | |||
186 | }, | 187 | }, |
187 | .probe = lm90_probe, | 188 | .probe = lm90_probe, |
188 | .remove = lm90_remove, | 189 | .remove = lm90_remove, |
190 | .alert = lm90_alert, | ||
189 | .id_table = lm90_id, | 191 | .id_table = lm90_id, |
190 | .detect = lm90_detect, | 192 | .detect = lm90_detect, |
191 | .address_list = normal_i2c, | 193 | .address_list = normal_i2c, |
@@ -204,6 +206,7 @@ struct lm90_data { | |||
204 | int flags; | 206 | int flags; |
205 | 207 | ||
206 | u8 config_orig; /* Original configuration register value */ | 208 | u8 config_orig; /* Original configuration register value */ |
209 | u8 alert_alarms; /* Which alarm bits trigger ALERT# */ | ||
207 | 210 | ||
208 | /* registers values */ | 211 | /* registers values */ |
209 | s8 temp8[4]; /* 0: local low limit | 212 | s8 temp8[4]; /* 0: local low limit |
@@ -806,6 +809,19 @@ static int lm90_probe(struct i2c_client *new_client, | |||
806 | new_client->flags &= ~I2C_CLIENT_PEC; | 809 | new_client->flags &= ~I2C_CLIENT_PEC; |
807 | } | 810 | } |
808 | 811 | ||
812 | /* Different devices have different alarm bits triggering the | ||
813 | * ALERT# output */ | ||
814 | switch (data->kind) { | ||
815 | case lm90: | ||
816 | case lm99: | ||
817 | case lm86: | ||
818 | data->alert_alarms = 0x7b; | ||
819 | break; | ||
820 | default: | ||
821 | data->alert_alarms = 0x7c; | ||
822 | break; | ||
823 | } | ||
824 | |||
809 | /* Initialize the LM90 chip */ | 825 | /* Initialize the LM90 chip */ |
810 | lm90_init_client(new_client); | 826 | lm90_init_client(new_client); |
811 | 827 | ||
@@ -895,6 +911,38 @@ static int lm90_remove(struct i2c_client *client) | |||
895 | return 0; | 911 | return 0; |
896 | } | 912 | } |
897 | 913 | ||
914 | static void lm90_alert(struct i2c_client *client, unsigned int flag) | ||
915 | { | ||
916 | struct lm90_data *data = i2c_get_clientdata(client); | ||
917 | u8 config, alarms; | ||
918 | |||
919 | lm90_read_reg(client, LM90_REG_R_STATUS, &alarms); | ||
920 | if ((alarms & 0x7f) == 0) { | ||
921 | dev_info(&client->dev, "Everything OK\n"); | ||
922 | } else { | ||
923 | if (alarms & 0x61) | ||
924 | dev_warn(&client->dev, | ||
925 | "temp%d out of range, please check!\n", 1); | ||
926 | if (alarms & 0x1a) | ||
927 | dev_warn(&client->dev, | ||
928 | "temp%d out of range, please check!\n", 2); | ||
929 | if (alarms & 0x04) | ||
930 | dev_warn(&client->dev, | ||
931 | "temp%d diode open, please check!\n", 2); | ||
932 | |||
933 | /* Disable ALERT# output, because these chips don't implement | ||
934 | SMBus alert correctly; they should only hold the alert line | ||
935 | low briefly. */ | ||
936 | if ((data->kind == adm1032 || data->kind == adt7461) | ||
937 | && (alarms & data->alert_alarms)) { | ||
938 | dev_dbg(&client->dev, "Disabling ALERT#\n"); | ||
939 | lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); | ||
940 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, | ||
941 | config | 0x80); | ||
942 | } | ||
943 | } | ||
944 | } | ||
945 | |||
898 | static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value) | 946 | static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value) |
899 | { | 947 | { |
900 | int err; | 948 | int err; |
@@ -982,6 +1030,21 @@ static struct lm90_data *lm90_update_device(struct device *dev) | |||
982 | } | 1030 | } |
983 | lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); | 1031 | lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); |
984 | 1032 | ||
1033 | /* Re-enable ALERT# output if it was originally enabled and | ||
1034 | * relevant alarms are all clear */ | ||
1035 | if ((data->config_orig & 0x80) == 0 | ||
1036 | && (data->alarms & data->alert_alarms) == 0) { | ||
1037 | u8 config; | ||
1038 | |||
1039 | lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); | ||
1040 | if (config & 0x80) { | ||
1041 | dev_dbg(&client->dev, "Re-enabling ALERT#\n"); | ||
1042 | i2c_smbus_write_byte_data(client, | ||
1043 | LM90_REG_W_CONFIG1, | ||
1044 | config & ~0x80); | ||
1045 | } | ||
1046 | } | ||
1047 | |||
985 | data->last_updated = jiffies; | 1048 | data->last_updated = jiffies; |
986 | data->valid = 1; | 1049 | data->valid = 1; |
987 | } | 1050 | } |