diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hwmon/Kconfig | 4 | ||||
-rw-r--r-- | drivers/hwmon/it87.c | 178 |
2 files changed, 156 insertions, 26 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 0e31a0c496e8..cefb1adf4534 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -186,8 +186,8 @@ config SENSORS_IT87 | |||
186 | select I2C_ISA | 186 | select I2C_ISA |
187 | select HWMON_VID | 187 | select HWMON_VID |
188 | help | 188 | help |
189 | If you say yes here you get support for ITE IT87xx sensor chips | 189 | If you say yes here you get support for ITE IT8705F, IT8712F and |
190 | and clones: SiS960. | 190 | IT8716F sensor chips, and the SiS960 clone. |
191 | 191 | ||
192 | This driver can also be built as a module. If so, the module | 192 | This driver can also be built as a module. If so, the module |
193 | will be called it87. | 193 | will be called it87. |
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index b0ee57492228..e7f14e61d6f2 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | Supports: IT8705F Super I/O chip w/LPC interface | 5 | Supports: IT8705F Super I/O chip w/LPC interface |
6 | IT8712F Super I/O chip w/LPC interface & SMBus | 6 | IT8712F Super I/O chip w/LPC interface & SMBus |
7 | IT8716F Super I/O chip w/LPC interface | ||
7 | Sis950 A clone of the IT8705F | 8 | Sis950 A clone of the IT8705F |
8 | 9 | ||
9 | Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com> | 10 | Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com> |
@@ -50,7 +51,7 @@ static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END }; | |||
50 | static unsigned short isa_address; | 51 | static unsigned short isa_address; |
51 | 52 | ||
52 | /* Insmod parameters */ | 53 | /* Insmod parameters */ |
53 | I2C_CLIENT_INSMOD_2(it87, it8712); | 54 | I2C_CLIENT_INSMOD_3(it87, it8712, it8716); |
54 | 55 | ||
55 | #define REG 0x2e /* The register to read/write */ | 56 | #define REG 0x2e /* The register to read/write */ |
56 | #define DEV 0x07 /* Register: Logical device select */ | 57 | #define DEV 0x07 /* Register: Logical device select */ |
@@ -101,6 +102,7 @@ superio_exit(void) | |||
101 | 102 | ||
102 | #define IT8712F_DEVID 0x8712 | 103 | #define IT8712F_DEVID 0x8712 |
103 | #define IT8705F_DEVID 0x8705 | 104 | #define IT8705F_DEVID 0x8705 |
105 | #define IT8716F_DEVID 0x8716 | ||
104 | #define IT87_ACT_REG 0x30 | 106 | #define IT87_ACT_REG 0x30 |
105 | #define IT87_BASE_REG 0x60 | 107 | #define IT87_BASE_REG 0x60 |
106 | 108 | ||
@@ -132,12 +134,18 @@ static u16 chip_type; | |||
132 | #define IT87_REG_ALARM3 0x03 | 134 | #define IT87_REG_ALARM3 0x03 |
133 | 135 | ||
134 | #define IT87_REG_VID 0x0a | 136 | #define IT87_REG_VID 0x0a |
137 | /* Warning: register 0x0b is used for something completely different in | ||
138 | new chips/revisions. I suspect only 16-bit tachometer mode will work | ||
139 | for these. */ | ||
135 | #define IT87_REG_FAN_DIV 0x0b | 140 | #define IT87_REG_FAN_DIV 0x0b |
141 | #define IT87_REG_FAN_16BIT 0x0c | ||
136 | 142 | ||
137 | /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ | 143 | /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ |
138 | 144 | ||
139 | #define IT87_REG_FAN(nr) (0x0d + (nr)) | 145 | #define IT87_REG_FAN(nr) (0x0d + (nr)) |
140 | #define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) | 146 | #define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) |
147 | #define IT87_REG_FANX(nr) (0x18 + (nr)) | ||
148 | #define IT87_REG_FANX_MIN(nr) (0x1b + (nr)) | ||
141 | #define IT87_REG_FAN_MAIN_CTRL 0x13 | 149 | #define IT87_REG_FAN_MAIN_CTRL 0x13 |
142 | #define IT87_REG_FAN_CTL 0x14 | 150 | #define IT87_REG_FAN_CTL 0x14 |
143 | #define IT87_REG_PWM(nr) (0x15 + (nr)) | 151 | #define IT87_REG_PWM(nr) (0x15 + (nr)) |
@@ -169,7 +177,16 @@ static inline u8 FAN_TO_REG(long rpm, int div) | |||
169 | 254); | 177 | 254); |
170 | } | 178 | } |
171 | 179 | ||
180 | static inline u16 FAN16_TO_REG(long rpm) | ||
181 | { | ||
182 | if (rpm == 0) | ||
183 | return 0xffff; | ||
184 | return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe); | ||
185 | } | ||
186 | |||
172 | #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) | 187 | #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) |
188 | /* The divider is fixed to 2 in 16-bit mode */ | ||
189 | #define FAN16_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:1350000/((val)*2)) | ||
173 | 190 | ||
174 | #define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\ | 191 | #define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\ |
175 | ((val)+500)/1000),-128,127)) | 192 | ((val)+500)/1000),-128,127)) |
@@ -205,8 +222,8 @@ struct it87_data { | |||
205 | u8 in[9]; /* Register value */ | 222 | u8 in[9]; /* Register value */ |
206 | u8 in_max[9]; /* Register value */ | 223 | u8 in_max[9]; /* Register value */ |
207 | u8 in_min[9]; /* Register value */ | 224 | u8 in_min[9]; /* Register value */ |
208 | u8 fan[3]; /* Register value */ | 225 | u16 fan[3]; /* Register values, possibly combined */ |
209 | u8 fan_min[3]; /* Register value */ | 226 | u16 fan_min[3]; /* Register values, possibly combined */ |
210 | u8 temp[3]; /* Register value */ | 227 | u8 temp[3]; /* Register value */ |
211 | u8 temp_high[3]; /* Register value */ | 228 | u8 temp_high[3]; /* Register value */ |
212 | u8 temp_low[3]; /* Register value */ | 229 | u8 temp_low[3]; /* Register value */ |
@@ -657,6 +674,59 @@ show_pwm_offset(1); | |||
657 | show_pwm_offset(2); | 674 | show_pwm_offset(2); |
658 | show_pwm_offset(3); | 675 | show_pwm_offset(3); |
659 | 676 | ||
677 | /* A different set of callbacks for 16-bit fans */ | ||
678 | static ssize_t show_fan16(struct device *dev, struct device_attribute *attr, | ||
679 | char *buf) | ||
680 | { | ||
681 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
682 | int nr = sensor_attr->index; | ||
683 | struct it87_data *data = it87_update_device(dev); | ||
684 | return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr])); | ||
685 | } | ||
686 | |||
687 | static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr, | ||
688 | char *buf) | ||
689 | { | ||
690 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
691 | int nr = sensor_attr->index; | ||
692 | struct it87_data *data = it87_update_device(dev); | ||
693 | return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr])); | ||
694 | } | ||
695 | |||
696 | static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr, | ||
697 | const char *buf, size_t count) | ||
698 | { | ||
699 | struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); | ||
700 | int nr = sensor_attr->index; | ||
701 | struct i2c_client *client = to_i2c_client(dev); | ||
702 | struct it87_data *data = i2c_get_clientdata(client); | ||
703 | int val = simple_strtol(buf, NULL, 10); | ||
704 | |||
705 | mutex_lock(&data->update_lock); | ||
706 | data->fan_min[nr] = FAN16_TO_REG(val); | ||
707 | it87_write_value(client, IT87_REG_FAN_MIN(nr), | ||
708 | data->fan_min[nr] & 0xff); | ||
709 | it87_write_value(client, IT87_REG_FANX_MIN(nr), | ||
710 | data->fan_min[nr] >> 8); | ||
711 | mutex_unlock(&data->update_lock); | ||
712 | return count; | ||
713 | } | ||
714 | |||
715 | /* We want to use the same sysfs file names as 8-bit fans, but we need | ||
716 | different variable names, so we have to use SENSOR_ATTR instead of | ||
717 | SENSOR_DEVICE_ATTR. */ | ||
718 | #define show_fan16_offset(offset) \ | ||
719 | static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \ | ||
720 | = SENSOR_ATTR(fan##offset##_input, S_IRUGO, \ | ||
721 | show_fan16, NULL, offset - 1); \ | ||
722 | static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \ | ||
723 | = SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ | ||
724 | show_fan16_min, set_fan16_min, offset - 1) | ||
725 | |||
726 | show_fan16_offset(1); | ||
727 | show_fan16_offset(2); | ||
728 | show_fan16_offset(3); | ||
729 | |||
660 | /* Alarms */ | 730 | /* Alarms */ |
661 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) | 731 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) |
662 | { | 732 | { |
@@ -721,6 +791,7 @@ static int __init it87_find(unsigned short *address) | |||
721 | superio_enter(); | 791 | superio_enter(); |
722 | chip_type = superio_inw(DEVID); | 792 | chip_type = superio_inw(DEVID); |
723 | if (chip_type != IT8712F_DEVID | 793 | if (chip_type != IT8712F_DEVID |
794 | && chip_type != IT8716F_DEVID | ||
724 | && chip_type != IT8705F_DEVID) | 795 | && chip_type != IT8705F_DEVID) |
725 | goto exit; | 796 | goto exit; |
726 | 797 | ||
@@ -800,8 +871,16 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) | |||
800 | i = it87_read_value(new_client, IT87_REG_CHIPID); | 871 | i = it87_read_value(new_client, IT87_REG_CHIPID); |
801 | if (i == 0x90) { | 872 | if (i == 0x90) { |
802 | kind = it87; | 873 | kind = it87; |
803 | if ((is_isa) && (chip_type == IT8712F_DEVID)) | 874 | if (is_isa) { |
804 | kind = it8712; | 875 | switch (chip_type) { |
876 | case IT8712F_DEVID: | ||
877 | kind = it8712; | ||
878 | break; | ||
879 | case IT8716F_DEVID: | ||
880 | kind = it8716; | ||
881 | break; | ||
882 | } | ||
883 | } | ||
805 | } | 884 | } |
806 | else { | 885 | else { |
807 | if (kind == 0) | 886 | if (kind == 0) |
@@ -818,6 +897,8 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) | |||
818 | name = "it87"; | 897 | name = "it87"; |
819 | } else if (kind == it8712) { | 898 | } else if (kind == it8712) { |
820 | name = "it8712"; | 899 | name = "it8712"; |
900 | } else if (kind == it8716) { | ||
901 | name = "it8716"; | ||
821 | } | 902 | } |
822 | 903 | ||
823 | /* Fill in the remaining client fields and put it into the global list */ | 904 | /* Fill in the remaining client fields and put it into the global list */ |
@@ -885,15 +966,41 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) | |||
885 | device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); | 966 | device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); |
886 | device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); | 967 | device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); |
887 | device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); | 968 | device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); |
888 | device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); | 969 | |
889 | device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); | 970 | if (data->type == it8716) { /* 16-bit tachometers */ |
890 | device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); | 971 | device_create_file(&new_client->dev, |
891 | device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); | 972 | &sensor_dev_attr_fan1_input16.dev_attr); |
892 | device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); | 973 | device_create_file(&new_client->dev, |
893 | device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); | 974 | &sensor_dev_attr_fan2_input16.dev_attr); |
894 | device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); | 975 | device_create_file(&new_client->dev, |
895 | device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); | 976 | &sensor_dev_attr_fan3_input16.dev_attr); |
896 | device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); | 977 | device_create_file(&new_client->dev, |
978 | &sensor_dev_attr_fan1_min16.dev_attr); | ||
979 | device_create_file(&new_client->dev, | ||
980 | &sensor_dev_attr_fan2_min16.dev_attr); | ||
981 | device_create_file(&new_client->dev, | ||
982 | &sensor_dev_attr_fan3_min16.dev_attr); | ||
983 | } else { | ||
984 | device_create_file(&new_client->dev, | ||
985 | &sensor_dev_attr_fan1_input.dev_attr); | ||
986 | device_create_file(&new_client->dev, | ||
987 | &sensor_dev_attr_fan2_input.dev_attr); | ||
988 | device_create_file(&new_client->dev, | ||
989 | &sensor_dev_attr_fan3_input.dev_attr); | ||
990 | device_create_file(&new_client->dev, | ||
991 | &sensor_dev_attr_fan1_min.dev_attr); | ||
992 | device_create_file(&new_client->dev, | ||
993 | &sensor_dev_attr_fan2_min.dev_attr); | ||
994 | device_create_file(&new_client->dev, | ||
995 | &sensor_dev_attr_fan3_min.dev_attr); | ||
996 | device_create_file(&new_client->dev, | ||
997 | &sensor_dev_attr_fan1_div.dev_attr); | ||
998 | device_create_file(&new_client->dev, | ||
999 | &sensor_dev_attr_fan2_div.dev_attr); | ||
1000 | device_create_file(&new_client->dev, | ||
1001 | &sensor_dev_attr_fan3_div.dev_attr); | ||
1002 | } | ||
1003 | |||
897 | device_create_file(&new_client->dev, &dev_attr_alarms); | 1004 | device_create_file(&new_client->dev, &dev_attr_alarms); |
898 | if (enable_pwm_interface) { | 1005 | if (enable_pwm_interface) { |
899 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); | 1006 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); |
@@ -904,7 +1011,7 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) | |||
904 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); | 1011 | device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); |
905 | } | 1012 | } |
906 | 1013 | ||
907 | if (data->type == it8712) { | 1014 | if (data->type == it8712 || data->type == it8716) { |
908 | data->vrm = vid_which_vrm(); | 1015 | data->vrm = vid_which_vrm(); |
909 | device_create_file_vrm(new_client); | 1016 | device_create_file_vrm(new_client); |
910 | device_create_file_vid(new_client); | 1017 | device_create_file_vid(new_client); |
@@ -1069,6 +1176,17 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data) | |||
1069 | it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); | 1176 | it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); |
1070 | } | 1177 | } |
1071 | 1178 | ||
1179 | /* Set tachometers to 16-bit mode if needed */ | ||
1180 | if (data->type == it8716) { | ||
1181 | tmp = it87_read_value(client, IT87_REG_FAN_16BIT); | ||
1182 | if ((tmp & 0x07) != 0x07) { | ||
1183 | dev_dbg(&client->dev, | ||
1184 | "Setting fan1-3 to 16-bit mode\n"); | ||
1185 | it87_write_value(client, IT87_REG_FAN_16BIT, | ||
1186 | tmp | 0x07); | ||
1187 | } | ||
1188 | } | ||
1189 | |||
1072 | /* Set current fan mode registers and the default settings for the | 1190 | /* Set current fan mode registers and the default settings for the |
1073 | * other mode registers */ | 1191 | * other mode registers */ |
1074 | for (i = 0; i < 3; i++) { | 1192 | for (i = 0; i < 3; i++) { |
@@ -1126,10 +1244,17 @@ static struct it87_data *it87_update_device(struct device *dev) | |||
1126 | data->in_max[8] = 255; | 1244 | data->in_max[8] = 255; |
1127 | 1245 | ||
1128 | for (i = 0; i < 3; i++) { | 1246 | for (i = 0; i < 3; i++) { |
1129 | data->fan[i] = | ||
1130 | it87_read_value(client, IT87_REG_FAN(i)); | ||
1131 | data->fan_min[i] = | 1247 | data->fan_min[i] = |
1132 | it87_read_value(client, IT87_REG_FAN_MIN(i)); | 1248 | it87_read_value(client, IT87_REG_FAN_MIN(i)); |
1249 | data->fan[i] = it87_read_value(client, | ||
1250 | IT87_REG_FAN(i)); | ||
1251 | /* Add high byte if in 16-bit mode */ | ||
1252 | if (data->type == it8716) { | ||
1253 | data->fan[i] |= it87_read_value(client, | ||
1254 | IT87_REG_FANX(i)) << 8; | ||
1255 | data->fan_min[i] |= it87_read_value(client, | ||
1256 | IT87_REG_FANX_MIN(i)) << 8; | ||
1257 | } | ||
1133 | } | 1258 | } |
1134 | for (i = 0; i < 3; i++) { | 1259 | for (i = 0; i < 3; i++) { |
1135 | data->temp[i] = | 1260 | data->temp[i] = |
@@ -1140,10 +1265,13 @@ static struct it87_data *it87_update_device(struct device *dev) | |||
1140 | it87_read_value(client, IT87_REG_TEMP_LOW(i)); | 1265 | it87_read_value(client, IT87_REG_TEMP_LOW(i)); |
1141 | } | 1266 | } |
1142 | 1267 | ||
1143 | i = it87_read_value(client, IT87_REG_FAN_DIV); | 1268 | /* Newer chips don't have clock dividers */ |
1144 | data->fan_div[0] = i & 0x07; | 1269 | if (data->type != it8716) { |
1145 | data->fan_div[1] = (i >> 3) & 0x07; | 1270 | i = it87_read_value(client, IT87_REG_FAN_DIV); |
1146 | data->fan_div[2] = (i & 0x40) ? 3 : 1; | 1271 | data->fan_div[0] = i & 0x07; |
1272 | data->fan_div[1] = (i >> 3) & 0x07; | ||
1273 | data->fan_div[2] = (i & 0x40) ? 3 : 1; | ||
1274 | } | ||
1147 | 1275 | ||
1148 | data->alarms = | 1276 | data->alarms = |
1149 | it87_read_value(client, IT87_REG_ALARM1) | | 1277 | it87_read_value(client, IT87_REG_ALARM1) | |
@@ -1153,9 +1281,11 @@ static struct it87_data *it87_update_device(struct device *dev) | |||
1153 | 1281 | ||
1154 | data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); | 1282 | data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); |
1155 | /* The 8705 does not have VID capability */ | 1283 | /* The 8705 does not have VID capability */ |
1156 | if (data->type == it8712) { | 1284 | if (data->type == it8712 || data->type == it8716) { |
1157 | data->vid = it87_read_value(client, IT87_REG_VID); | 1285 | data->vid = it87_read_value(client, IT87_REG_VID); |
1158 | data->vid &= 0x1f; | 1286 | /* The older IT8712F revisions had only 5 VID pins, |
1287 | but we assume it is always safe to read 6 bits. */ | ||
1288 | data->vid &= 0x3f; | ||
1159 | } | 1289 | } |
1160 | data->last_updated = jiffies; | 1290 | data->last_updated = jiffies; |
1161 | data->valid = 1; | 1291 | data->valid = 1; |
@@ -1194,7 +1324,7 @@ static void __exit sm_it87_exit(void) | |||
1194 | 1324 | ||
1195 | 1325 | ||
1196 | MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>"); | 1326 | MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>"); |
1197 | MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); | 1327 | MODULE_DESCRIPTION("IT8705F/8712F/8716F, SiS950 driver"); |
1198 | module_param(update_vbat, bool, 0); | 1328 | module_param(update_vbat, bool, 0); |
1199 | MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); | 1329 | MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); |
1200 | module_param(fix_pwm_polarity, bool, 0); | 1330 | module_param(fix_pwm_polarity, bool, 0); |