aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/f71805f.c
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2006-12-12 12:18:29 -0500
committerJean Delvare <khali@arrakis.delvare>2006-12-12 12:18:29 -0500
commit51c997d80e1f625aea3426a8a9087f5830ac6db3 (patch)
tree91f3bba2d2c2904276089679bcc9a276ebd1f63f /drivers/hwmon/f71805f.c
parentba224e2c4f0a706714ccb483b0c21d32f5994f67 (diff)
hwmon/f71805f: Add support for the Fintek F71872F/FG chip
Add support for the Fintek F71872F/FG Super-I/O chip. It is basically the same as the Fintek F71805F/FG as far as hardware monitoring is concerned, with two additional internal voltages monitored (VSB and battery), and 6 VID inputs (not yet supported.) To make things a bit more confusing, two of the voltage input pins (in4 and in8) can be used for other functions. The driver reads the pin configuration from the Super-I/O configuration space to decide whether it must create interface files for these inputs or not. Many thanks to Nikolay Derkach for testing the early iterations of this code and reporting bugs. Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/f71805f.c')
-rw-r--r--drivers/hwmon/f71805f.c230
1 files changed, 187 insertions, 43 deletions
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 975c1cc2acf1..ba5e7b70f8cc 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1,12 +1,15 @@
1/* 1/*
2 * f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated 2 * f71805f.c - driver for the Fintek F71805F/FG and F71872F/FG Super-I/O
3 * hardware monitoring features 3 * chips integrated hardware monitoring features
4 * Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org> 4 * Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org>
5 * 5 *
6 * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates 6 * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates
7 * complete hardware monitoring features: voltage, fan and temperature 7 * complete hardware monitoring features: voltage, fan and temperature
8 * sensors, and manual and automatic fan speed control. 8 * sensors, and manual and automatic fan speed control.
9 * 9 *
10 * The F71872F/FG is almost the same, with two more voltages monitored,
11 * and 6 VID inputs.
12 *
10 * This program is free software; you can redistribute it and/or modify 13 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or 15 * the Free Software Foundation; either version 2 of the License, or
@@ -37,6 +40,7 @@
37static struct platform_device *pdev; 40static struct platform_device *pdev;
38 41
39#define DRVNAME "f71805f" 42#define DRVNAME "f71805f"
43enum kinds { f71805f, f71872f };
40 44
41/* 45/*
42 * Super-I/O constants and functions 46 * Super-I/O constants and functions
@@ -48,11 +52,13 @@ static struct platform_device *pdev;
48#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ 52#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
49#define SIO_REG_DEVREV 0x22 /* Device revision */ 53#define SIO_REG_DEVREV 0x22 /* Device revision */
50#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ 54#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
55#define SIO_REG_FNSEL1 0x29 /* Multi Function Select 1 (F71872F) */
51#define SIO_REG_ENABLE 0x30 /* Logical device enable */ 56#define SIO_REG_ENABLE 0x30 /* Logical device enable */
52#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ 57#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
53 58
54#define SIO_FINTEK_ID 0x1934 59#define SIO_FINTEK_ID 0x1934
55#define SIO_F71805F_ID 0x0406 60#define SIO_F71805F_ID 0x0406
61#define SIO_F71872F_ID 0x0341
56 62
57static inline int 63static inline int
58superio_inb(int base, int reg) 64superio_inb(int base, int reg)
@@ -104,10 +110,10 @@ superio_exit(int base)
104 * Registers 110 * Registers
105 */ 111 */
106 112
107/* in nr from 0 to 8 (8-bit values) */ 113/* in nr from 0 to 10 (8-bit values) */
108#define F71805F_REG_IN(nr) (0x10 + (nr)) 114#define F71805F_REG_IN(nr) (0x10 + (nr))
109#define F71805F_REG_IN_HIGH(nr) (0x40 + 2 * (nr)) 115#define F71805F_REG_IN_HIGH(nr) ((nr) < 10 ? 0x40 + 2 * (nr) : 0x2E)
110#define F71805F_REG_IN_LOW(nr) (0x41 + 2 * (nr)) 116#define F71805F_REG_IN_LOW(nr) ((nr) < 10 ? 0x41 + 2 * (nr) : 0x2F)
111/* fan nr from 0 to 2 (12-bit values, two registers) */ 117/* fan nr from 0 to 2 (12-bit values, two registers) */
112#define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) 118#define F71805F_REG_FAN(nr) (0x20 + 2 * (nr))
113#define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) 119#define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr))
@@ -150,9 +156,10 @@ struct f71805f_data {
150 unsigned long last_limits; /* In jiffies */ 156 unsigned long last_limits; /* In jiffies */
151 157
152 /* Register values */ 158 /* Register values */
153 u8 in[9]; 159 u8 in[11];
154 u8 in_high[9]; 160 u8 in_high[11];
155 u8 in_low[9]; 161 u8 in_low[11];
162 u16 has_in;
156 u16 fan[3]; 163 u16 fan[3];
157 u16 fan_low[3]; 164 u16 fan_low[3];
158 u16 fan_target[3]; 165 u16 fan_target[3];
@@ -166,6 +173,11 @@ struct f71805f_data {
166 unsigned long alarms; 173 unsigned long alarms;
167}; 174};
168 175
176struct f71805f_sio_data {
177 enum kinds kind;
178 u8 fnsel1;
179};
180
169static inline long in_from_reg(u8 reg) 181static inline long in_from_reg(u8 reg)
170{ 182{
171 return (reg * 8); 183 return (reg * 8);
@@ -316,7 +328,9 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
316 /* Limit registers cache is refreshed after 60 seconds */ 328 /* Limit registers cache is refreshed after 60 seconds */
317 if (time_after(jiffies, data->last_updated + 60 * HZ) 329 if (time_after(jiffies, data->last_updated + 60 * HZ)
318 || !data->valid) { 330 || !data->valid) {
319 for (nr = 0; nr < 9; nr++) { 331 for (nr = 0; nr < 11; nr++) {
332 if (!(data->has_in & (1 << nr)))
333 continue;
320 data->in_high[nr] = f71805f_read8(data, 334 data->in_high[nr] = f71805f_read8(data,
321 F71805F_REG_IN_HIGH(nr)); 335 F71805F_REG_IN_HIGH(nr));
322 data->in_low[nr] = f71805f_read8(data, 336 data->in_low[nr] = f71805f_read8(data,
@@ -346,7 +360,9 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
346 /* Measurement registers cache is refreshed after 1 second */ 360 /* Measurement registers cache is refreshed after 1 second */
347 if (time_after(jiffies, data->last_updated + HZ) 361 if (time_after(jiffies, data->last_updated + HZ)
348 || !data->valid) { 362 || !data->valid) {
349 for (nr = 0; nr < 9; nr++) { 363 for (nr = 0; nr < 11; nr++) {
364 if (!(data->has_in & (1 << nr)))
365 continue;
350 data->in[nr] = f71805f_read8(data, 366 data->in[nr] = f71805f_read8(data,
351 F71805F_REG_IN(nr)); 367 F71805F_REG_IN(nr));
352 } 368 }
@@ -385,35 +401,43 @@ static ssize_t show_in0(struct device *dev, struct device_attribute *devattr,
385 char *buf) 401 char *buf)
386{ 402{
387 struct f71805f_data *data = f71805f_update_device(dev); 403 struct f71805f_data *data = f71805f_update_device(dev);
404 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
405 int nr = attr->index;
388 406
389 return sprintf(buf, "%ld\n", in0_from_reg(data->in[0])); 407 return sprintf(buf, "%ld\n", in0_from_reg(data->in[nr]));
390} 408}
391 409
392static ssize_t show_in0_max(struct device *dev, struct device_attribute 410static ssize_t show_in0_max(struct device *dev, struct device_attribute
393 *devattr, char *buf) 411 *devattr, char *buf)
394{ 412{
395 struct f71805f_data *data = f71805f_update_device(dev); 413 struct f71805f_data *data = f71805f_update_device(dev);
414 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
415 int nr = attr->index;
396 416
397 return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[0])); 417 return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[nr]));
398} 418}
399 419
400static ssize_t show_in0_min(struct device *dev, struct device_attribute 420static ssize_t show_in0_min(struct device *dev, struct device_attribute
401 *devattr, char *buf) 421 *devattr, char *buf)
402{ 422{
403 struct f71805f_data *data = f71805f_update_device(dev); 423 struct f71805f_data *data = f71805f_update_device(dev);
424 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
425 int nr = attr->index;
404 426
405 return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[0])); 427 return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[nr]));
406} 428}
407 429
408static ssize_t set_in0_max(struct device *dev, struct device_attribute 430static ssize_t set_in0_max(struct device *dev, struct device_attribute
409 *devattr, const char *buf, size_t count) 431 *devattr, const char *buf, size_t count)
410{ 432{
411 struct f71805f_data *data = dev_get_drvdata(dev); 433 struct f71805f_data *data = dev_get_drvdata(dev);
434 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
435 int nr = attr->index;
412 long val = simple_strtol(buf, NULL, 10); 436 long val = simple_strtol(buf, NULL, 10);
413 437
414 mutex_lock(&data->update_lock); 438 mutex_lock(&data->update_lock);
415 data->in_high[0] = in0_to_reg(val); 439 data->in_high[nr] = in0_to_reg(val);
416 f71805f_write8(data, F71805F_REG_IN_HIGH(0), data->in_high[0]); 440 f71805f_write8(data, F71805F_REG_IN_HIGH(nr), data->in_high[nr]);
417 mutex_unlock(&data->update_lock); 441 mutex_unlock(&data->update_lock);
418 442
419 return count; 443 return count;
@@ -423,11 +447,13 @@ static ssize_t set_in0_min(struct device *dev, struct device_attribute
423 *devattr, const char *buf, size_t count) 447 *devattr, const char *buf, size_t count)
424{ 448{
425 struct f71805f_data *data = dev_get_drvdata(dev); 449 struct f71805f_data *data = dev_get_drvdata(dev);
450 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
451 int nr = attr->index;
426 long val = simple_strtol(buf, NULL, 10); 452 long val = simple_strtol(buf, NULL, 10);
427 453
428 mutex_lock(&data->update_lock); 454 mutex_lock(&data->update_lock);
429 data->in_low[0] = in0_to_reg(val); 455 data->in_low[nr] = in0_to_reg(val);
430 f71805f_write8(data, F71805F_REG_IN_LOW(0), data->in_low[0]); 456 f71805f_write8(data, F71805F_REG_IN_LOW(nr), data->in_low[nr]);
431 mutex_unlock(&data->update_lock); 457 mutex_unlock(&data->update_lock);
432 458
433 return count; 459 return count;
@@ -770,7 +796,7 @@ static ssize_t show_alarms_in(struct device *dev, struct device_attribute
770{ 796{
771 struct f71805f_data *data = f71805f_update_device(dev); 797 struct f71805f_data *data = f71805f_update_device(dev);
772 798
773 return sprintf(buf, "%lu\n", data->alarms & 0x1ff); 799 return sprintf(buf, "%lu\n", data->alarms & 0x7ff);
774} 800}
775 801
776static ssize_t show_alarms_fan(struct device *dev, struct device_attribute 802static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
@@ -807,9 +833,11 @@ static ssize_t show_name(struct device *dev, struct device_attribute
807 return sprintf(buf, "%s\n", data->name); 833 return sprintf(buf, "%s\n", data->name);
808} 834}
809 835
810static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL); 836static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL, 0);
811static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max); 837static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR,
812static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min); 838 show_in0_max, set_in0_max, 0);
839static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR,
840 show_in0_min, set_in0_min, 0);
813static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); 841static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
814static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, 842static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR,
815 show_in_max, set_in_max, 1); 843 show_in_max, set_in_max, 1);
@@ -850,6 +878,16 @@ static SENSOR_DEVICE_ATTR(in8_max, S_IRUGO | S_IWUSR,
850 show_in_max, set_in_max, 8); 878 show_in_max, set_in_max, 8);
851static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR, 879static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR,
852 show_in_min, set_in_min, 8); 880 show_in_min, set_in_min, 8);
881static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_in0, NULL, 9);
882static SENSOR_DEVICE_ATTR(in9_max, S_IRUGO | S_IWUSR,
883 show_in0_max, set_in0_max, 9);
884static SENSOR_DEVICE_ATTR(in9_min, S_IRUGO | S_IWUSR,
885 show_in0_min, set_in0_min, 9);
886static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in0, NULL, 10);
887static SENSOR_DEVICE_ATTR(in10_max, S_IRUGO | S_IWUSR,
888 show_in0_max, set_in0_max, 10);
889static SENSOR_DEVICE_ATTR(in10_min, S_IRUGO | S_IWUSR,
890 show_in0_min, set_in0_min, 10);
853 891
854static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); 892static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
855static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, 893static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
@@ -916,6 +954,8 @@ static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
916static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); 954static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
917static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7); 955static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
918static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8); 956static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
957static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9);
958static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10);
919static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11); 959static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11);
920static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12); 960static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12);
921static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); 961static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
@@ -929,9 +969,9 @@ static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL);
929static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 969static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
930 970
931static struct attribute *f71805f_attributes[] = { 971static struct attribute *f71805f_attributes[] = {
932 &dev_attr_in0_input.attr, 972 &sensor_dev_attr_in0_input.dev_attr.attr,
933 &dev_attr_in0_max.attr, 973 &sensor_dev_attr_in0_max.dev_attr.attr,
934 &dev_attr_in0_min.attr, 974 &sensor_dev_attr_in0_min.dev_attr.attr,
935 &sensor_dev_attr_in1_input.dev_attr.attr, 975 &sensor_dev_attr_in1_input.dev_attr.attr,
936 &sensor_dev_attr_in1_max.dev_attr.attr, 976 &sensor_dev_attr_in1_max.dev_attr.attr,
937 &sensor_dev_attr_in1_min.dev_attr.attr, 977 &sensor_dev_attr_in1_min.dev_attr.attr,
@@ -941,9 +981,6 @@ static struct attribute *f71805f_attributes[] = {
941 &sensor_dev_attr_in3_input.dev_attr.attr, 981 &sensor_dev_attr_in3_input.dev_attr.attr,
942 &sensor_dev_attr_in3_max.dev_attr.attr, 982 &sensor_dev_attr_in3_max.dev_attr.attr,
943 &sensor_dev_attr_in3_min.dev_attr.attr, 983 &sensor_dev_attr_in3_min.dev_attr.attr,
944 &sensor_dev_attr_in4_input.dev_attr.attr,
945 &sensor_dev_attr_in4_max.dev_attr.attr,
946 &sensor_dev_attr_in4_min.dev_attr.attr,
947 &sensor_dev_attr_in5_input.dev_attr.attr, 984 &sensor_dev_attr_in5_input.dev_attr.attr,
948 &sensor_dev_attr_in5_max.dev_attr.attr, 985 &sensor_dev_attr_in5_max.dev_attr.attr,
949 &sensor_dev_attr_in5_min.dev_attr.attr, 986 &sensor_dev_attr_in5_min.dev_attr.attr,
@@ -953,9 +990,6 @@ static struct attribute *f71805f_attributes[] = {
953 &sensor_dev_attr_in7_input.dev_attr.attr, 990 &sensor_dev_attr_in7_input.dev_attr.attr,
954 &sensor_dev_attr_in7_max.dev_attr.attr, 991 &sensor_dev_attr_in7_max.dev_attr.attr,
955 &sensor_dev_attr_in7_min.dev_attr.attr, 992 &sensor_dev_attr_in7_min.dev_attr.attr,
956 &sensor_dev_attr_in8_input.dev_attr.attr,
957 &sensor_dev_attr_in8_max.dev_attr.attr,
958 &sensor_dev_attr_in8_min.dev_attr.attr,
959 993
960 &sensor_dev_attr_temp1_input.dev_attr.attr, 994 &sensor_dev_attr_temp1_input.dev_attr.attr,
961 &sensor_dev_attr_temp1_max.dev_attr.attr, 995 &sensor_dev_attr_temp1_max.dev_attr.attr,
@@ -974,11 +1008,9 @@ static struct attribute *f71805f_attributes[] = {
974 &sensor_dev_attr_in1_alarm.dev_attr.attr, 1008 &sensor_dev_attr_in1_alarm.dev_attr.attr,
975 &sensor_dev_attr_in2_alarm.dev_attr.attr, 1009 &sensor_dev_attr_in2_alarm.dev_attr.attr,
976 &sensor_dev_attr_in3_alarm.dev_attr.attr, 1010 &sensor_dev_attr_in3_alarm.dev_attr.attr,
977 &sensor_dev_attr_in4_alarm.dev_attr.attr,
978 &sensor_dev_attr_in5_alarm.dev_attr.attr, 1011 &sensor_dev_attr_in5_alarm.dev_attr.attr,
979 &sensor_dev_attr_in6_alarm.dev_attr.attr, 1012 &sensor_dev_attr_in6_alarm.dev_attr.attr,
980 &sensor_dev_attr_in7_alarm.dev_attr.attr, 1013 &sensor_dev_attr_in7_alarm.dev_attr.attr,
981 &sensor_dev_attr_in8_alarm.dev_attr.attr,
982 &dev_attr_alarms_in.attr, 1014 &dev_attr_alarms_in.attr,
983 &sensor_dev_attr_temp1_alarm.dev_attr.attr, 1015 &sensor_dev_attr_temp1_alarm.dev_attr.attr,
984 &sensor_dev_attr_temp2_alarm.dev_attr.attr, 1016 &sensor_dev_attr_temp2_alarm.dev_attr.attr,
@@ -994,6 +1026,41 @@ static const struct attribute_group f71805f_group = {
994 .attrs = f71805f_attributes, 1026 .attrs = f71805f_attributes,
995}; 1027};
996 1028
1029static struct attribute *f71805f_attributes_optin[4][5] = {
1030 {
1031 &sensor_dev_attr_in4_input.dev_attr.attr,
1032 &sensor_dev_attr_in4_max.dev_attr.attr,
1033 &sensor_dev_attr_in4_min.dev_attr.attr,
1034 &sensor_dev_attr_in4_alarm.dev_attr.attr,
1035 NULL
1036 }, {
1037 &sensor_dev_attr_in8_input.dev_attr.attr,
1038 &sensor_dev_attr_in8_max.dev_attr.attr,
1039 &sensor_dev_attr_in8_min.dev_attr.attr,
1040 &sensor_dev_attr_in8_alarm.dev_attr.attr,
1041 NULL
1042 }, {
1043 &sensor_dev_attr_in9_input.dev_attr.attr,
1044 &sensor_dev_attr_in9_max.dev_attr.attr,
1045 &sensor_dev_attr_in9_min.dev_attr.attr,
1046 &sensor_dev_attr_in9_alarm.dev_attr.attr,
1047 NULL
1048 }, {
1049 &sensor_dev_attr_in10_input.dev_attr.attr,
1050 &sensor_dev_attr_in10_max.dev_attr.attr,
1051 &sensor_dev_attr_in10_min.dev_attr.attr,
1052 &sensor_dev_attr_in10_alarm.dev_attr.attr,
1053 NULL
1054 }
1055};
1056
1057static const struct attribute_group f71805f_group_optin[4] = {
1058 { .attrs = f71805f_attributes_optin[0] },
1059 { .attrs = f71805f_attributes_optin[1] },
1060 { .attrs = f71805f_attributes_optin[2] },
1061 { .attrs = f71805f_attributes_optin[3] },
1062};
1063
997static struct attribute *f71805f_attributes_fan[3][8] = { 1064static struct attribute *f71805f_attributes_fan[3][8] = {
998 { 1065 {
999 &sensor_dev_attr_fan1_input.dev_attr.attr, 1066 &sensor_dev_attr_fan1_input.dev_attr.attr,
@@ -1084,10 +1151,16 @@ static void __devinit f71805f_init_device(struct f71805f_data *data)
1084 1151
1085static int __devinit f71805f_probe(struct platform_device *pdev) 1152static int __devinit f71805f_probe(struct platform_device *pdev)
1086{ 1153{
1154 struct f71805f_sio_data *sio_data = pdev->dev.platform_data;
1087 struct f71805f_data *data; 1155 struct f71805f_data *data;
1088 struct resource *res; 1156 struct resource *res;
1089 int i, err; 1157 int i, err;
1090 1158
1159 static const char *names[] = {
1160 "f71805f",
1161 "f71872f",
1162 };
1163
1091 if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { 1164 if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) {
1092 err = -ENOMEM; 1165 err = -ENOMEM;
1093 printk(KERN_ERR DRVNAME ": Out of memory\n"); 1166 printk(KERN_ERR DRVNAME ": Out of memory\n");
@@ -1097,17 +1170,51 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
1097 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 1170 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1098 data->addr = res->start; 1171 data->addr = res->start;
1099 mutex_init(&data->lock); 1172 mutex_init(&data->lock);
1100 data->name = "f71805f"; 1173 data->name = names[sio_data->kind];
1101 mutex_init(&data->update_lock); 1174 mutex_init(&data->update_lock);
1102 1175
1103 platform_set_drvdata(pdev, data); 1176 platform_set_drvdata(pdev, data);
1104 1177
1178 /* Some voltage inputs depend on chip model and configuration */
1179 switch (sio_data->kind) {
1180 case f71805f:
1181 data->has_in = 0x1ff;
1182 break;
1183 case f71872f:
1184 data->has_in = 0x6ef;
1185 if (sio_data->fnsel1 & 0x01)
1186 data->has_in |= (1 << 4); /* in4 */
1187 if (sio_data->fnsel1 & 0x02)
1188 data->has_in |= (1 << 8); /* in8 */
1189 break;
1190 }
1191
1105 /* Initialize the F71805F chip */ 1192 /* Initialize the F71805F chip */
1106 f71805f_init_device(data); 1193 f71805f_init_device(data);
1107 1194
1108 /* Register sysfs interface files */ 1195 /* Register sysfs interface files */
1109 if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group))) 1196 if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group)))
1110 goto exit_free; 1197 goto exit_free;
1198 if (data->has_in & (1 << 4)) { /* in4 */
1199 if ((err = sysfs_create_group(&pdev->dev.kobj,
1200 &f71805f_group_optin[0])))
1201 goto exit_remove_files;
1202 }
1203 if (data->has_in & (1 << 8)) { /* in8 */
1204 if ((err = sysfs_create_group(&pdev->dev.kobj,
1205 &f71805f_group_optin[1])))
1206 goto exit_remove_files;
1207 }
1208 if (data->has_in & (1 << 9)) { /* in9 (F71872F/FG only) */
1209 if ((err = sysfs_create_group(&pdev->dev.kobj,
1210 &f71805f_group_optin[2])))
1211 goto exit_remove_files;
1212 }
1213 if (data->has_in & (1 << 10)) { /* in9 (F71872F/FG only) */
1214 if ((err = sysfs_create_group(&pdev->dev.kobj,
1215 &f71805f_group_optin[3])))
1216 goto exit_remove_files;
1217 }
1111 for (i = 0; i < 3; i++) { 1218 for (i = 0; i < 3; i++) {
1112 if (data->fan_ctrl[i] & FAN_CTRL_SKIP) 1219 if (data->fan_ctrl[i] & FAN_CTRL_SKIP)
1113 continue; 1220 continue;
@@ -1143,6 +1250,8 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
1143 1250
1144exit_remove_files: 1251exit_remove_files:
1145 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); 1252 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
1253 for (i = 0; i < 4; i++)
1254 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
1146 for (i = 0; i < 3; i++) 1255 for (i = 0; i < 3; i++)
1147 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); 1256 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
1148 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); 1257 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
@@ -1161,6 +1270,8 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
1161 platform_set_drvdata(pdev, NULL); 1270 platform_set_drvdata(pdev, NULL);
1162 hwmon_device_unregister(data->class_dev); 1271 hwmon_device_unregister(data->class_dev);
1163 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); 1272 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
1273 for (i = 0; i < 4; i++)
1274 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
1164 for (i = 0; i < 3; i++) 1275 for (i = 0; i < 3; i++)
1165 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); 1276 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
1166 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); 1277 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
@@ -1178,7 +1289,8 @@ static struct platform_driver f71805f_driver = {
1178 .remove = __devexit_p(f71805f_remove), 1289 .remove = __devexit_p(f71805f_remove),
1179}; 1290};
1180 1291
1181static int __init f71805f_device_add(unsigned short address) 1292static int __init f71805f_device_add(unsigned short address,
1293 const struct f71805f_sio_data *sio_data)
1182{ 1294{
1183 struct resource res = { 1295 struct resource res = {
1184 .start = address, 1296 .start = address,
@@ -1202,26 +1314,45 @@ static int __init f71805f_device_add(unsigned short address)
1202 goto exit_device_put; 1314 goto exit_device_put;
1203 } 1315 }
1204 1316
1317 pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data),
1318 GFP_KERNEL);
1319 if (!pdev->dev.platform_data) {
1320 err = -ENOMEM;
1321 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1322 goto exit_device_put;
1323 }
1324 memcpy(pdev->dev.platform_data, sio_data,
1325 sizeof(struct f71805f_sio_data));
1326
1205 err = platform_device_add(pdev); 1327 err = platform_device_add(pdev);
1206 if (err) { 1328 if (err) {
1207 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", 1329 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
1208 err); 1330 err);
1209 goto exit_device_put; 1331 goto exit_kfree_data;
1210 } 1332 }
1211 1333
1212 return 0; 1334 return 0;
1213 1335
1336exit_kfree_data:
1337 kfree(pdev->dev.platform_data);
1338 pdev->dev.platform_data = NULL;
1214exit_device_put: 1339exit_device_put:
1215 platform_device_put(pdev); 1340 platform_device_put(pdev);
1216exit: 1341exit:
1217 return err; 1342 return err;
1218} 1343}
1219 1344
1220static int __init f71805f_find(int sioaddr, unsigned short *address) 1345static int __init f71805f_find(int sioaddr, unsigned short *address,
1346 struct f71805f_sio_data *sio_data)
1221{ 1347{
1222 int err = -ENODEV; 1348 int err = -ENODEV;
1223 u16 devid; 1349 u16 devid;
1224 1350
1351 static const char *names[] = {
1352 "F71805F/FG",
1353 "F71872F/FG",
1354 };
1355
1225 superio_enter(sioaddr); 1356 superio_enter(sioaddr);
1226 1357
1227 devid = superio_inw(sioaddr, SIO_REG_MANID); 1358 devid = superio_inw(sioaddr, SIO_REG_MANID);
@@ -1229,7 +1360,15 @@ static int __init f71805f_find(int sioaddr, unsigned short *address)
1229 goto exit; 1360 goto exit;
1230 1361
1231 devid = superio_inw(sioaddr, SIO_REG_DEVID); 1362 devid = superio_inw(sioaddr, SIO_REG_DEVID);
1232 if (devid != SIO_F71805F_ID) { 1363 switch (devid) {
1364 case SIO_F71805F_ID:
1365 sio_data->kind = f71805f;
1366 break;
1367 case SIO_F71872F_ID:
1368 sio_data->kind = f71872f;
1369 sio_data->fnsel1 = superio_inb(sioaddr, SIO_REG_FNSEL1);
1370 break;
1371 default:
1233 printk(KERN_INFO DRVNAME ": Unsupported Fintek device, " 1372 printk(KERN_INFO DRVNAME ": Unsupported Fintek device, "
1234 "skipping\n"); 1373 "skipping\n");
1235 goto exit; 1374 goto exit;
@@ -1250,8 +1389,9 @@ static int __init f71805f_find(int sioaddr, unsigned short *address)
1250 } 1389 }
1251 1390
1252 err = 0; 1391 err = 0;
1253 printk(KERN_INFO DRVNAME ": Found F71805F chip at %#x, revision %u\n", 1392 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %u\n",
1254 *address, superio_inb(sioaddr, SIO_REG_DEVREV)); 1393 names[sio_data->kind], *address,
1394 superio_inb(sioaddr, SIO_REG_DEVREV));
1255 1395
1256exit: 1396exit:
1257 superio_exit(sioaddr); 1397 superio_exit(sioaddr);
@@ -1262,9 +1402,10 @@ static int __init f71805f_init(void)
1262{ 1402{
1263 int err; 1403 int err;
1264 unsigned short address; 1404 unsigned short address;
1405 struct f71805f_sio_data sio_data;
1265 1406
1266 if (f71805f_find(0x2e, &address) 1407 if (f71805f_find(0x2e, &address, &sio_data)
1267 && f71805f_find(0x4e, &address)) 1408 && f71805f_find(0x4e, &address, &sio_data))
1268 return -ENODEV; 1409 return -ENODEV;
1269 1410
1270 err = platform_driver_register(&f71805f_driver); 1411 err = platform_driver_register(&f71805f_driver);
@@ -1272,7 +1413,7 @@ static int __init f71805f_init(void)
1272 goto exit; 1413 goto exit;
1273 1414
1274 /* Sets global pdev as a side effect */ 1415 /* Sets global pdev as a side effect */
1275 err = f71805f_device_add(address); 1416 err = f71805f_device_add(address, &sio_data);
1276 if (err) 1417 if (err)
1277 goto exit_driver; 1418 goto exit_driver;
1278 1419
@@ -1286,13 +1427,16 @@ exit:
1286 1427
1287static void __exit f71805f_exit(void) 1428static void __exit f71805f_exit(void)
1288{ 1429{
1430 kfree(pdev->dev.platform_data);
1431 pdev->dev.platform_data = NULL;
1289 platform_device_unregister(pdev); 1432 platform_device_unregister(pdev);
1433
1290 platform_driver_unregister(&f71805f_driver); 1434 platform_driver_unregister(&f71805f_driver);
1291} 1435}
1292 1436
1293MODULE_AUTHOR("Jean Delvare <khali@linux-fr>"); 1437MODULE_AUTHOR("Jean Delvare <khali@linux-fr>");
1294MODULE_LICENSE("GPL"); 1438MODULE_LICENSE("GPL");
1295MODULE_DESCRIPTION("F71805F hardware monitoring driver"); 1439MODULE_DESCRIPTION("F71805F/F71872F hardware monitoring driver");
1296 1440
1297module_init(f71805f_init); 1441module_init(f71805f_init);
1298module_exit(f71805f_exit); 1442module_exit(f71805f_exit);