aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2010-10-28 14:31:51 -0400
committerJean Delvare <khali@endymion.delvare>2010-10-28 14:31:51 -0400
commit44c1bcd4bcde32b2a31a6775a277706ab489c0dc (patch)
treebb8f17e5c2d0e6e871906f3cddb32290cf1a09b8 /drivers/hwmon
parent0df6454da937548594774788b009616ed27607ed (diff)
hwmon: (it87) Add support for the IT8721F/IT8758E
Add support for the IT8721F/IT8758E. These new chips differ from the older IT87xxF chips in the following ways: * ADC LSB is 12 mV instead of 16 mV. * PWM values are 8-bit instead of 7-bit. There are other minor changes we don't have to care about in the driver. Another change is that we will handle internal voltage scaling in the driver instead of delegating the work to user-space. Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig4
-rw-r--r--drivers/hwmon/it87.c116
2 files changed, 96 insertions, 24 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index aefb9e6db237..a56f6adf3b76 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -428,8 +428,8 @@ config SENSORS_IT87
428 select HWMON_VID 428 select HWMON_VID
429 help 429 help
430 If you say yes here you get support for ITE IT8705F, IT8712F, 430 If you say yes here you get support for ITE IT8705F, IT8712F,
431 IT8716F, IT8718F, IT8720F and IT8726F sensor chips, and the 431 IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor
432 SiS960 clone. 432 chips, and the SiS960 clone.
433 433
434 This driver can also be built as a module. If so, the module 434 This driver can also be built as a module. If so, the module
435 will be called it87. 435 will be called it87.
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 7a3616ccbf05..14a5d981be7d 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -15,7 +15,9 @@
15 * IT8716F Super I/O chip w/LPC interface 15 * IT8716F Super I/O chip w/LPC interface
16 * IT8718F Super I/O chip w/LPC interface 16 * IT8718F Super I/O chip w/LPC interface
17 * IT8720F Super I/O chip w/LPC interface 17 * IT8720F Super I/O chip w/LPC interface
18 * IT8721F Super I/O chip w/LPC interface
18 * IT8726F Super I/O chip w/LPC interface 19 * IT8726F Super I/O chip w/LPC interface
20 * IT8758E Super I/O chip w/LPC interface
19 * Sis950 A clone of the IT8705F 21 * Sis950 A clone of the IT8705F
20 * 22 *
21 * Copyright (C) 2001 Chris Gauthron 23 * Copyright (C) 2001 Chris Gauthron
@@ -54,7 +56,7 @@
54 56
55#define DRVNAME "it87" 57#define DRVNAME "it87"
56 58
57enum chips { it87, it8712, it8716, it8718, it8720 }; 59enum chips { it87, it8712, it8716, it8718, it8720, it8721 };
58 60
59static unsigned short force_id; 61static unsigned short force_id;
60module_param(force_id, ushort, 0); 62module_param(force_id, ushort, 0);
@@ -126,6 +128,7 @@ superio_exit(void)
126#define IT8716F_DEVID 0x8716 128#define IT8716F_DEVID 0x8716
127#define IT8718F_DEVID 0x8718 129#define IT8718F_DEVID 0x8718
128#define IT8720F_DEVID 0x8720 130#define IT8720F_DEVID 0x8720
131#define IT8721F_DEVID 0x8721
129#define IT8726F_DEVID 0x8726 132#define IT8726F_DEVID 0x8726
130#define IT87_ACT_REG 0x30 133#define IT87_ACT_REG 0x30
131#define IT87_BASE_REG 0x60 134#define IT87_BASE_REG 0x60
@@ -229,6 +232,7 @@ struct it87_data {
229 char valid; /* !=0 if following fields are valid */ 232 char valid; /* !=0 if following fields are valid */
230 unsigned long last_updated; /* In jiffies */ 233 unsigned long last_updated; /* In jiffies */
231 234
235 u16 in_scaled; /* Internal voltage sensors are scaled */
232 u8 in[9]; /* Register value */ 236 u8 in[9]; /* Register value */
233 u8 in_max[8]; /* Register value */ 237 u8 in_max[8]; /* Register value */
234 u8 in_min[8]; /* Register value */ 238 u8 in_min[8]; /* Register value */
@@ -260,8 +264,32 @@ struct it87_data {
260 s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ 264 s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
261}; 265};
262 266
263#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8) / 16), 0, 255)) 267static u8 in_to_reg(const struct it87_data *data, int nr, long val)
264#define IN_FROM_REG(val) ((val) * 16) 268{
269 long lsb;
270
271 if (data->type == it8721) {
272 if (data->in_scaled & (1 << nr))
273 lsb = 24;
274 else
275 lsb = 12;
276 } else
277 lsb = 16;
278
279 val = DIV_ROUND_CLOSEST(val, lsb);
280 return SENSORS_LIMIT(val, 0, 255);
281}
282
283static int in_from_reg(const struct it87_data *data, int nr, int val)
284{
285 if (data->type == it8721) {
286 if (data->in_scaled & (1 << nr))
287 return val * 24;
288 else
289 return val * 12;
290 } else
291 return val * 16;
292}
265 293
266static inline u8 FAN_TO_REG(long rpm, int div) 294static inline u8 FAN_TO_REG(long rpm, int div)
267{ 295{
@@ -289,8 +317,22 @@ static inline u16 FAN16_TO_REG(long rpm)
289 ((val) + 500) / 1000), -128, 127)) 317 ((val) + 500) / 1000), -128, 127))
290#define TEMP_FROM_REG(val) ((val) * 1000) 318#define TEMP_FROM_REG(val) ((val) * 1000)
291 319
292#define PWM_TO_REG(val) ((val) >> 1) 320static u8 pwm_to_reg(const struct it87_data *data, long val)
293#define PWM_FROM_REG(val) (((val) & 0x7f) << 1) 321{
322 if (data->type == it8721)
323 return val;
324 else
325 return val >> 1;
326}
327
328static int pwm_from_reg(const struct it87_data *data, u8 reg)
329{
330 if (data->type == it8721)
331 return reg;
332 else
333 return (reg & 0x7f) << 1;
334}
335
294 336
295static int DIV_TO_REG(int val) 337static int DIV_TO_REG(int val)
296{ 338{
@@ -321,7 +363,8 @@ static inline int has_16bit_fans(const struct it87_data *data)
321 || (data->type == it8712 && data->revision >= 0x08) 363 || (data->type == it8712 && data->revision >= 0x08)
322 || data->type == it8716 364 || data->type == it8716
323 || data->type == it8718 365 || data->type == it8718
324 || data->type == it8720; 366 || data->type == it8720
367 || data->type == it8721;
325} 368}
326 369
327static inline int has_old_autopwm(const struct it87_data *data) 370static inline int has_old_autopwm(const struct it87_data *data)
@@ -359,7 +402,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
359 int nr = sensor_attr->index; 402 int nr = sensor_attr->index;
360 403
361 struct it87_data *data = it87_update_device(dev); 404 struct it87_data *data = it87_update_device(dev);
362 return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); 405 return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr]));
363} 406}
364 407
365static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, 408static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
@@ -369,7 +412,7 @@ static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
369 int nr = sensor_attr->index; 412 int nr = sensor_attr->index;
370 413
371 struct it87_data *data = it87_update_device(dev); 414 struct it87_data *data = it87_update_device(dev);
372 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); 415 return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_min[nr]));
373} 416}
374 417
375static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, 418static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
@@ -379,7 +422,7 @@ static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
379 int nr = sensor_attr->index; 422 int nr = sensor_attr->index;
380 423
381 struct it87_data *data = it87_update_device(dev); 424 struct it87_data *data = it87_update_device(dev);
382 return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); 425 return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_max[nr]));
383} 426}
384 427
385static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, 428static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
@@ -395,7 +438,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
395 return -EINVAL; 438 return -EINVAL;
396 439
397 mutex_lock(&data->update_lock); 440 mutex_lock(&data->update_lock);
398 data->in_min[nr] = IN_TO_REG(val); 441 data->in_min[nr] = in_to_reg(data, nr, val);
399 it87_write_value(data, IT87_REG_VIN_MIN(nr), 442 it87_write_value(data, IT87_REG_VIN_MIN(nr),
400 data->in_min[nr]); 443 data->in_min[nr]);
401 mutex_unlock(&data->update_lock); 444 mutex_unlock(&data->update_lock);
@@ -414,7 +457,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
414 return -EINVAL; 457 return -EINVAL;
415 458
416 mutex_lock(&data->update_lock); 459 mutex_lock(&data->update_lock);
417 data->in_max[nr] = IN_TO_REG(val); 460 data->in_max[nr] = in_to_reg(data, nr, val);
418 it87_write_value(data, IT87_REG_VIN_MAX(nr), 461 it87_write_value(data, IT87_REG_VIN_MAX(nr),
419 data->in_max[nr]); 462 data->in_max[nr]);
420 mutex_unlock(&data->update_lock); 463 mutex_unlock(&data->update_lock);
@@ -644,7 +687,8 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
644 int nr = sensor_attr->index; 687 int nr = sensor_attr->index;
645 688
646 struct it87_data *data = it87_update_device(dev); 689 struct it87_data *data = it87_update_device(dev);
647 return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm_duty[nr])); 690 return sprintf(buf, "%d\n",
691 pwm_from_reg(data, data->pwm_duty[nr]));
648} 692}
649static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, 693static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
650 char *buf) 694 char *buf)
@@ -814,7 +858,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
814 return -EINVAL; 858 return -EINVAL;
815 859
816 mutex_lock(&data->update_lock); 860 mutex_lock(&data->update_lock);
817 data->pwm_duty[nr] = PWM_TO_REG(val); 861 data->pwm_duty[nr] = pwm_to_reg(data, val);
818 /* If we are in manual mode, write the duty cycle immediately; 862 /* If we are in manual mode, write the duty cycle immediately;
819 * otherwise, just store it for later use. */ 863 * otherwise, just store it for later use. */
820 if (!(data->pwm_ctrl[nr] & 0x80)) { 864 if (!(data->pwm_ctrl[nr] & 0x80)) {
@@ -918,7 +962,8 @@ static ssize_t show_auto_pwm(struct device *dev,
918 int nr = sensor_attr->nr; 962 int nr = sensor_attr->nr;
919 int point = sensor_attr->index; 963 int point = sensor_attr->index;
920 964
921 return sprintf(buf, "%d\n", PWM_FROM_REG(data->auto_pwm[nr][point])); 965 return sprintf(buf, "%d\n",
966 pwm_from_reg(data, data->auto_pwm[nr][point]));
922} 967}
923 968
924static ssize_t set_auto_pwm(struct device *dev, 969static ssize_t set_auto_pwm(struct device *dev,
@@ -935,7 +980,7 @@ static ssize_t set_auto_pwm(struct device *dev,
935 return -EINVAL; 980 return -EINVAL;
936 981
937 mutex_lock(&data->update_lock); 982 mutex_lock(&data->update_lock);
938 data->auto_pwm[nr][point] = PWM_TO_REG(val); 983 data->auto_pwm[nr][point] = pwm_to_reg(data, val);
939 it87_write_value(data, IT87_REG_AUTO_PWM(nr, point), 984 it87_write_value(data, IT87_REG_AUTO_PWM(nr, point),
940 data->auto_pwm[nr][point]); 985 data->auto_pwm[nr][point]);
941 mutex_unlock(&data->update_lock); 986 mutex_unlock(&data->update_lock);
@@ -1205,9 +1250,16 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr,
1205 "5VSB", 1250 "5VSB",
1206 "Vbat", 1251 "Vbat",
1207 }; 1252 };
1253 static const char *labels_it8721[] = {
1254 "+3.3V",
1255 "3VSB",
1256 "Vbat",
1257 };
1258 struct it87_data *data = dev_get_drvdata(dev);
1208 int nr = to_sensor_dev_attr(attr)->index; 1259 int nr = to_sensor_dev_attr(attr)->index;
1209 1260
1210 return sprintf(buf, "%s\n", labels[nr]); 1261 return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr]
1262 : labels[nr]);
1211} 1263}
1212static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); 1264static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
1213static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); 1265static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
@@ -1492,6 +1544,9 @@ static int __init it87_find(unsigned short *address,
1492 case IT8720F_DEVID: 1544 case IT8720F_DEVID:
1493 sio_data->type = it8720; 1545 sio_data->type = it8720;
1494 break; 1546 break;
1547 case IT8721F_DEVID:
1548 sio_data->type = it8721;
1549 break;
1495 case 0xffff: /* No device at all */ 1550 case 0xffff: /* No device at all */
1496 goto exit; 1551 goto exit;
1497 default: 1552 default:
@@ -1532,11 +1587,17 @@ static int __init it87_find(unsigned short *address,
1532 int reg; 1587 int reg;
1533 1588
1534 superio_select(GPIO); 1589 superio_select(GPIO);
1535 /* We need at least 4 VID pins */ 1590
1536 reg = superio_inb(IT87_SIO_GPIO3_REG); 1591 reg = superio_inb(IT87_SIO_GPIO3_REG);
1537 if (reg & 0x0f) { 1592 if (sio_data->type == it8721) {
1538 pr_info("it87: VID is disabled (pins used for GPIO)\n"); 1593 /* The IT8721F/IT8758E doesn't have VID pins at all */
1539 sio_data->skip_vid = 1; 1594 sio_data->skip_vid = 1;
1595 } else {
1596 /* We need at least 4 VID pins */
1597 if (reg & 0x0f) {
1598 pr_info("it87: VID is disabled (pins used for GPIO)\n");
1599 sio_data->skip_vid = 1;
1600 }
1540 } 1601 }
1541 1602
1542 /* Check if fan3 is there or not */ 1603 /* Check if fan3 is there or not */
@@ -1574,7 +1635,7 @@ static int __init it87_find(unsigned short *address,
1574 } 1635 }
1575 if (reg & (1 << 0)) 1636 if (reg & (1 << 0))
1576 sio_data->internal |= (1 << 0); 1637 sio_data->internal |= (1 << 0);
1577 if (reg & (1 << 1)) 1638 if ((reg & (1 << 1)) || sio_data->type == it8721)
1578 sio_data->internal |= (1 << 1); 1639 sio_data->internal |= (1 << 1);
1579 1640
1580 sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; 1641 sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
@@ -1652,6 +1713,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
1652 "it8716", 1713 "it8716",
1653 "it8718", 1714 "it8718",
1654 "it8720", 1715 "it8720",
1716 "it8721",
1655 }; 1717 };
1656 1718
1657 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 1719 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1688,6 +1750,16 @@ static int __devinit it87_probe(struct platform_device *pdev)
1688 /* Check PWM configuration */ 1750 /* Check PWM configuration */
1689 enable_pwm_interface = it87_check_pwm(dev); 1751 enable_pwm_interface = it87_check_pwm(dev);
1690 1752
1753 /* Starting with IT8721F, we handle scaling of internal voltages */
1754 if (data->type == it8721) {
1755 if (sio_data->internal & (1 << 0))
1756 data->in_scaled |= (1 << 3); /* in3 is AVCC */
1757 if (sio_data->internal & (1 << 1))
1758 data->in_scaled |= (1 << 7); /* in7 is VSB */
1759 if (sio_data->internal & (1 << 2))
1760 data->in_scaled |= (1 << 8); /* in8 is Vbat */
1761 }
1762
1691 /* Initialize the IT87 chip */ 1763 /* Initialize the IT87 chip */
1692 it87_init_device(pdev); 1764 it87_init_device(pdev);
1693 1765
@@ -2053,7 +2125,7 @@ static struct it87_data *it87_update_device(struct device *dev)
2053 2125
2054 data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); 2126 data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
2055 /* The 8705 does not have VID capability. 2127 /* The 8705 does not have VID capability.
2056 The 8718 and the 8720 don't use IT87_REG_VID for the 2128 The 8718 and later don't use IT87_REG_VID for the
2057 same purpose. */ 2129 same purpose. */
2058 if (data->type == it8712 || data->type == it8716) { 2130 if (data->type == it8712 || data->type == it8716) {
2059 data->vid = it87_read_value(data, IT87_REG_VID); 2131 data->vid = it87_read_value(data, IT87_REG_VID);
@@ -2153,7 +2225,7 @@ static void __exit sm_it87_exit(void)
2153 2225
2154MODULE_AUTHOR("Chris Gauthron, " 2226MODULE_AUTHOR("Chris Gauthron, "
2155 "Jean Delvare <khali@linux-fr.org>"); 2227 "Jean Delvare <khali@linux-fr.org>");
2156MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8720F/8726F, SiS950 driver"); 2228MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
2157module_param(update_vbat, bool, 0); 2229module_param(update_vbat, bool, 0);
2158MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); 2230MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
2159module_param(fix_pwm_polarity, bool, 0); 2231module_param(fix_pwm_polarity, bool, 0);