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 | d8d2ee073274ab666282d1942d08f1bb454d715b (patch) | |
tree | c36ac0f8a63f3ff83a312c61a19d6dde1d5c34da /drivers/hwmon/adt7475.c | |
parent | ebfaf1fbb6010204e973e329034d0004d6521503 (diff) |
hwmon: (adt7475) Add support for the ADT7476
Add support for the Analog Devices ADT7476 chip. This chip is largely
compatible with the ADT7473 and ADT7475, with additional features.
In particular, it has 5 voltage inputs instead of 2, and VID input
pins.
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>
Diffstat (limited to 'drivers/hwmon/adt7475.c')
-rw-r--r-- | drivers/hwmon/adt7475.c | 80 |
1 files changed, 62 insertions, 18 deletions
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index eac24c1361bc..72c3b754e7b6 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c | |||
@@ -58,6 +58,8 @@ | |||
58 | #define REG_STATUS1 0x41 | 58 | #define REG_STATUS1 0x41 |
59 | #define REG_STATUS2 0x42 | 59 | #define REG_STATUS2 0x42 |
60 | 60 | ||
61 | #define REG_VID 0x43 /* ADT7476 only */ | ||
62 | |||
61 | #define REG_VOLTAGE_MIN_BASE 0x44 | 63 | #define REG_VOLTAGE_MIN_BASE 0x44 |
62 | #define REG_VOLTAGE_MAX_BASE 0x45 | 64 | #define REG_VOLTAGE_MAX_BASE 0x45 |
63 | 65 | ||
@@ -94,6 +96,8 @@ | |||
94 | #define REG_VTT_MIN 0x84 /* ADT7490 only */ | 96 | #define REG_VTT_MIN 0x84 /* ADT7490 only */ |
95 | #define REG_VTT_MAX 0x86 /* ADT7490 only */ | 97 | #define REG_VTT_MAX 0x86 /* ADT7490 only */ |
96 | 98 | ||
99 | #define VID_VIDSEL 0x80 /* ADT7476 only */ | ||
100 | |||
97 | #define CONFIG2_ATTN 0x20 | 101 | #define CONFIG2_ATTN 0x20 |
98 | 102 | ||
99 | #define CONFIG3_SMBALERT 0x01 | 103 | #define CONFIG3_SMBALERT 0x01 |
@@ -142,11 +146,12 @@ | |||
142 | 146 | ||
143 | static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; | 147 | static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; |
144 | 148 | ||
145 | I2C_CLIENT_INSMOD_3(adt7473, adt7475, adt7490); | 149 | I2C_CLIENT_INSMOD_4(adt7473, adt7475, adt7476, adt7490); |
146 | 150 | ||
147 | static const struct i2c_device_id adt7475_id[] = { | 151 | static const struct i2c_device_id adt7475_id[] = { |
148 | { "adt7473", adt7473 }, | 152 | { "adt7473", adt7473 }, |
149 | { "adt7475", adt7475 }, | 153 | { "adt7475", adt7475 }, |
154 | { "adt7476", adt7476 }, | ||
150 | { "adt7490", adt7490 }, | 155 | { "adt7490", adt7490 }, |
151 | { } | 156 | { } |
152 | }; | 157 | }; |
@@ -1082,7 +1087,6 @@ static struct attribute *pwm2_attrs[] = { | |||
1082 | NULL | 1087 | NULL |
1083 | }; | 1088 | }; |
1084 | 1089 | ||
1085 | /* Attributes specific to the ADT7490 */ | ||
1086 | static struct attribute *in0_attrs[] = { | 1090 | static struct attribute *in0_attrs[] = { |
1087 | &sensor_dev_attr_in0_input.dev_attr.attr, | 1091 | &sensor_dev_attr_in0_input.dev_attr.attr, |
1088 | &sensor_dev_attr_in0_max.dev_attr.attr, | 1092 | &sensor_dev_attr_in0_max.dev_attr.attr, |
@@ -1091,15 +1095,23 @@ static struct attribute *in0_attrs[] = { | |||
1091 | NULL | 1095 | NULL |
1092 | }; | 1096 | }; |
1093 | 1097 | ||
1094 | static struct attribute *adt7490_attrs[] = { | 1098 | static struct attribute *in3_attrs[] = { |
1095 | &sensor_dev_attr_in3_input.dev_attr.attr, | 1099 | &sensor_dev_attr_in3_input.dev_attr.attr, |
1096 | &sensor_dev_attr_in3_max.dev_attr.attr, | 1100 | &sensor_dev_attr_in3_max.dev_attr.attr, |
1097 | &sensor_dev_attr_in3_min.dev_attr.attr, | 1101 | &sensor_dev_attr_in3_min.dev_attr.attr, |
1098 | &sensor_dev_attr_in3_alarm.dev_attr.attr, | 1102 | &sensor_dev_attr_in3_alarm.dev_attr.attr, |
1103 | NULL | ||
1104 | }; | ||
1105 | |||
1106 | static struct attribute *in4_attrs[] = { | ||
1099 | &sensor_dev_attr_in4_input.dev_attr.attr, | 1107 | &sensor_dev_attr_in4_input.dev_attr.attr, |
1100 | &sensor_dev_attr_in4_max.dev_attr.attr, | 1108 | &sensor_dev_attr_in4_max.dev_attr.attr, |
1101 | &sensor_dev_attr_in4_min.dev_attr.attr, | 1109 | &sensor_dev_attr_in4_min.dev_attr.attr, |
1102 | &sensor_dev_attr_in4_alarm.dev_attr.attr, | 1110 | &sensor_dev_attr_in4_alarm.dev_attr.attr, |
1111 | NULL | ||
1112 | }; | ||
1113 | |||
1114 | static struct attribute *in5_attrs[] = { | ||
1103 | &sensor_dev_attr_in5_input.dev_attr.attr, | 1115 | &sensor_dev_attr_in5_input.dev_attr.attr, |
1104 | &sensor_dev_attr_in5_max.dev_attr.attr, | 1116 | &sensor_dev_attr_in5_max.dev_attr.attr, |
1105 | &sensor_dev_attr_in5_min.dev_attr.attr, | 1117 | &sensor_dev_attr_in5_min.dev_attr.attr, |
@@ -1111,7 +1123,9 @@ static struct attribute_group adt7475_attr_group = { .attrs = adt7475_attrs }; | |||
1111 | static struct attribute_group fan4_attr_group = { .attrs = fan4_attrs }; | 1123 | static struct attribute_group fan4_attr_group = { .attrs = fan4_attrs }; |
1112 | static struct attribute_group pwm2_attr_group = { .attrs = pwm2_attrs }; | 1124 | static struct attribute_group pwm2_attr_group = { .attrs = pwm2_attrs }; |
1113 | static struct attribute_group in0_attr_group = { .attrs = in0_attrs }; | 1125 | static struct attribute_group in0_attr_group = { .attrs = in0_attrs }; |
1114 | static struct attribute_group adt7490_attr_group = { .attrs = adt7490_attrs }; | 1126 | static struct attribute_group in3_attr_group = { .attrs = in3_attrs }; |
1127 | static struct attribute_group in4_attr_group = { .attrs = in4_attrs }; | ||
1128 | static struct attribute_group in5_attr_group = { .attrs = in5_attrs }; | ||
1115 | 1129 | ||
1116 | static int adt7475_detect(struct i2c_client *client, int kind, | 1130 | static int adt7475_detect(struct i2c_client *client, int kind, |
1117 | struct i2c_board_info *info) | 1131 | struct i2c_board_info *info) |
@@ -1134,11 +1148,13 @@ static int adt7475_detect(struct i2c_client *client, int kind, | |||
1134 | name = "adt7473"; | 1148 | name = "adt7473"; |
1135 | else if (devid == 0x75 && client->addr == 0x2e) | 1149 | else if (devid == 0x75 && client->addr == 0x2e) |
1136 | name = "adt7475"; | 1150 | name = "adt7475"; |
1151 | else if (devid == 0x76) | ||
1152 | name = "adt7476"; | ||
1137 | else if ((devid2 & 0xfc) == 0x6c) | 1153 | else if ((devid2 & 0xfc) == 0x6c) |
1138 | name = "adt7490"; | 1154 | name = "adt7490"; |
1139 | else { | 1155 | else { |
1140 | dev_dbg(&adapter->dev, | 1156 | dev_dbg(&adapter->dev, |
1141 | "Couldn't detect an ADT7473/75/90 part at " | 1157 | "Couldn't detect an ADT7473/75/76/90 part at " |
1142 | "0x%02x\n", (unsigned int)client->addr); | 1158 | "0x%02x\n", (unsigned int)client->addr); |
1143 | return -ENODEV; | 1159 | return -ENODEV; |
1144 | } | 1160 | } |
@@ -1152,14 +1168,18 @@ static void adt7475_remove_files(struct i2c_client *client, | |||
1152 | struct adt7475_data *data) | 1168 | struct adt7475_data *data) |
1153 | { | 1169 | { |
1154 | sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group); | 1170 | sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group); |
1155 | if (data->has_voltage & 0x39) | ||
1156 | sysfs_remove_group(&client->dev.kobj, &adt7490_attr_group); | ||
1157 | if (data->has_fan4) | 1171 | if (data->has_fan4) |
1158 | sysfs_remove_group(&client->dev.kobj, &fan4_attr_group); | 1172 | sysfs_remove_group(&client->dev.kobj, &fan4_attr_group); |
1159 | if (data->has_pwm2) | 1173 | if (data->has_pwm2) |
1160 | sysfs_remove_group(&client->dev.kobj, &pwm2_attr_group); | 1174 | sysfs_remove_group(&client->dev.kobj, &pwm2_attr_group); |
1161 | if (data->has_voltage & (1 << 0)) | 1175 | if (data->has_voltage & (1 << 0)) |
1162 | sysfs_remove_group(&client->dev.kobj, &in0_attr_group); | 1176 | sysfs_remove_group(&client->dev.kobj, &in0_attr_group); |
1177 | if (data->has_voltage & (1 << 3)) | ||
1178 | sysfs_remove_group(&client->dev.kobj, &in3_attr_group); | ||
1179 | if (data->has_voltage & (1 << 4)) | ||
1180 | sysfs_remove_group(&client->dev.kobj, &in4_attr_group); | ||
1181 | if (data->has_voltage & (1 << 5)) | ||
1182 | sysfs_remove_group(&client->dev.kobj, &in5_attr_group); | ||
1163 | } | 1183 | } |
1164 | 1184 | ||
1165 | static int adt7475_probe(struct i2c_client *client, | 1185 | static int adt7475_probe(struct i2c_client *client, |
@@ -1168,6 +1188,7 @@ static int adt7475_probe(struct i2c_client *client, | |||
1168 | static const char *names[] = { | 1188 | static const char *names[] = { |
1169 | [adt7473] = "ADT7473", | 1189 | [adt7473] = "ADT7473", |
1170 | [adt7475] = "ADT7475", | 1190 | [adt7475] = "ADT7475", |
1191 | [adt7476] = "ADT7476", | ||
1171 | [adt7490] = "ADT7490", | 1192 | [adt7490] = "ADT7490", |
1172 | }; | 1193 | }; |
1173 | 1194 | ||
@@ -1184,6 +1205,10 @@ static int adt7475_probe(struct i2c_client *client, | |||
1184 | 1205 | ||
1185 | /* Initialize device-specific values */ | 1206 | /* Initialize device-specific values */ |
1186 | switch (id->driver_data) { | 1207 | switch (id->driver_data) { |
1208 | case adt7476: | ||
1209 | data->has_voltage = 0x0e; /* in1 to in3 */ | ||
1210 | revision = adt7475_read(REG_DEVID2) & 0x07; | ||
1211 | break; | ||
1187 | case adt7490: | 1212 | case adt7490: |
1188 | data->has_voltage = 0x3e; /* in1 to in5 */ | 1213 | data->has_voltage = 0x3e; /* in1 to in5 */ |
1189 | revision = adt7475_read(REG_DEVID2) & 0x03; | 1214 | revision = adt7475_read(REG_DEVID2) & 0x03; |
@@ -1208,17 +1233,27 @@ static int adt7475_probe(struct i2c_client *client, | |||
1208 | if ((data->config4 & CONFIG4_PINFUNC) == 0x0) | 1233 | if ((data->config4 & CONFIG4_PINFUNC) == 0x0) |
1209 | data->has_fan4 = 1; | 1234 | data->has_fan4 = 1; |
1210 | 1235 | ||
1211 | /* THERM configuration is more complex on the ADT7490, because 2 | 1236 | /* THERM configuration is more complex on the ADT7476 and ADT7490, |
1212 | different pins (TACH4 and +2.5 Vin) can be used for this function */ | 1237 | because 2 different pins (TACH4 and +2.5 Vin) can be used for |
1238 | this function */ | ||
1213 | if (id->driver_data == adt7490) { | 1239 | if (id->driver_data == adt7490) { |
1214 | if ((data->config4 & CONFIG4_PINFUNC) == 0x1 && | 1240 | if ((data->config4 & CONFIG4_PINFUNC) == 0x1 && |
1215 | !(config3 & CONFIG3_THERM)) | 1241 | !(config3 & CONFIG3_THERM)) |
1216 | data->has_fan4 = 1; | 1242 | data->has_fan4 = 1; |
1243 | } | ||
1244 | if (id->driver_data == adt7476 || id->driver_data == adt7490) { | ||
1217 | if (!(config3 & CONFIG3_THERM) || | 1245 | if (!(config3 & CONFIG3_THERM) || |
1218 | (data->config4 & CONFIG4_PINFUNC) == 0x1) | 1246 | (data->config4 & CONFIG4_PINFUNC) == 0x1) |
1219 | data->has_voltage |= (1 << 0); /* in0 */ | 1247 | data->has_voltage |= (1 << 0); /* in0 */ |
1220 | } | 1248 | } |
1221 | 1249 | ||
1250 | /* On the ADT7476, the +12V input pin may instead be used as VID5 */ | ||
1251 | if (id->driver_data == adt7476) { | ||
1252 | u8 vid = adt7475_read(REG_VID); | ||
1253 | if (!(vid & VID_VIDSEL)) | ||
1254 | data->has_voltage |= (1 << 4); /* in4 */ | ||
1255 | } | ||
1256 | |||
1222 | /* Voltage attenuators can be bypassed, globally or individually */ | 1257 | /* Voltage attenuators can be bypassed, globally or individually */ |
1223 | config2 = adt7475_read(REG_CONFIG2); | 1258 | config2 = adt7475_read(REG_CONFIG2); |
1224 | if (config2 & CONFIG2_ATTN) { | 1259 | if (config2 & CONFIG2_ATTN) { |
@@ -1238,13 +1273,6 @@ static int adt7475_probe(struct i2c_client *client, | |||
1238 | if (ret) | 1273 | if (ret) |
1239 | goto efree; | 1274 | goto efree; |
1240 | 1275 | ||
1241 | if (id->driver_data == adt7490) { | ||
1242 | ret = sysfs_create_group(&client->dev.kobj, | ||
1243 | &adt7490_attr_group); | ||
1244 | if (ret) | ||
1245 | goto eremove; | ||
1246 | } | ||
1247 | |||
1248 | /* Features that can be disabled individually */ | 1276 | /* Features that can be disabled individually */ |
1249 | if (data->has_fan4) { | 1277 | if (data->has_fan4) { |
1250 | ret = sysfs_create_group(&client->dev.kobj, &fan4_attr_group); | 1278 | ret = sysfs_create_group(&client->dev.kobj, &fan4_attr_group); |
@@ -1261,6 +1289,21 @@ static int adt7475_probe(struct i2c_client *client, | |||
1261 | if (ret) | 1289 | if (ret) |
1262 | goto eremove; | 1290 | goto eremove; |
1263 | } | 1291 | } |
1292 | if (data->has_voltage & (1 << 3)) { | ||
1293 | ret = sysfs_create_group(&client->dev.kobj, &in3_attr_group); | ||
1294 | if (ret) | ||
1295 | goto eremove; | ||
1296 | } | ||
1297 | if (data->has_voltage & (1 << 4)) { | ||
1298 | ret = sysfs_create_group(&client->dev.kobj, &in4_attr_group); | ||
1299 | if (ret) | ||
1300 | goto eremove; | ||
1301 | } | ||
1302 | if (data->has_voltage & (1 << 5)) { | ||
1303 | ret = sysfs_create_group(&client->dev.kobj, &in5_attr_group); | ||
1304 | if (ret) | ||
1305 | goto eremove; | ||
1306 | } | ||
1264 | 1307 | ||
1265 | data->hwmon_dev = hwmon_device_register(&client->dev); | 1308 | data->hwmon_dev = hwmon_device_register(&client->dev); |
1266 | if (IS_ERR(data->hwmon_dev)) { | 1309 | if (IS_ERR(data->hwmon_dev)) { |
@@ -1270,9 +1313,10 @@ static int adt7475_probe(struct i2c_client *client, | |||
1270 | 1313 | ||
1271 | dev_info(&client->dev, "%s device, revision %d\n", | 1314 | dev_info(&client->dev, "%s device, revision %d\n", |
1272 | names[id->driver_data], revision); | 1315 | names[id->driver_data], revision); |
1273 | if ((data->has_voltage & (1 << 0)) || data->has_fan4 || data->has_pwm2) | 1316 | if ((data->has_voltage & 0x11) || data->has_fan4 || data->has_pwm2) |
1274 | dev_info(&client->dev, "Optional features:%s%s%s\n", | 1317 | dev_info(&client->dev, "Optional features:%s%s%s%s\n", |
1275 | (data->has_voltage & (1 << 0)) ? " in0" : "", | 1318 | (data->has_voltage & (1 << 0)) ? " in0" : "", |
1319 | (data->has_voltage & (1 << 4)) ? " in4" : "", | ||
1276 | data->has_fan4 ? " fan4" : "", | 1320 | data->has_fan4 ? " fan4" : "", |
1277 | data->has_pwm2 ? " pwm2" : ""); | 1321 | data->has_pwm2 ? " pwm2" : ""); |
1278 | if (data->bypass_attn) | 1322 | if (data->bypass_attn) |