diff options
| author | Jean Delvare <khali@linux-fr.org> | 2012-01-16 16:51:48 -0500 |
|---|---|---|
| committer | Jean Delvare <khali@endymion.delvare> | 2012-01-16 16:51:48 -0500 |
| commit | 16b5dda22e3798e61bb008d2329d4f4d90ef764e (patch) | |
| tree | f9b00eb0982045d496835b2ab0e829995c3d94d9 | |
| parent | d6db23c7ce8d02896197394c1d741bdffe58ac54 (diff) | |
hwmon: (it87) Add IT8728F support
Until we get a datasheet for the IT8728F, treat it as fully compatible
with the IT8721F, as it seems to work reasonably well.
This closes kernel bug #27262.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Acked-by: Guenter Roeck <guenter.roeck@ericsson.com>
| -rw-r--r-- | Documentation/hwmon/it87 | 13 | ||||
| -rw-r--r-- | drivers/hwmon/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/hwmon/it87.c | 61 |
3 files changed, 58 insertions, 20 deletions
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 6f496a586732..23b7def21ba8 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 | |||
| @@ -26,6 +26,10 @@ Supported chips: | |||
| 26 | Prefix: 'it8721' | 26 | Prefix: 'it8721' |
| 27 | Addresses scanned: from Super I/O config space (8 I/O ports) | 27 | Addresses scanned: from Super I/O config space (8 I/O ports) |
| 28 | Datasheet: Not publicly available | 28 | Datasheet: Not publicly available |
| 29 | * IT8728F | ||
| 30 | Prefix: 'it8728' | ||
| 31 | Addresses scanned: from Super I/O config space (8 I/O ports) | ||
| 32 | Datasheet: Not publicly available | ||
| 29 | * SiS950 [clone of IT8705F] | 33 | * SiS950 [clone of IT8705F] |
| 30 | Prefix: 'it87' | 34 | Prefix: 'it87' |
| 31 | Addresses scanned: from Super I/O config space (8 I/O ports) | 35 | Addresses scanned: from Super I/O config space (8 I/O ports) |
| @@ -71,7 +75,7 @@ Description | |||
| 71 | ----------- | 75 | ----------- |
| 72 | 76 | ||
| 73 | This driver implements support for the IT8705F, IT8712F, IT8716F, | 77 | This driver implements support for the IT8705F, IT8712F, IT8716F, |
| 74 | IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips. | 78 | IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E and SiS950 chips. |
| 75 | 79 | ||
| 76 | These chips are 'Super I/O chips', supporting floppy disks, infrared ports, | 80 | These chips are 'Super I/O chips', supporting floppy disks, infrared ports, |
| 77 | joysticks and other miscellaneous stuff. For hardware monitoring, they | 81 | joysticks and other miscellaneous stuff. For hardware monitoring, they |
| @@ -105,6 +109,9 @@ The IT8726F is just bit enhanced IT8716F with additional hardware | |||
| 105 | for AMD power sequencing. Therefore the chip will appear as IT8716F | 109 | for AMD power sequencing. Therefore the chip will appear as IT8716F |
| 106 | to userspace applications. | 110 | to userspace applications. |
| 107 | 111 | ||
| 112 | The IT8728F is considered compatible with the IT8721F, until a datasheet | ||
| 113 | becomes available (hopefully.) | ||
| 114 | |||
| 108 | Temperatures are measured in degrees Celsius. An alarm is triggered once | 115 | Temperatures are measured in degrees Celsius. An alarm is triggered once |
| 109 | when the Overtemperature Shutdown limit is crossed. | 116 | when the Overtemperature Shutdown limit is crossed. |
| 110 | 117 | ||
| @@ -121,8 +128,8 @@ alarm is triggered if the voltage has crossed a programmable minimum or | |||
| 121 | maximum limit. Note that minimum in this case always means 'closest to | 128 | maximum limit. Note that minimum in this case always means 'closest to |
| 122 | zero'; this is important for negative voltage measurements. All voltage | 129 | zero'; this is important for negative voltage measurements. All voltage |
| 123 | inputs can measure voltages between 0 and 4.08 volts, with a resolution of | 130 | inputs can measure voltages between 0 and 4.08 volts, with a resolution of |
| 124 | 0.016 volt (except IT8721F/IT8758E: 0.012 volt.) The battery voltage in8 does | 131 | 0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery |
| 125 | not have limit registers. | 132 | voltage in8 does not have limit registers. |
| 126 | 133 | ||
| 127 | On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside | 134 | On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside |
| 128 | the chip (in7, in8 and optionally in3). The driver handles this transparently | 135 | the chip (in7, in8 and optionally in3). The driver handles this transparently |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f468bbb6357a..02260406b9e4 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
| @@ -474,8 +474,8 @@ config SENSORS_IT87 | |||
| 474 | select HWMON_VID | 474 | select HWMON_VID |
| 475 | help | 475 | help |
| 476 | If you say yes here you get support for ITE IT8705F, IT8712F, | 476 | If you say yes here you get support for ITE IT8705F, IT8712F, |
| 477 | IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor | 477 | IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E |
| 478 | chips, and the SiS960 clone. | 478 | sensor chips, and the SiS960 clone. |
| 479 | 479 | ||
| 480 | This driver can also be built as a module. If so, the module | 480 | This driver can also be built as a module. If so, the module |
| 481 | will be called it87. | 481 | will be called it87. |
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 603ef2af2707..0054d6f9cec9 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c | |||
| @@ -17,6 +17,7 @@ | |||
| 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 | * IT8721F Super I/O chip w/LPC interface |
| 19 | * IT8726F Super I/O chip w/LPC interface | 19 | * IT8726F Super I/O chip w/LPC interface |
| 20 | * IT8728F Super I/O chip w/LPC interface | ||
| 20 | * IT8758E Super I/O chip w/LPC interface | 21 | * IT8758E Super I/O chip w/LPC interface |
| 21 | * Sis950 A clone of the IT8705F | 22 | * Sis950 A clone of the IT8705F |
| 22 | * | 23 | * |
| @@ -58,7 +59,7 @@ | |||
| 58 | 59 | ||
| 59 | #define DRVNAME "it87" | 60 | #define DRVNAME "it87" |
| 60 | 61 | ||
| 61 | enum chips { it87, it8712, it8716, it8718, it8720, it8721 }; | 62 | enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 }; |
| 62 | 63 | ||
| 63 | static unsigned short force_id; | 64 | static unsigned short force_id; |
| 64 | module_param(force_id, ushort, 0); | 65 | module_param(force_id, ushort, 0); |
| @@ -135,6 +136,7 @@ static inline void superio_exit(void) | |||
| 135 | #define IT8720F_DEVID 0x8720 | 136 | #define IT8720F_DEVID 0x8720 |
| 136 | #define IT8721F_DEVID 0x8721 | 137 | #define IT8721F_DEVID 0x8721 |
| 137 | #define IT8726F_DEVID 0x8726 | 138 | #define IT8726F_DEVID 0x8726 |
| 139 | #define IT8728F_DEVID 0x8728 | ||
| 138 | #define IT87_ACT_REG 0x30 | 140 | #define IT87_ACT_REG 0x30 |
| 139 | #define IT87_BASE_REG 0x60 | 141 | #define IT87_BASE_REG 0x60 |
| 140 | 142 | ||
| @@ -274,11 +276,31 @@ struct it87_data { | |||
| 274 | s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ | 276 | s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ |
| 275 | }; | 277 | }; |
| 276 | 278 | ||
| 279 | static inline int has_12mv_adc(const struct it87_data *data) | ||
| 280 | { | ||
| 281 | /* | ||
| 282 | * IT8721F and later have a 12 mV ADC, also with internal scaling | ||
| 283 | * on selected inputs. | ||
| 284 | */ | ||
| 285 | return data->type == it8721 | ||
| 286 | || data->type == it8728; | ||
| 287 | } | ||
| 288 | |||
| 289 | static inline int has_newer_autopwm(const struct it87_data *data) | ||
| 290 | { | ||
| 291 | /* | ||
| 292 | * IT8721F and later have separate registers for the temperature | ||
| 293 | * mapping and the manual duty cycle. | ||
| 294 | */ | ||
| 295 | return data->type == it8721 | ||
| 296 | || data->type == it8728; | ||
| 297 | } | ||
| 298 | |||
| 277 | static u8 in_to_reg(const struct it87_data *data, int nr, long val) | 299 | static u8 in_to_reg(const struct it87_data *data, int nr, long val) |
| 278 | { | 300 | { |
| 279 | long lsb; | 301 | long lsb; |
| 280 | 302 | ||
| 281 | if (data->type == it8721) { | 303 | if (has_12mv_adc(data)) { |
| 282 | if (data->in_scaled & (1 << nr)) | 304 | if (data->in_scaled & (1 << nr)) |
| 283 | lsb = 24; | 305 | lsb = 24; |
| 284 | else | 306 | else |
| @@ -292,7 +314,7 @@ static u8 in_to_reg(const struct it87_data *data, int nr, long val) | |||
| 292 | 314 | ||
| 293 | static int in_from_reg(const struct it87_data *data, int nr, int val) | 315 | static int in_from_reg(const struct it87_data *data, int nr, int val) |
| 294 | { | 316 | { |
| 295 | if (data->type == it8721) { | 317 | if (has_12mv_adc(data)) { |
| 296 | if (data->in_scaled & (1 << nr)) | 318 | if (data->in_scaled & (1 << nr)) |
| 297 | return val * 24; | 319 | return val * 24; |
| 298 | else | 320 | else |
| @@ -329,7 +351,7 @@ static inline u16 FAN16_TO_REG(long rpm) | |||
| 329 | 351 | ||
| 330 | static u8 pwm_to_reg(const struct it87_data *data, long val) | 352 | static u8 pwm_to_reg(const struct it87_data *data, long val) |
| 331 | { | 353 | { |
| 332 | if (data->type == it8721) | 354 | if (has_newer_autopwm(data)) |
| 333 | return val; | 355 | return val; |
| 334 | else | 356 | else |
| 335 | return val >> 1; | 357 | return val >> 1; |
| @@ -337,7 +359,7 @@ static u8 pwm_to_reg(const struct it87_data *data, long val) | |||
| 337 | 359 | ||
| 338 | static int pwm_from_reg(const struct it87_data *data, u8 reg) | 360 | static int pwm_from_reg(const struct it87_data *data, u8 reg) |
| 339 | { | 361 | { |
| 340 | if (data->type == it8721) | 362 | if (has_newer_autopwm(data)) |
| 341 | return reg; | 363 | return reg; |
| 342 | else | 364 | else |
| 343 | return (reg & 0x7f) << 1; | 365 | return (reg & 0x7f) << 1; |
| @@ -374,7 +396,8 @@ static inline int has_16bit_fans(const struct it87_data *data) | |||
| 374 | || data->type == it8716 | 396 | || data->type == it8716 |
| 375 | || data->type == it8718 | 397 | || data->type == it8718 |
| 376 | || data->type == it8720 | 398 | || data->type == it8720 |
| 377 | || data->type == it8721; | 399 | || data->type == it8721 |
| 400 | || data->type == it8728; | ||
| 378 | } | 401 | } |
| 379 | 402 | ||
| 380 | static inline int has_old_autopwm(const struct it87_data *data) | 403 | static inline int has_old_autopwm(const struct it87_data *data) |
| @@ -842,7 +865,7 @@ static ssize_t set_pwm_enable(struct device *dev, | |||
| 842 | data->fan_main_ctrl); | 865 | data->fan_main_ctrl); |
| 843 | } else { | 866 | } else { |
| 844 | if (val == 1) /* Manual mode */ | 867 | if (val == 1) /* Manual mode */ |
| 845 | data->pwm_ctrl[nr] = data->type == it8721 ? | 868 | data->pwm_ctrl[nr] = has_newer_autopwm(data) ? |
| 846 | data->pwm_temp_map[nr] : | 869 | data->pwm_temp_map[nr] : |
| 847 | data->pwm_duty[nr]; | 870 | data->pwm_duty[nr]; |
| 848 | else /* Automatic mode */ | 871 | else /* Automatic mode */ |
| @@ -870,7 +893,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, | |||
| 870 | return -EINVAL; | 893 | return -EINVAL; |
| 871 | 894 | ||
| 872 | mutex_lock(&data->update_lock); | 895 | mutex_lock(&data->update_lock); |
| 873 | if (data->type == it8721) { | 896 | if (has_newer_autopwm(data)) { |
| 874 | /* If we are in automatic mode, the PWM duty cycle register | 897 | /* If we are in automatic mode, the PWM duty cycle register |
| 875 | * is read-only so we can't write the value */ | 898 | * is read-only so we can't write the value */ |
| 876 | if (data->pwm_ctrl[nr] & 0x80) { | 899 | if (data->pwm_ctrl[nr] & 0x80) { |
| @@ -1311,8 +1334,8 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, | |||
| 1311 | struct it87_data *data = dev_get_drvdata(dev); | 1334 | struct it87_data *data = dev_get_drvdata(dev); |
| 1312 | int nr = to_sensor_dev_attr(attr)->index; | 1335 | int nr = to_sensor_dev_attr(attr)->index; |
| 1313 | 1336 | ||
| 1314 | return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr] | 1337 | return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr] |
| 1315 | : labels[nr]); | 1338 | : labels[nr]); |
| 1316 | } | 1339 | } |
| 1317 | static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); | 1340 | static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); |
| 1318 | static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); | 1341 | static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); |
| @@ -1605,6 +1628,9 @@ static int __init it87_find(unsigned short *address, | |||
| 1605 | case IT8721F_DEVID: | 1628 | case IT8721F_DEVID: |
| 1606 | sio_data->type = it8721; | 1629 | sio_data->type = it8721; |
| 1607 | break; | 1630 | break; |
| 1631 | case IT8728F_DEVID: | ||
| 1632 | sio_data->type = it8728; | ||
| 1633 | break; | ||
| 1608 | case 0xffff: /* No device at all */ | 1634 | case 0xffff: /* No device at all */ |
| 1609 | goto exit; | 1635 | goto exit; |
| 1610 | default: | 1636 | default: |
| @@ -1646,8 +1672,11 @@ static int __init it87_find(unsigned short *address, | |||
| 1646 | superio_select(GPIO); | 1672 | superio_select(GPIO); |
| 1647 | 1673 | ||
| 1648 | reg = superio_inb(IT87_SIO_GPIO3_REG); | 1674 | reg = superio_inb(IT87_SIO_GPIO3_REG); |
| 1649 | if (sio_data->type == it8721) { | 1675 | if (sio_data->type == it8721 || sio_data->type == it8728) { |
| 1650 | /* The IT8721F/IT8758E doesn't have VID pins at all */ | 1676 | /* |
| 1677 | * The IT8721F/IT8758E doesn't have VID pins at all, | ||
| 1678 | * not sure about the IT8728F. | ||
| 1679 | */ | ||
| 1651 | sio_data->skip_vid = 1; | 1680 | sio_data->skip_vid = 1; |
| 1652 | } else { | 1681 | } else { |
| 1653 | /* We need at least 4 VID pins */ | 1682 | /* We need at least 4 VID pins */ |
| @@ -1692,7 +1721,8 @@ static int __init it87_find(unsigned short *address, | |||
| 1692 | } | 1721 | } |
| 1693 | if (reg & (1 << 0)) | 1722 | if (reg & (1 << 0)) |
| 1694 | sio_data->internal |= (1 << 0); | 1723 | sio_data->internal |= (1 << 0); |
| 1695 | if ((reg & (1 << 1)) || sio_data->type == it8721) | 1724 | if ((reg & (1 << 1)) || sio_data->type == it8721 || |
| 1725 | sio_data->type == it8728) | ||
| 1696 | sio_data->internal |= (1 << 1); | 1726 | sio_data->internal |= (1 << 1); |
| 1697 | 1727 | ||
| 1698 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; | 1728 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; |
| @@ -1770,6 +1800,7 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
| 1770 | "it8718", | 1800 | "it8718", |
| 1771 | "it8720", | 1801 | "it8720", |
| 1772 | "it8721", | 1802 | "it8721", |
| 1803 | "it8728", | ||
| 1773 | }; | 1804 | }; |
| 1774 | 1805 | ||
| 1775 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1806 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
| @@ -1807,7 +1838,7 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
| 1807 | enable_pwm_interface = it87_check_pwm(dev); | 1838 | enable_pwm_interface = it87_check_pwm(dev); |
| 1808 | 1839 | ||
| 1809 | /* Starting with IT8721F, we handle scaling of internal voltages */ | 1840 | /* Starting with IT8721F, we handle scaling of internal voltages */ |
| 1810 | if (data->type == it8721) { | 1841 | if (has_12mv_adc(data)) { |
| 1811 | if (sio_data->internal & (1 << 0)) | 1842 | if (sio_data->internal & (1 << 0)) |
| 1812 | data->in_scaled |= (1 << 3); /* in3 is AVCC */ | 1843 | data->in_scaled |= (1 << 3); /* in3 is AVCC */ |
| 1813 | if (sio_data->internal & (1 << 1)) | 1844 | if (sio_data->internal & (1 << 1)) |
| @@ -2093,7 +2124,7 @@ static void __devinit it87_init_device(struct platform_device *pdev) | |||
| 2093 | static void it87_update_pwm_ctrl(struct it87_data *data, int nr) | 2124 | static void it87_update_pwm_ctrl(struct it87_data *data, int nr) |
| 2094 | { | 2125 | { |
| 2095 | data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr)); | 2126 | data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr)); |
| 2096 | if (data->type == it8721) { | 2127 | if (has_newer_autopwm(data)) { |
| 2097 | data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; | 2128 | data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; |
| 2098 | data->pwm_duty[nr] = it87_read_value(data, | 2129 | data->pwm_duty[nr] = it87_read_value(data, |
| 2099 | IT87_REG_PWM_DUTY(nr)); | 2130 | IT87_REG_PWM_DUTY(nr)); |
