Commit 16b5dda22e3798e61bb008d2329d4f4d90ef764e
Committed by
Jean Delvare
1 parent
d6db23c7ce
Exists in
master
and in
37 other branches
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>
Showing 3 changed files with 58 additions and 20 deletions Side-by-side Diff
Documentation/hwmon/it87
... | ... | @@ -26,6 +26,10 @@ |
26 | 26 | Prefix: 'it8721' |
27 | 27 | Addresses scanned: from Super I/O config space (8 I/O ports) |
28 | 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 | 33 | * SiS950 [clone of IT8705F] |
30 | 34 | Prefix: 'it87' |
31 | 35 | Addresses scanned: from Super I/O config space (8 I/O ports) |
... | ... | @@ -71,7 +75,7 @@ |
71 | 75 | ----------- |
72 | 76 | |
73 | 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 | 80 | These chips are 'Super I/O chips', supporting floppy disks, infrared ports, |
77 | 81 | joysticks and other miscellaneous stuff. For hardware monitoring, they |
... | ... | @@ -105,6 +109,9 @@ |
105 | 109 | for AMD power sequencing. Therefore the chip will appear as IT8716F |
106 | 110 | to userspace applications. |
107 | 111 | |
112 | +The IT8728F is considered compatible with the IT8721F, until a datasheet | |
113 | +becomes available (hopefully.) | |
114 | + | |
108 | 115 | Temperatures are measured in degrees Celsius. An alarm is triggered once |
109 | 116 | when the Overtemperature Shutdown limit is crossed. |
110 | 117 | |
... | ... | @@ -121,8 +128,8 @@ |
121 | 128 | maximum limit. Note that minimum in this case always means 'closest to |
122 | 129 | zero'; this is important for negative voltage measurements. All voltage |
123 | 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 | |
125 | -not have limit registers. | |
131 | +0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery | |
132 | +voltage in8 does not have limit registers. | |
126 | 133 | |
127 | 134 | On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside |
128 | 135 | the chip (in7, in8 and optionally in3). The driver handles this transparently |
drivers/hwmon/Kconfig
... | ... | @@ -474,8 +474,8 @@ |
474 | 474 | select HWMON_VID |
475 | 475 | help |
476 | 476 | If you say yes here you get support for ITE IT8705F, IT8712F, |
477 | - IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor | |
478 | - chips, and the SiS960 clone. | |
477 | + IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E | |
478 | + sensor chips, and the SiS960 clone. | |
479 | 479 | |
480 | 480 | This driver can also be built as a module. If so, the module |
481 | 481 | will be called it87. |
drivers/hwmon/it87.c
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 | * IT8720F Super I/O chip w/LPC interface |
18 | 18 | * IT8721F Super I/O chip w/LPC interface |
19 | 19 | * IT8726F Super I/O chip w/LPC interface |
20 | + * IT8728F Super I/O chip w/LPC interface | |
20 | 21 | * IT8758E Super I/O chip w/LPC interface |
21 | 22 | * Sis950 A clone of the IT8705F |
22 | 23 | * |
... | ... | @@ -58,7 +59,7 @@ |
58 | 59 | |
59 | 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 | 64 | static unsigned short force_id; |
64 | 65 | module_param(force_id, ushort, 0); |
... | ... | @@ -135,6 +136,7 @@ |
135 | 136 | #define IT8720F_DEVID 0x8720 |
136 | 137 | #define IT8721F_DEVID 0x8721 |
137 | 138 | #define IT8726F_DEVID 0x8726 |
139 | +#define IT8728F_DEVID 0x8728 | |
138 | 140 | #define IT87_ACT_REG 0x30 |
139 | 141 | #define IT87_BASE_REG 0x60 |
140 | 142 | |
141 | 143 | |
... | ... | @@ -274,11 +276,31 @@ |
274 | 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 | 299 | static u8 in_to_reg(const struct it87_data *data, int nr, long val) |
278 | 300 | { |
279 | 301 | long lsb; |
280 | 302 | |
281 | - if (data->type == it8721) { | |
303 | + if (has_12mv_adc(data)) { | |
282 | 304 | if (data->in_scaled & (1 << nr)) |
283 | 305 | lsb = 24; |
284 | 306 | else |
... | ... | @@ -292,7 +314,7 @@ |
292 | 314 | |
293 | 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 | 318 | if (data->in_scaled & (1 << nr)) |
297 | 319 | return val * 24; |
298 | 320 | else |
... | ... | @@ -329,7 +351,7 @@ |
329 | 351 | |
330 | 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 | 355 | return val; |
334 | 356 | else |
335 | 357 | return val >> 1; |
... | ... | @@ -337,7 +359,7 @@ |
337 | 359 | |
338 | 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 | 363 | return reg; |
342 | 364 | else |
343 | 365 | return (reg & 0x7f) << 1; |
... | ... | @@ -374,7 +396,8 @@ |
374 | 396 | || data->type == it8716 |
375 | 397 | || data->type == it8718 |
376 | 398 | || data->type == it8720 |
377 | - || data->type == it8721; | |
399 | + || data->type == it8721 | |
400 | + || data->type == it8728; | |
378 | 401 | } |
379 | 402 | |
380 | 403 | static inline int has_old_autopwm(const struct it87_data *data) |
... | ... | @@ -842,7 +865,7 @@ |
842 | 865 | data->fan_main_ctrl); |
843 | 866 | } else { |
844 | 867 | if (val == 1) /* Manual mode */ |
845 | - data->pwm_ctrl[nr] = data->type == it8721 ? | |
868 | + data->pwm_ctrl[nr] = has_newer_autopwm(data) ? | |
846 | 869 | data->pwm_temp_map[nr] : |
847 | 870 | data->pwm_duty[nr]; |
848 | 871 | else /* Automatic mode */ |
... | ... | @@ -870,7 +893,7 @@ |
870 | 893 | return -EINVAL; |
871 | 894 | |
872 | 895 | mutex_lock(&data->update_lock); |
873 | - if (data->type == it8721) { | |
896 | + if (has_newer_autopwm(data)) { | |
874 | 897 | /* If we are in automatic mode, the PWM duty cycle register |
875 | 898 | * is read-only so we can't write the value */ |
876 | 899 | if (data->pwm_ctrl[nr] & 0x80) { |
... | ... | @@ -1311,8 +1334,8 @@ |
1311 | 1334 | struct it87_data *data = dev_get_drvdata(dev); |
1312 | 1335 | int nr = to_sensor_dev_attr(attr)->index; |
1313 | 1336 | |
1314 | - return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr] | |
1315 | - : labels[nr]); | |
1337 | + return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr] | |
1338 | + : labels[nr]); | |
1316 | 1339 | } |
1317 | 1340 | static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); |
1318 | 1341 | static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); |
... | ... | @@ -1605,6 +1628,9 @@ |
1605 | 1628 | case IT8721F_DEVID: |
1606 | 1629 | sio_data->type = it8721; |
1607 | 1630 | break; |
1631 | + case IT8728F_DEVID: | |
1632 | + sio_data->type = it8728; | |
1633 | + break; | |
1608 | 1634 | case 0xffff: /* No device at all */ |
1609 | 1635 | goto exit; |
1610 | 1636 | default: |
... | ... | @@ -1646,8 +1672,11 @@ |
1646 | 1672 | superio_select(GPIO); |
1647 | 1673 | |
1648 | 1674 | reg = superio_inb(IT87_SIO_GPIO3_REG); |
1649 | - if (sio_data->type == it8721) { | |
1650 | - /* The IT8721F/IT8758E doesn't have VID pins at all */ | |
1675 | + if (sio_data->type == it8721 || sio_data->type == it8728) { | |
1676 | + /* | |
1677 | + * The IT8721F/IT8758E doesn't have VID pins at all, | |
1678 | + * not sure about the IT8728F. | |
1679 | + */ | |
1651 | 1680 | sio_data->skip_vid = 1; |
1652 | 1681 | } else { |
1653 | 1682 | /* We need at least 4 VID pins */ |
... | ... | @@ -1692,7 +1721,8 @@ |
1692 | 1721 | } |
1693 | 1722 | if (reg & (1 << 0)) |
1694 | 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 | 1726 | sio_data->internal |= (1 << 1); |
1697 | 1727 | |
1698 | 1728 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; |
... | ... | @@ -1770,6 +1800,7 @@ |
1770 | 1800 | "it8718", |
1771 | 1801 | "it8720", |
1772 | 1802 | "it8721", |
1803 | + "it8728", | |
1773 | 1804 | }; |
1774 | 1805 | |
1775 | 1806 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
... | ... | @@ -1807,7 +1838,7 @@ |
1807 | 1838 | enable_pwm_interface = it87_check_pwm(dev); |
1808 | 1839 | |
1809 | 1840 | /* Starting with IT8721F, we handle scaling of internal voltages */ |
1810 | - if (data->type == it8721) { | |
1841 | + if (has_12mv_adc(data)) { | |
1811 | 1842 | if (sio_data->internal & (1 << 0)) |
1812 | 1843 | data->in_scaled |= (1 << 3); /* in3 is AVCC */ |
1813 | 1844 | if (sio_data->internal & (1 << 1)) |
... | ... | @@ -2093,7 +2124,7 @@ |
2093 | 2124 | static void it87_update_pwm_ctrl(struct it87_data *data, int nr) |
2094 | 2125 | { |
2095 | 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 | 2128 | data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; |
2098 | 2129 | data->pwm_duty[nr] = it87_read_value(data, |
2099 | 2130 | IT87_REG_PWM_DUTY(nr)); |