diff options
author | Jean Delvare <khali@linux-fr.org> | 2009-12-09 14:36:08 -0500 |
---|---|---|
committer | Jean Delvare <khali@linux-fr.org> | 2009-12-09 14:36:08 -0500 |
commit | 54fe4671aa5853ca88da72d67e969a3d8de6dcf6 (patch) | |
tree | d92f5306dc6c2deedf8bb082f9a848f77110258d | |
parent | b058b8596136d97b9469366f1f97fb35accf3d66 (diff) |
hwmon: (adt7475) Add VID support for the ADT7476
The ADT7476 has 5 dedicated pins for VID input, and the +12V input can
optionally be used as a 6th VID pin. Add support for VID input.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Jordan Crouse <jordan@cosmicpenguin.net>
Cc: "Darrick J. Wong" <djwong@us.ibm.com>
-rw-r--r-- | Documentation/hwmon/adt7475 | 2 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 1 | ||||
-rw-r--r-- | drivers/hwmon/adt7475.c | 66 |
3 files changed, 65 insertions, 4 deletions
diff --git a/Documentation/hwmon/adt7475 b/Documentation/hwmon/adt7475 index 03be1e6f69c..0502f2b464e 100644 --- a/Documentation/hwmon/adt7475 +++ b/Documentation/hwmon/adt7475 | |||
@@ -70,7 +70,7 @@ ADT7475: | |||
70 | 70 | ||
71 | ADT7476: | 71 | ADT7476: |
72 | * 5 voltage inputs | 72 | * 5 voltage inputs |
73 | * VID support (not implemented) | 73 | * VID support |
74 | 74 | ||
75 | ADT7490: | 75 | ADT7490: |
76 | * 6 voltage inputs | 76 | * 6 voltage inputs |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 957171c6232..9e640c62ebd 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -207,6 +207,7 @@ config SENSORS_ADT7473 | |||
207 | config SENSORS_ADT7475 | 207 | config SENSORS_ADT7475 |
208 | tristate "Analog Devices ADT7473, ADT7475, ADT7476 and ADT7490" | 208 | tristate "Analog Devices ADT7473, ADT7475, ADT7476 and ADT7490" |
209 | depends on I2C && EXPERIMENTAL | 209 | depends on I2C && EXPERIMENTAL |
210 | select HWMON_VID | ||
210 | help | 211 | help |
211 | If you say yes here you get support for the Analog Devices | 212 | If you say yes here you get support for the Analog Devices |
212 | ADT7473, ADT7475, ADT7476 and ADT7490 hardware monitoring | 213 | ADT7473, ADT7475, ADT7476 and ADT7490 hardware monitoring |
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 72c3b754e7b..99abfddedbc 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/hwmon.h> | 19 | #include <linux/hwmon.h> |
20 | #include <linux/hwmon-sysfs.h> | 20 | #include <linux/hwmon-sysfs.h> |
21 | #include <linux/hwmon-vid.h> | ||
21 | #include <linux/err.h> | 22 | #include <linux/err.h> |
22 | 23 | ||
23 | /* Indexes for the sysfs hooks */ | 24 | /* Indexes for the sysfs hooks */ |
@@ -110,6 +111,7 @@ | |||
110 | 111 | ||
111 | #define CONFIG5_TWOSCOMP 0x01 | 112 | #define CONFIG5_TWOSCOMP 0x01 |
112 | #define CONFIG5_TEMPOFFSET 0x02 | 113 | #define CONFIG5_TEMPOFFSET 0x02 |
114 | #define CONFIG5_VIDGPIO 0x10 /* ADT7476 only */ | ||
113 | 115 | ||
114 | /* ADT7475 Settings */ | 116 | /* ADT7475 Settings */ |
115 | 117 | ||
@@ -171,6 +173,7 @@ struct adt7475_data { | |||
171 | u8 bypass_attn; /* Bypass voltage attenuator */ | 173 | u8 bypass_attn; /* Bypass voltage attenuator */ |
172 | u8 has_pwm2:1; | 174 | u8 has_pwm2:1; |
173 | u8 has_fan4:1; | 175 | u8 has_fan4:1; |
176 | u8 has_vid:1; | ||
174 | u32 alarms; | 177 | u32 alarms; |
175 | u16 voltage[3][6]; | 178 | u16 voltage[3][6]; |
176 | u16 temp[7][3]; | 179 | u16 temp[7][3]; |
@@ -179,6 +182,9 @@ struct adt7475_data { | |||
179 | u8 range[3]; | 182 | u8 range[3]; |
180 | u8 pwmctl[3]; | 183 | u8 pwmctl[3]; |
181 | u8 pwmchan[3]; | 184 | u8 pwmchan[3]; |
185 | |||
186 | u8 vid; | ||
187 | u8 vrm; | ||
182 | }; | 188 | }; |
183 | 189 | ||
184 | static struct i2c_driver adt7475_driver; | 190 | static struct i2c_driver adt7475_driver; |
@@ -864,6 +870,35 @@ static ssize_t set_pwm_at_crit(struct device *dev, | |||
864 | return count; | 870 | return count; |
865 | } | 871 | } |
866 | 872 | ||
873 | static ssize_t show_vrm(struct device *dev, struct device_attribute *devattr, | ||
874 | char *buf) | ||
875 | { | ||
876 | struct adt7475_data *data = dev_get_drvdata(dev); | ||
877 | return sprintf(buf, "%d\n", (int)data->vrm); | ||
878 | } | ||
879 | |||
880 | static ssize_t set_vrm(struct device *dev, struct device_attribute *devattr, | ||
881 | const char *buf, size_t count) | ||
882 | { | ||
883 | struct adt7475_data *data = dev_get_drvdata(dev); | ||
884 | long val; | ||
885 | |||
886 | if (strict_strtol(buf, 10, &val)) | ||
887 | return -EINVAL; | ||
888 | if (val < 0 || val > 255) | ||
889 | return -EINVAL; | ||
890 | data->vrm = val; | ||
891 | |||
892 | return count; | ||
893 | } | ||
894 | |||
895 | static ssize_t show_vid(struct device *dev, struct device_attribute *devattr, | ||
896 | char *buf) | ||
897 | { | ||
898 | struct adt7475_data *data = adt7475_update_device(dev); | ||
899 | return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); | ||
900 | } | ||
901 | |||
867 | static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_voltage, NULL, INPUT, 0); | 902 | static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_voltage, NULL, INPUT, 0); |
868 | static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_voltage, | 903 | static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_voltage, |
869 | set_voltage, MAX, 0); | 904 | set_voltage, MAX, 0); |
@@ -1007,6 +1042,9 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, | |||
1007 | static DEVICE_ATTR(pwm_use_point2_pwm_at_crit, S_IWUSR | S_IRUGO, | 1042 | static DEVICE_ATTR(pwm_use_point2_pwm_at_crit, S_IWUSR | S_IRUGO, |
1008 | show_pwm_at_crit, set_pwm_at_crit); | 1043 | show_pwm_at_crit, set_pwm_at_crit); |
1009 | 1044 | ||
1045 | static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, set_vrm); | ||
1046 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); | ||
1047 | |||
1010 | static struct attribute *adt7475_attrs[] = { | 1048 | static struct attribute *adt7475_attrs[] = { |
1011 | &sensor_dev_attr_in1_input.dev_attr.attr, | 1049 | &sensor_dev_attr_in1_input.dev_attr.attr, |
1012 | &sensor_dev_attr_in1_max.dev_attr.attr, | 1050 | &sensor_dev_attr_in1_max.dev_attr.attr, |
@@ -1119,6 +1157,12 @@ static struct attribute *in5_attrs[] = { | |||
1119 | NULL | 1157 | NULL |
1120 | }; | 1158 | }; |
1121 | 1159 | ||
1160 | static struct attribute *vid_attrs[] = { | ||
1161 | &dev_attr_cpu0_vid.attr, | ||
1162 | &dev_attr_vrm.attr, | ||
1163 | NULL | ||
1164 | }; | ||
1165 | |||
1122 | static struct attribute_group adt7475_attr_group = { .attrs = adt7475_attrs }; | 1166 | static struct attribute_group adt7475_attr_group = { .attrs = adt7475_attrs }; |
1123 | static struct attribute_group fan4_attr_group = { .attrs = fan4_attrs }; | 1167 | static struct attribute_group fan4_attr_group = { .attrs = fan4_attrs }; |
1124 | static struct attribute_group pwm2_attr_group = { .attrs = pwm2_attrs }; | 1168 | static struct attribute_group pwm2_attr_group = { .attrs = pwm2_attrs }; |
@@ -1126,6 +1170,7 @@ static struct attribute_group in0_attr_group = { .attrs = in0_attrs }; | |||
1126 | static struct attribute_group in3_attr_group = { .attrs = in3_attrs }; | 1170 | static struct attribute_group in3_attr_group = { .attrs = in3_attrs }; |
1127 | static struct attribute_group in4_attr_group = { .attrs = in4_attrs }; | 1171 | static struct attribute_group in4_attr_group = { .attrs = in4_attrs }; |
1128 | static struct attribute_group in5_attr_group = { .attrs = in5_attrs }; | 1172 | static struct attribute_group in5_attr_group = { .attrs = in5_attrs }; |
1173 | static struct attribute_group vid_attr_group = { .attrs = vid_attrs }; | ||
1129 | 1174 | ||
1130 | static int adt7475_detect(struct i2c_client *client, int kind, | 1175 | static int adt7475_detect(struct i2c_client *client, int kind, |
1131 | struct i2c_board_info *info) | 1176 | struct i2c_board_info *info) |
@@ -1180,6 +1225,8 @@ static void adt7475_remove_files(struct i2c_client *client, | |||
1180 | sysfs_remove_group(&client->dev.kobj, &in4_attr_group); | 1225 | sysfs_remove_group(&client->dev.kobj, &in4_attr_group); |
1181 | if (data->has_voltage & (1 << 5)) | 1226 | if (data->has_voltage & (1 << 5)) |
1182 | sysfs_remove_group(&client->dev.kobj, &in5_attr_group); | 1227 | sysfs_remove_group(&client->dev.kobj, &in5_attr_group); |
1228 | if (data->has_vid) | ||
1229 | sysfs_remove_group(&client->dev.kobj, &vid_attr_group); | ||
1183 | } | 1230 | } |
1184 | 1231 | ||
1185 | static int adt7475_probe(struct i2c_client *client, | 1232 | static int adt7475_probe(struct i2c_client *client, |
@@ -1247,11 +1294,14 @@ static int adt7475_probe(struct i2c_client *client, | |||
1247 | data->has_voltage |= (1 << 0); /* in0 */ | 1294 | data->has_voltage |= (1 << 0); /* in0 */ |
1248 | } | 1295 | } |
1249 | 1296 | ||
1250 | /* On the ADT7476, the +12V input pin may instead be used as VID5 */ | 1297 | /* On the ADT7476, the +12V input pin may instead be used as VID5, |
1298 | and VID pins may alternatively be used as GPIO */ | ||
1251 | if (id->driver_data == adt7476) { | 1299 | if (id->driver_data == adt7476) { |
1252 | u8 vid = adt7475_read(REG_VID); | 1300 | u8 vid = adt7475_read(REG_VID); |
1253 | if (!(vid & VID_VIDSEL)) | 1301 | if (!(vid & VID_VIDSEL)) |
1254 | data->has_voltage |= (1 << 4); /* in4 */ | 1302 | data->has_voltage |= (1 << 4); /* in4 */ |
1303 | |||
1304 | data->has_vid = !(adt7475_read(REG_CONFIG5) & CONFIG5_VIDGPIO); | ||
1255 | } | 1305 | } |
1256 | 1306 | ||
1257 | /* Voltage attenuators can be bypassed, globally or individually */ | 1307 | /* Voltage attenuators can be bypassed, globally or individually */ |
@@ -1304,6 +1354,12 @@ static int adt7475_probe(struct i2c_client *client, | |||
1304 | if (ret) | 1354 | if (ret) |
1305 | goto eremove; | 1355 | goto eremove; |
1306 | } | 1356 | } |
1357 | if (data->has_vid) { | ||
1358 | data->vrm = vid_which_vrm(); | ||
1359 | ret = sysfs_create_group(&client->dev.kobj, &vid_attr_group); | ||
1360 | if (ret) | ||
1361 | goto eremove; | ||
1362 | } | ||
1307 | 1363 | ||
1308 | data->hwmon_dev = hwmon_device_register(&client->dev); | 1364 | data->hwmon_dev = hwmon_device_register(&client->dev); |
1309 | if (IS_ERR(data->hwmon_dev)) { | 1365 | if (IS_ERR(data->hwmon_dev)) { |
@@ -1314,11 +1370,12 @@ static int adt7475_probe(struct i2c_client *client, | |||
1314 | dev_info(&client->dev, "%s device, revision %d\n", | 1370 | dev_info(&client->dev, "%s device, revision %d\n", |
1315 | names[id->driver_data], revision); | 1371 | names[id->driver_data], revision); |
1316 | if ((data->has_voltage & 0x11) || data->has_fan4 || data->has_pwm2) | 1372 | if ((data->has_voltage & 0x11) || data->has_fan4 || data->has_pwm2) |
1317 | dev_info(&client->dev, "Optional features:%s%s%s%s\n", | 1373 | dev_info(&client->dev, "Optional features:%s%s%s%s%s\n", |
1318 | (data->has_voltage & (1 << 0)) ? " in0" : "", | 1374 | (data->has_voltage & (1 << 0)) ? " in0" : "", |
1319 | (data->has_voltage & (1 << 4)) ? " in4" : "", | 1375 | (data->has_voltage & (1 << 4)) ? " in4" : "", |
1320 | data->has_fan4 ? " fan4" : "", | 1376 | data->has_fan4 ? " fan4" : "", |
1321 | data->has_pwm2 ? " pwm2" : ""); | 1377 | data->has_pwm2 ? " pwm2" : "", |
1378 | data->has_vid ? " vid" : ""); | ||
1322 | if (data->bypass_attn) | 1379 | if (data->bypass_attn) |
1323 | dev_info(&client->dev, "Bypassing attenuators on:%s%s%s%s\n", | 1380 | dev_info(&client->dev, "Bypassing attenuators on:%s%s%s%s\n", |
1324 | (data->bypass_attn & (1 << 0)) ? " in0" : "", | 1381 | (data->bypass_attn & (1 << 0)) ? " in0" : "", |
@@ -1472,6 +1529,9 @@ static struct adt7475_data *adt7475_update_device(struct device *dev) | |||
1472 | data->pwm[INPUT][i] = adt7475_read(PWM_REG(i)); | 1529 | data->pwm[INPUT][i] = adt7475_read(PWM_REG(i)); |
1473 | } | 1530 | } |
1474 | 1531 | ||
1532 | if (data->has_vid) | ||
1533 | data->vid = adt7475_read(REG_VID) & 0x3f; | ||
1534 | |||
1475 | data->measure_updated = jiffies; | 1535 | data->measure_updated = jiffies; |
1476 | } | 1536 | } |
1477 | 1537 | ||