diff options
author | Guenter Roeck <linux@roeck-us.net> | 2012-03-02 14:46:44 -0500 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2012-05-20 22:41:48 -0400 |
commit | 0531d98b1f2ec6f92074e5b2a74927b865bc605c (patch) | |
tree | 2546a596b517da316c3cd07c0e99aafec27322ce /drivers/hwmon | |
parent | 76e10d158efb6d4516018846f60c2ab5501900bc (diff) |
hwmon: (it87) Add support for IT8782F and IT8783E/F
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/it87.c | 125 |
1 files changed, 99 insertions, 26 deletions
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 0b204e4cf51c..aebac1334ff6 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c | |||
@@ -19,6 +19,8 @@ | |||
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 | * IT8728F Super I/O chip w/LPC interface |
21 | * IT8758E Super I/O chip w/LPC interface | 21 | * IT8758E Super I/O chip w/LPC interface |
22 | * IT8782F Super I/O chip w/LPC interface | ||
23 | * IT8783E/F Super I/O chip w/LPC interface | ||
22 | * Sis950 A clone of the IT8705F | 24 | * Sis950 A clone of the IT8705F |
23 | * | 25 | * |
24 | * Copyright (C) 2001 Chris Gauthron | 26 | * Copyright (C) 2001 Chris Gauthron |
@@ -59,7 +61,8 @@ | |||
59 | 61 | ||
60 | #define DRVNAME "it87" | 62 | #define DRVNAME "it87" |
61 | 63 | ||
62 | enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 }; | 64 | enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782, |
65 | it8783 }; | ||
63 | 66 | ||
64 | static unsigned short force_id; | 67 | static unsigned short force_id; |
65 | module_param(force_id, ushort, 0); | 68 | module_param(force_id, ushort, 0); |
@@ -137,13 +140,18 @@ static inline void superio_exit(void) | |||
137 | #define IT8721F_DEVID 0x8721 | 140 | #define IT8721F_DEVID 0x8721 |
138 | #define IT8726F_DEVID 0x8726 | 141 | #define IT8726F_DEVID 0x8726 |
139 | #define IT8728F_DEVID 0x8728 | 142 | #define IT8728F_DEVID 0x8728 |
143 | #define IT8782F_DEVID 0x8782 | ||
144 | #define IT8783E_DEVID 0x8783 | ||
140 | #define IT87_ACT_REG 0x30 | 145 | #define IT87_ACT_REG 0x30 |
141 | #define IT87_BASE_REG 0x60 | 146 | #define IT87_BASE_REG 0x60 |
142 | 147 | ||
143 | /* Logical device 7 registers (IT8712F and later) */ | 148 | /* Logical device 7 registers (IT8712F and later) */ |
149 | #define IT87_SIO_GPIO1_REG 0x25 | ||
144 | #define IT87_SIO_GPIO3_REG 0x27 | 150 | #define IT87_SIO_GPIO3_REG 0x27 |
145 | #define IT87_SIO_GPIO5_REG 0x29 | 151 | #define IT87_SIO_GPIO5_REG 0x29 |
152 | #define IT87_SIO_PINX1_REG 0x2a /* Pin selection */ | ||
146 | #define IT87_SIO_PINX2_REG 0x2c /* Pin selection */ | 153 | #define IT87_SIO_PINX2_REG 0x2c /* Pin selection */ |
154 | #define IT87_SIO_SPI_REG 0xef /* SPI function pin select */ | ||
147 | #define IT87_SIO_VID_REG 0xfc /* VID value */ | 155 | #define IT87_SIO_VID_REG 0xfc /* VID value */ |
148 | #define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ | 156 | #define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ |
149 | 157 | ||
@@ -304,31 +312,23 @@ static inline int has_newer_autopwm(const struct it87_data *data) | |||
304 | || data->type == it8728; | 312 | || data->type == it8728; |
305 | } | 313 | } |
306 | 314 | ||
307 | static u8 in_to_reg(const struct it87_data *data, int nr, long val) | 315 | static int adc_lsb(const struct it87_data *data, int nr) |
308 | { | 316 | { |
309 | long lsb; | 317 | int lsb = has_12mv_adc(data) ? 12 : 16; |
310 | 318 | if (data->in_scaled & (1 << nr)) | |
311 | if (has_12mv_adc(data)) { | 319 | lsb <<= 1; |
312 | if (data->in_scaled & (1 << nr)) | 320 | return lsb; |
313 | lsb = 24; | 321 | } |
314 | else | ||
315 | lsb = 12; | ||
316 | } else | ||
317 | lsb = 16; | ||
318 | 322 | ||
319 | val = DIV_ROUND_CLOSEST(val, lsb); | 323 | static u8 in_to_reg(const struct it87_data *data, int nr, long val) |
324 | { | ||
325 | val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr)); | ||
320 | return SENSORS_LIMIT(val, 0, 255); | 326 | return SENSORS_LIMIT(val, 0, 255); |
321 | } | 327 | } |
322 | 328 | ||
323 | static int in_from_reg(const struct it87_data *data, int nr, int val) | 329 | static int in_from_reg(const struct it87_data *data, int nr, int val) |
324 | { | 330 | { |
325 | if (has_12mv_adc(data)) { | 331 | return val * adc_lsb(data, nr); |
326 | if (data->in_scaled & (1 << nr)) | ||
327 | return val * 24; | ||
328 | else | ||
329 | return val * 12; | ||
330 | } else | ||
331 | return val * 16; | ||
332 | } | 332 | } |
333 | 333 | ||
334 | static inline u8 FAN_TO_REG(long rpm, int div) | 334 | static inline u8 FAN_TO_REG(long rpm, int div) |
@@ -407,7 +407,9 @@ static inline int has_16bit_fans(const struct it87_data *data) | |||
407 | || data->type == it8718 | 407 | || data->type == it8718 |
408 | || data->type == it8720 | 408 | || data->type == it8720 |
409 | || data->type == it8721 | 409 | || data->type == it8721 |
410 | || data->type == it8728; | 410 | || data->type == it8728 |
411 | || data->type == it8782 | ||
412 | || data->type == it8783; | ||
411 | } | 413 | } |
412 | 414 | ||
413 | static inline int has_old_autopwm(const struct it87_data *data) | 415 | static inline int has_old_autopwm(const struct it87_data *data) |
@@ -1651,6 +1653,12 @@ static int __init it87_find(unsigned short *address, | |||
1651 | case IT8728F_DEVID: | 1653 | case IT8728F_DEVID: |
1652 | sio_data->type = it8728; | 1654 | sio_data->type = it8728; |
1653 | break; | 1655 | break; |
1656 | case IT8782F_DEVID: | ||
1657 | sio_data->type = it8782; | ||
1658 | break; | ||
1659 | case IT8783E_DEVID: | ||
1660 | sio_data->type = it8783; | ||
1661 | break; | ||
1654 | case 0xffff: /* No device at all */ | 1662 | case 0xffff: /* No device at all */ |
1655 | goto exit; | 1663 | goto exit; |
1656 | default: | 1664 | default: |
@@ -1686,16 +1694,68 @@ static int __init it87_find(unsigned short *address, | |||
1686 | /* The IT8705F has a different LD number for GPIO */ | 1694 | /* The IT8705F has a different LD number for GPIO */ |
1687 | superio_select(5); | 1695 | superio_select(5); |
1688 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; | 1696 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; |
1697 | } else if (sio_data->type == it8783) { | ||
1698 | int reg25, reg27, reg2A, reg2C, regEF; | ||
1699 | bool uart6; | ||
1700 | |||
1701 | sio_data->skip_vid = 1; /* No VID */ | ||
1702 | |||
1703 | superio_select(GPIO); | ||
1704 | |||
1705 | reg25 = superio_inb(IT87_SIO_GPIO1_REG); | ||
1706 | reg27 = superio_inb(IT87_SIO_GPIO3_REG); | ||
1707 | reg2A = superio_inb(IT87_SIO_PINX1_REG); | ||
1708 | reg2C = superio_inb(IT87_SIO_PINX2_REG); | ||
1709 | regEF = superio_inb(IT87_SIO_SPI_REG); | ||
1710 | |||
1711 | uart6 = reg2C & (1 << 2); | ||
1712 | |||
1713 | /* Check if fan3 is there or not */ | ||
1714 | if ((reg27 & (1 << 0)) || !uart6) | ||
1715 | sio_data->skip_fan |= (1 << 2); | ||
1716 | if ((reg25 & (1 << 4)) | ||
1717 | || (!(reg2A & (1 << 1)) && (regEF & (1 << 0)))) | ||
1718 | sio_data->skip_pwm |= (1 << 2); | ||
1719 | |||
1720 | /* Check if fan2 is there or not */ | ||
1721 | if (reg27 & (1 << 7)) | ||
1722 | sio_data->skip_fan |= (1 << 1); | ||
1723 | if (reg27 & (1 << 3)) | ||
1724 | sio_data->skip_pwm |= (1 << 1); | ||
1725 | |||
1726 | /* VIN5 */ | ||
1727 | if ((reg27 & (1 << 0)) || uart6) | ||
1728 | ; /* No VIN5 */ | ||
1729 | |||
1730 | /* VIN6 */ | ||
1731 | if ((reg27 & (1 << 1)) || uart6) | ||
1732 | ; /* No VIN6 */ | ||
1733 | |||
1734 | /* | ||
1735 | * VIN7 | ||
1736 | * Does not depend on bit 2 of Reg2C, contrary to datasheet. | ||
1737 | */ | ||
1738 | if (reg27 & (1 << 2)) | ||
1739 | ; /* No VIN7 (unless internal) */ | ||
1740 | |||
1741 | if (reg2C & (1 << 0)) | ||
1742 | sio_data->internal |= (1 << 0); | ||
1743 | if (reg2C & (1 << 1)) | ||
1744 | sio_data->internal |= (1 << 1); | ||
1745 | |||
1746 | sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; | ||
1747 | |||
1689 | } else { | 1748 | } else { |
1690 | int reg; | 1749 | int reg; |
1691 | 1750 | ||
1692 | superio_select(GPIO); | 1751 | superio_select(GPIO); |
1693 | 1752 | ||
1694 | reg = superio_inb(IT87_SIO_GPIO3_REG); | 1753 | reg = superio_inb(IT87_SIO_GPIO3_REG); |
1695 | if (sio_data->type == it8721 || sio_data->type == it8728) { | 1754 | if (sio_data->type == it8721 || sio_data->type == it8728 || |
1755 | sio_data->type == it8782) { | ||
1696 | /* | 1756 | /* |
1697 | * The IT8721F/IT8758E doesn't have VID pins at all, | 1757 | * IT8721F/IT8758E, and IT8782F don't have VID pins |
1698 | * not sure about the IT8728F. | 1758 | * at all, not sure about the IT8728F. |
1699 | */ | 1759 | */ |
1700 | sio_data->skip_vid = 1; | 1760 | sio_data->skip_vid = 1; |
1701 | } else { | 1761 | } else { |
@@ -1733,8 +1793,13 @@ static int __init it87_find(unsigned short *address, | |||
1733 | * configured, even though the IT8720F datasheet claims | 1793 | * configured, even though the IT8720F datasheet claims |
1734 | * that the internal routing of VCCH to VIN7 is the default | 1794 | * that the internal routing of VCCH to VIN7 is the default |
1735 | * setting. So we force the internal routing in this case. | 1795 | * setting. So we force the internal routing in this case. |
1796 | * | ||
1797 | * On IT8782F, VIN7 is multiplexed with one of the UART6 pins. | ||
1798 | * If UART6 is enabled, re-route VIN7 to the internal divider. | ||
1736 | */ | 1799 | */ |
1737 | if (sio_data->type == it8720 && !(reg & (1 << 1))) { | 1800 | if ((sio_data->type == it8720 || |
1801 | (sio_data->type == it8782 && (reg & (1 << 2)))) | ||
1802 | && !(reg & (1 << 1))) { | ||
1738 | reg |= (1 << 1); | 1803 | reg |= (1 << 1); |
1739 | superio_outb(IT87_SIO_PINX2_REG, reg); | 1804 | superio_outb(IT87_SIO_PINX2_REG, reg); |
1740 | pr_notice("Routing internal VCCH to in7\n"); | 1805 | pr_notice("Routing internal VCCH to in7\n"); |
@@ -1823,6 +1888,8 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1823 | "it8720", | 1888 | "it8720", |
1824 | "it8721", | 1889 | "it8721", |
1825 | "it8728", | 1890 | "it8728", |
1891 | "it8782", | ||
1892 | "it8783", | ||
1826 | }; | 1893 | }; |
1827 | 1894 | ||
1828 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1895 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
@@ -1867,6 +1934,11 @@ static int __devinit it87_probe(struct platform_device *pdev) | |||
1867 | data->in_scaled |= (1 << 7); /* in7 is VSB */ | 1934 | data->in_scaled |= (1 << 7); /* in7 is VSB */ |
1868 | if (sio_data->internal & (1 << 2)) | 1935 | if (sio_data->internal & (1 << 2)) |
1869 | data->in_scaled |= (1 << 8); /* in8 is Vbat */ | 1936 | data->in_scaled |= (1 << 8); /* in8 is Vbat */ |
1937 | } else if (sio_data->type == it8782 || sio_data->type == it8783) { | ||
1938 | if (sio_data->internal & (1 << 0)) | ||
1939 | data->in_scaled |= (1 << 3); /* in3 is VCC5V */ | ||
1940 | if (sio_data->internal & (1 << 1)) | ||
1941 | data->in_scaled |= (1 << 7); /* in7 is VCCH5V */ | ||
1870 | } | 1942 | } |
1871 | 1943 | ||
1872 | /* Initialize the IT87 chip */ | 1944 | /* Initialize the IT87 chip */ |
@@ -2143,8 +2215,9 @@ static void __devinit it87_init_device(struct platform_device *pdev) | |||
2143 | it87_write_value(data, IT87_REG_FAN_16BIT, | 2215 | it87_write_value(data, IT87_REG_FAN_16BIT, |
2144 | tmp | 0x07); | 2216 | tmp | 0x07); |
2145 | } | 2217 | } |
2146 | /* IT8705F only supports three fans. */ | 2218 | /* IT8705F, IT8782F, and IT8783E/F only support three fans. */ |
2147 | if (data->type != it87) { | 2219 | if (data->type != it87 && data->type != it8782 && |
2220 | data->type != it8783) { | ||
2148 | if (tmp & (1 << 4)) | 2221 | if (tmp & (1 << 4)) |
2149 | data->has_fan |= (1 << 3); /* fan4 enabled */ | 2222 | data->has_fan |= (1 << 3); /* fan4 enabled */ |
2150 | if (tmp & (1 << 5)) | 2223 | if (tmp & (1 << 5)) |