diff options
Diffstat (limited to 'drivers/hwmon/lm90.c')
-rw-r--r-- | drivers/hwmon/lm90.c | 89 |
1 files changed, 84 insertions, 5 deletions
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 7c9bdc167426..7cc2708871ab 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * lm90.c - Part of lm_sensors, Linux kernel modules for hardware | 2 | * lm90.c - Part of lm_sensors, Linux kernel modules for hardware |
3 | * monitoring | 3 | * monitoring |
4 | * Copyright (C) 2003-2009 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org> |
5 | * | 5 | * |
6 | * Based on the lm83 driver. The LM90 is a sensor chip made by National | 6 | * Based on the lm83 driver. The LM90 is a sensor chip made by National |
7 | * Semiconductor. It reports up to two temperatures (its own plus up to | 7 | * Semiconductor. It reports up to two temperatures (its own plus up to |
@@ -93,7 +93,8 @@ | |||
93 | static const unsigned short normal_i2c[] = { | 93 | static const unsigned short normal_i2c[] = { |
94 | 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; | 94 | 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; |
95 | 95 | ||
96 | enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646 }; | 96 | enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646, |
97 | w83l771 }; | ||
97 | 98 | ||
98 | /* | 99 | /* |
99 | * The LM90 registers | 100 | * The LM90 registers |
@@ -151,6 +152,7 @@ static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info); | |||
151 | static int lm90_probe(struct i2c_client *client, | 152 | static int lm90_probe(struct i2c_client *client, |
152 | const struct i2c_device_id *id); | 153 | const struct i2c_device_id *id); |
153 | 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); | ||
154 | static int lm90_remove(struct i2c_client *client); | 156 | static int lm90_remove(struct i2c_client *client); |
155 | static struct lm90_data *lm90_update_device(struct device *dev); | 157 | static struct lm90_data *lm90_update_device(struct device *dev); |
156 | 158 | ||
@@ -173,6 +175,7 @@ static const struct i2c_device_id lm90_id[] = { | |||
173 | { "max6659", max6657 }, | 175 | { "max6659", max6657 }, |
174 | { "max6680", max6680 }, | 176 | { "max6680", max6680 }, |
175 | { "max6681", max6680 }, | 177 | { "max6681", max6680 }, |
178 | { "w83l771", w83l771 }, | ||
176 | { } | 179 | { } |
177 | }; | 180 | }; |
178 | MODULE_DEVICE_TABLE(i2c, lm90_id); | 181 | MODULE_DEVICE_TABLE(i2c, lm90_id); |
@@ -184,6 +187,7 @@ static struct i2c_driver lm90_driver = { | |||
184 | }, | 187 | }, |
185 | .probe = lm90_probe, | 188 | .probe = lm90_probe, |
186 | .remove = lm90_remove, | 189 | .remove = lm90_remove, |
190 | .alert = lm90_alert, | ||
187 | .id_table = lm90_id, | 191 | .id_table = lm90_id, |
188 | .detect = lm90_detect, | 192 | .detect = lm90_detect, |
189 | .address_list = normal_i2c, | 193 | .address_list = normal_i2c, |
@@ -201,6 +205,9 @@ struct lm90_data { | |||
201 | int kind; | 205 | int kind; |
202 | int flags; | 206 | int flags; |
203 | 207 | ||
208 | u8 config_orig; /* Original configuration register value */ | ||
209 | u8 alert_alarms; /* Which alarm bits trigger ALERT# */ | ||
210 | |||
204 | /* registers values */ | 211 | /* registers values */ |
205 | s8 temp8[4]; /* 0: local low limit | 212 | s8 temp8[4]; /* 0: local low limit |
206 | 1: local high limit | 213 | 1: local high limit |
@@ -758,6 +765,14 @@ static int lm90_detect(struct i2c_client *new_client, | |||
758 | && reg_convrate <= 0x07) { | 765 | && reg_convrate <= 0x07) { |
759 | name = "max6646"; | 766 | name = "max6646"; |
760 | } | 767 | } |
768 | } else | ||
769 | if (address == 0x4C | ||
770 | && man_id == 0x5C) { /* Winbond/Nuvoton */ | ||
771 | if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */ | ||
772 | && (reg_config1 & 0x2A) == 0x00 | ||
773 | && reg_convrate <= 0x08) { | ||
774 | name = "w83l771"; | ||
775 | } | ||
761 | } | 776 | } |
762 | 777 | ||
763 | if (!name) { /* identification failed */ | 778 | if (!name) { /* identification failed */ |
@@ -794,6 +809,19 @@ static int lm90_probe(struct i2c_client *new_client, | |||
794 | new_client->flags &= ~I2C_CLIENT_PEC; | 809 | new_client->flags &= ~I2C_CLIENT_PEC; |
795 | } | 810 | } |
796 | 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 | |||
797 | /* Initialize the LM90 chip */ | 825 | /* Initialize the LM90 chip */ |
798 | lm90_init_client(new_client); | 826 | lm90_init_client(new_client); |
799 | 827 | ||
@@ -830,7 +858,7 @@ exit: | |||
830 | 858 | ||
831 | static void lm90_init_client(struct i2c_client *client) | 859 | static void lm90_init_client(struct i2c_client *client) |
832 | { | 860 | { |
833 | u8 config, config_orig; | 861 | u8 config; |
834 | struct lm90_data *data = i2c_get_clientdata(client); | 862 | struct lm90_data *data = i2c_get_clientdata(client); |
835 | 863 | ||
836 | /* | 864 | /* |
@@ -842,7 +870,7 @@ static void lm90_init_client(struct i2c_client *client) | |||
842 | dev_warn(&client->dev, "Initialization failed!\n"); | 870 | dev_warn(&client->dev, "Initialization failed!\n"); |
843 | return; | 871 | return; |
844 | } | 872 | } |
845 | config_orig = config; | 873 | data->config_orig = config; |
846 | 874 | ||
847 | /* Check Temperature Range Select */ | 875 | /* Check Temperature Range Select */ |
848 | if (data->kind == adt7461) { | 876 | if (data->kind == adt7461) { |
@@ -860,7 +888,7 @@ static void lm90_init_client(struct i2c_client *client) | |||
860 | } | 888 | } |
861 | 889 | ||
862 | config &= 0xBF; /* run */ | 890 | config &= 0xBF; /* run */ |
863 | if (config != config_orig) /* Only write if changed */ | 891 | if (config != data->config_orig) /* Only write if changed */ |
864 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); | 892 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); |
865 | } | 893 | } |
866 | 894 | ||
@@ -875,10 +903,46 @@ static int lm90_remove(struct i2c_client *client) | |||
875 | device_remove_file(&client->dev, | 903 | device_remove_file(&client->dev, |
876 | &sensor_dev_attr_temp2_offset.dev_attr); | 904 | &sensor_dev_attr_temp2_offset.dev_attr); |
877 | 905 | ||
906 | /* Restore initial configuration */ | ||
907 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, | ||
908 | data->config_orig); | ||
909 | |||
878 | kfree(data); | 910 | kfree(data); |
879 | return 0; | 911 | return 0; |
880 | } | 912 | } |
881 | 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 | |||
882 | 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) |
883 | { | 947 | { |
884 | int err; | 948 | int err; |
@@ -966,6 +1030,21 @@ static struct lm90_data *lm90_update_device(struct device *dev) | |||
966 | } | 1030 | } |
967 | lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); | 1031 | lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); |
968 | 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 | |||
969 | data->last_updated = jiffies; | 1048 | data->last_updated = jiffies; |
970 | data->valid = 1; | 1049 | data->valid = 1; |
971 | } | 1050 | } |