]> git.sur5r.net Git - groeck-it87/blobdiff - it87.c
Added preliminary support for IT8665E
[groeck-it87] / it87.c
diff --git a/it87.c b/it87.c
index df87ffaec0baee34d70f77077cdbf1368ed8951e..8b0c2096439afe9a2bb2feed2d8eb68e5e67760f 100644 (file)
--- a/it87.c
+++ b/it87.c
  *  similar parts.  The other devices are supported by different drivers.
  *
  *  Supports: IT8603E  Super I/O chip w/LPC interface
+ *            IT8607E  Super I/O chip w/LPC interface
  *            IT8620E  Super I/O chip w/LPC interface
  *            IT8622E  Super I/O chip w/LPC interface
  *            IT8623E  Super I/O chip w/LPC interface
  *            IT8628E  Super I/O chip w/LPC interface
+ *            IT8665E  Super I/O chip w/LPC interface
+ *            IT8686E  Super I/O chip w/LPC interface
  *            IT8705F  Super I/O chip w/LPC interface
  *            IT8712F  Super I/O chip w/LPC interface
  *            IT8716F  Super I/O chip w/LPC interface
@@ -73,7 +76,8 @@
 
 enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732,
             it8771, it8772, it8781, it8782, it8783, it8786, it8790,
-            it8792, it8603, it8620, it8622, it8628 };
+            it8792, it8603, it8607, it8620, it8622, it8628, it8665,
+            it8686 };
 
 static unsigned short force_id;
 module_param(force_id, ushort, 0);
@@ -163,10 +167,13 @@ static inline void superio_exit(int ioreg)
 #define IT8786E_DEVID 0x8786
 #define IT8790E_DEVID 0x8790
 #define IT8603E_DEVID 0x8603
+#define IT8607E_DEVID 0x8607
 #define IT8620E_DEVID 0x8620
 #define IT8622E_DEVID 0x8622
 #define IT8623E_DEVID 0x8623
 #define IT8628E_DEVID 0x8628
+#define IT8665E_DEVID 0x8665
+#define IT8686E_DEVID 0x8686
 #define IT87_ACT_REG  0x30
 #define IT87_BASE_REG 0x60
 
@@ -176,8 +183,10 @@ static inline void superio_exit(int ioreg)
 #define IT87_SIO_GPIO3_REG     0x27
 #define IT87_SIO_GPIO4_REG     0x28
 #define IT87_SIO_GPIO5_REG     0x29
+#define IT87_SIO_GPIO9_REG     0xd3
 #define IT87_SIO_PINX1_REG     0x2a    /* Pin selection */
 #define IT87_SIO_PINX2_REG     0x2c    /* Pin selection */
+#define IT87_SIO_PINX4_REG     0x2d    /* Pin selection */
 #define IT87_SIO_SPI_REG       0xef    /* SPI function pin select */
 #define IT87_SIO_VID_REG       0xfc    /* VID value */
 #define IT87_SIO_BEEP_PIN_REG  0xf6    /* Beep pin mapping */
@@ -211,6 +220,8 @@ static bool fix_pwm_polarity;
 #define IT87_REG_ALARM2        0x02
 #define IT87_REG_ALARM3        0x03
 
+#define IT87_REG_BANK          0x06
+
 /*
  * The IT8718F and IT8720F have the VID value in a different register, in
  * Super-I/O configuration space.
@@ -303,6 +314,10 @@ struct it87_devices {
 #define FEAT_PWM_FREQ2         BIT(16) /* Separate pwm freq 2 */
 #define FEAT_SIX_TEMP          BIT(17) /* Up to 6 temp sensors */
 #define FEAT_VIN3_5V           BIT(18) /* VIN3 connected to +5V */
+#define FEAT_FOUR_FANS         BIT(19) /* Supports four fans */
+#define FEAT_FOUR_PWM          BIT(20) /* Supports four fan controls */
+#define FEAT_BANK_SEL          BIT(21) /* Chip has multi-bank support */
+#define FEAT_SCALING           BIT(22) /* Internal voltage scaling */
 
 static const struct it87_devices it87_devices[] = {
        [it87] = {
@@ -344,7 +359,7 @@ static const struct it87_devices it87_devices[] = {
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
                  | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
-                 | FEAT_PWM_FREQ2,
+                 | FEAT_PWM_FREQ2 | FEAT_SCALING,
                .peci_mask = 0x05,
                .old_peci_mask = 0x02,  /* Actually reports PCH */
        },
@@ -353,7 +368,7 @@ static const struct it87_devices it87_devices[] = {
                .suffix = "F",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
-                 | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
+                 | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_SCALING,
                .peci_mask = 0x07,
        },
        [it8732] = {
@@ -361,7 +376,8 @@ static const struct it87_devices it87_devices[] = {
                .suffix = "F",
                .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
-                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
+                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS
+                 | FEAT_FOUR_PWM,
                .peci_mask = 0x07,
                .old_peci_mask = 0x02,  /* Actually reports PCH */
        },
@@ -370,7 +386,7 @@ static const struct it87_devices it87_devices[] = {
                .suffix = "E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
-                 | FEAT_PWM_FREQ2,
+                 | FEAT_PWM_FREQ2 | FEAT_SCALING,
                                /* PECI: guesswork */
                                /* 12mV ADC (OHM) */
                                /* 16 bit fans (OHM) */
@@ -382,7 +398,7 @@ static const struct it87_devices it87_devices[] = {
                .suffix = "E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
-                 | FEAT_PWM_FREQ2,
+                 | FEAT_PWM_FREQ2 | FEAT_SCALING,
                                /* PECI (coreboot) */
                                /* 12mV ADC (HWSensors4, OHM) */
                                /* 16 bit fans (HWSensors4, OHM) */
@@ -421,26 +437,33 @@ static const struct it87_devices it87_devices[] = {
        [it8790] = {
                .name = "it8790",
                .suffix = "E",
-               .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
-                 | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
-                 | FEAT_PWM_FREQ2,
+               .features = FEAT_NEWER_AUTOPWM | FEAT_10_9MV_ADC | FEAT_SCALING
+                 | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI
+                 | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
                .peci_mask = 0x07,
        },
        [it8792] = {
                .name = "it8792",
                .suffix = "E",
-               .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
-                 | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
-                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
+               .features = FEAT_NEWER_AUTOPWM | FEAT_10_9MV_ADC | FEAT_SCALING
+                 | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI
+                 | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
                .peci_mask = 0x07,
-               .old_peci_mask = 0x02,  /* Actually reports PCH */
        },
        [it8603] = {
                .name = "it8603",
                .suffix = "E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
-                 | FEAT_AVCC3 | FEAT_PWM_FREQ2,
+                 | FEAT_AVCC3 | FEAT_PWM_FREQ2 | FEAT_SCALING,
+               .peci_mask = 0x07,
+       },
+       [it8607] = {
+               .name = "it8607",
+               .suffix = "E",
+               .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+                 | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+                 | FEAT_AVCC3 | FEAT_PWM_FREQ2 | FEAT_SCALING,
                .peci_mask = 0x07,
        },
        [it8620] = {
@@ -449,7 +472,7 @@ static const struct it87_devices it87_devices[] = {
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
                  | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
-                 | FEAT_SIX_TEMP | FEAT_VIN3_5V,
+                 | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_SCALING,
                .peci_mask = 0x07,
        },
        [it8622] = {
@@ -458,7 +481,7 @@ static const struct it87_devices it87_devices[] = {
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
                  | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
-                 | FEAT_AVCC3 | FEAT_VIN3_5V,
+                 | FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_SCALING,
                .peci_mask = 0x07,
        },
        [it8628] = {
@@ -467,7 +490,25 @@ static const struct it87_devices it87_devices[] = {
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
                  | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
-                 | FEAT_SIX_TEMP | FEAT_VIN3_5V,
+                 | FEAT_SIX_TEMP | FEAT_SCALING,
+               .peci_mask = 0x07,
+       },
+       [it8665] = {
+               .name = "it8665",
+               .suffix = "E",
+               .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
+                 | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
+                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_SIX_FANS
+                 | FEAT_SIX_PWM | FEAT_BANK_SEL,
+               .peci_mask = 0x07,
+       },
+       [it8686] = {
+               .name = "it8686",
+               .suffix = "E",
+               .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+                 | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
+                 | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
+                 | FEAT_SIX_TEMP | FEAT_BANK_SEL | FEAT_SCALING,
                .peci_mask = 0x07,
        },
 };
@@ -496,6 +537,14 @@ static const struct it87_devices it87_devices[] = {
 #define has_pwm_freq2(data)    ((data)->features & FEAT_PWM_FREQ2)
 #define has_six_temp(data)     ((data)->features & FEAT_SIX_TEMP)
 #define has_vin3_5v(data)      ((data)->features & FEAT_VIN3_5V)
+#define has_four_fans(data)    ((data)->features & (FEAT_FOUR_FANS | \
+                                                    FEAT_FIVE_FANS | \
+                                                    FEAT_SIX_FANS))
+#define has_four_pwm(data)     ((data)->features & (FEAT_FOUR_PWM | \
+                                                    FEAT_FIVE_PWM \
+                                                    | FEAT_SIX_PWM))
+#define has_bank_sel(data)     ((data)->features & FEAT_BANK_SEL)
+#define has_scaling(data)      ((data)->features & FEAT_SCALING)
 
 struct it87_sio_data {
        enum chips type;
@@ -520,6 +569,7 @@ struct it87_data {
        const struct attribute_group *groups[7];
        enum chips type;
        u32 features;
+       u8 bank;
        u8 peci_mask;
        u8 old_peci_mask;
 
@@ -668,15 +718,39 @@ static const unsigned int pwm_freq[8] = {
        750000,
 };
 
+static int _it87_read_value(struct it87_data *data, u8 reg)
+{
+       outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+       return inb_p(data->addr + IT87_DATA_REG_OFFSET);
+}
+
+static void _it87_write_value(struct it87_data *data, u8 reg, u8 value)
+{
+       outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+       outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
+}
+
+static void it87_set_bank(struct it87_data *data, u8 bank)
+{
+       if (has_bank_sel(data) && bank != data->bank) {
+               u8 breg = _it87_read_value(data, IT87_REG_BANK);
+
+               breg &= 0x1f;
+               breg |= (bank << 5);
+               data->bank = bank;
+               _it87_write_value(data, IT87_REG_BANK, breg);
+       }
+}
+
 /*
  * Must be called with data->update_lock held, except during initialization.
  * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
  * would slow down the IT87 access and should not be necessary.
  */
-static int it87_read_value(struct it87_data *data, u8 reg)
+static int it87_read_value(struct it87_data *data, u16 reg)
 {
-       outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
-       return inb_p(data->addr + IT87_DATA_REG_OFFSET);
+       it87_set_bank(data, reg >> 8);
+       return _it87_read_value(data, reg & 0xff);
 }
 
 /*
@@ -684,10 +758,10 @@ static int it87_read_value(struct it87_data *data, u8 reg)
  * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
  * would slow down the IT87 access and should not be necessary.
  */
-static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
+static void it87_write_value(struct it87_data *data, u16 reg, u8 value)
 {
-       outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
-       outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
+       it87_set_bank(data, reg >> 8);
+       _it87_write_value(data, reg & 0xff, value);
 }
 
 static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
@@ -1328,25 +1402,35 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
                        it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
                                         data->fan_main_ctrl);
                } else {
+                       u8 ctrl;
+
                        /* No on/off mode, set maximum pwm value */
                        data->pwm_duty[nr] = pwm_to_reg(data, 0xff);
                        it87_write_value(data, IT87_REG_PWM_DUTY[nr],
                                         data->pwm_duty[nr]);
                        /* and set manual mode */
-                       data->pwm_ctrl[nr] = has_newer_autopwm(data) ?
-                                            data->pwm_temp_map[nr] :
-                                            data->pwm_duty[nr];
-                       it87_write_value(data, IT87_REG_PWM[nr],
-                                        data->pwm_ctrl[nr]);
+                       if (has_newer_autopwm(data)) {
+                               ctrl = (data->pwm_ctrl[nr] & 0x7c) |
+                                       data->pwm_temp_map[nr];
+                       } else {
+                               ctrl = data->pwm_duty[nr];
+                       }
+                       data->pwm_ctrl[nr] = ctrl;
+                       it87_write_value(data, IT87_REG_PWM[nr], ctrl);
                }
        } else {
-               if (val == 1)                           /* Manual mode */
-                       data->pwm_ctrl[nr] = has_newer_autopwm(data) ?
-                                            data->pwm_temp_map[nr] :
-                                            data->pwm_duty[nr];
-               else                                    /* Automatic mode */
-                       data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
-               it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
+               u8 ctrl;
+
+               if (has_newer_autopwm(data)) {
+                       ctrl = (data->pwm_ctrl[nr] & 0x7c) |
+                               data->pwm_temp_map[nr];
+                       if (val != 1)
+                               ctrl |= 0x80;
+               } else {
+                       ctrl = (val == 1 ? data->pwm_duty[nr] : 0x80);
+               }
+               data->pwm_ctrl[nr] = ctrl;
+               it87_write_value(data, IT87_REG_PWM[nr], ctrl);
 
                if (data->type != it8603 && nr < 3) {
                        /* set SmartGuardian mode */
@@ -1492,7 +1576,8 @@ static ssize_t set_pwm_temp_map(struct device *dev,
         * otherwise, just store it for later use.
         */
        if (data->pwm_ctrl[nr] & 0x80) {
-               data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
+               data->pwm_ctrl[nr] = (data->pwm_ctrl[nr] & 0xfc) |
+                                               data->pwm_temp_map[nr];
                it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
        }
        mutex_unlock(&data->update_lock);
@@ -2392,7 +2477,12 @@ static int __init it87_find(int sioaddr, unsigned short *address,
                return err;
 
        err = -ENODEV;
-       chip_type = force_id ? force_id : superio_inw(sioaddr, DEVID);
+       chip_type = superio_inw(sioaddr, DEVID);
+       if (chip_type == 0xffff)
+               goto exit;
+
+       if (force_id)
+               chip_type = force_id;
 
        switch (chip_type) {
        case IT8705F_DEVID:
@@ -2448,6 +2538,9 @@ static int __init it87_find(int sioaddr, unsigned short *address,
        case IT8623E_DEVID:
                sio_data->type = it8603;
                break;
+       case IT8607E_DEVID:
+               sio_data->type = it8607;
+               break;
        case IT8620E_DEVID:
                sio_data->type = it8620;
                break;
@@ -2457,6 +2550,12 @@ static int __init it87_find(int sioaddr, unsigned short *address,
        case IT8628E_DEVID:
                sio_data->type = it8628;
                break;
+       case IT8665E_DEVID:
+               sio_data->type = it8665;
+               break;
+       case IT8686E_DEVID:
+               sio_data->type = it8686;
+               break;
        case 0xffff:    /* No device at all */
                goto exit;
        default:
@@ -2497,8 +2596,10 @@ static int __init it87_find(int sioaddr, unsigned short *address,
        else
                sio_data->skip_in |= BIT(9);
 
-       if (!has_five_pwm(config))
+       if (!has_four_pwm(config))
                sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5);
+       else if (!has_five_pwm(config))
+               sio_data->skip_pwm |= BIT(4) | BIT(5);
        else if (!has_six_pwm(config))
                sio_data->skip_pwm |= BIT(5);
 
@@ -2578,7 +2679,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,
 
                sio_data->beep_pin = superio_inb(sioaddr,
                                                 IT87_SIO_BEEP_PIN_REG) & 0x3f;
-       } else if (sio_data->type == it8603) {
+       } else if (sio_data->type == it8603 || sio_data->type == it8607) {
                int reg27, reg29;
 
                superio_select(sioaddr, GPIO);
@@ -2598,12 +2699,15 @@ static int __init it87_find(int sioaddr, unsigned short *address,
                if (reg29 & BIT(2))
                        sio_data->skip_fan |= BIT(1);
 
-               sio_data->skip_in |= BIT(5); /* No VIN5 */
-               sio_data->skip_in |= BIT(6); /* No VIN6 */
+               if (sio_data->type == it8603) {
+                       sio_data->skip_in |= BIT(5); /* No VIN5 */
+                       sio_data->skip_in |= BIT(6); /* No VIN6 */
+               }
 
                sio_data->beep_pin = superio_inb(sioaddr,
                                                 IT87_SIO_BEEP_PIN_REG) & 0x3f;
-       } else if (sio_data->type == it8620 || sio_data->type == it8628) {
+       } else if (sio_data->type == it8620 || sio_data->type == it8628 ||
+                  sio_data->type == it8686) {
                int reg;
 
                superio_select(sioaddr, GPIO);
@@ -2629,7 +2733,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,
 
                /* Check for pwm4 */
                reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG);
-               if (!(reg & BIT(2)))
+               if (reg & BIT(2))
                        sio_data->skip_pwm |= BIT(3);
 
                /* Check for pwm2, fan2 */
@@ -2688,6 +2792,76 @@ static int __init it87_find(int sioaddr, unsigned short *address,
                if (!(reg & BIT(0)))
                        sio_data->skip_in |= BIT(9);
 
+               sio_data->beep_pin = superio_inb(sioaddr,
+                                                IT87_SIO_BEEP_PIN_REG) & 0x3f;
+       } else if (sio_data->type == it8732) {
+               int reg;
+
+               superio_select(sioaddr, GPIO);
+
+               /* Check for pwm2, fan2 */
+               reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
+               if (reg & BIT(1))
+                       sio_data->skip_pwm |= BIT(1);
+               if (reg & BIT(2))
+                       sio_data->skip_fan |= BIT(1);
+
+               /* Check for pwm3, fan3, fan4 */
+               reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
+               if (reg & BIT(6))
+                       sio_data->skip_pwm |= BIT(2);
+               if (reg & BIT(7))
+                       sio_data->skip_fan |= BIT(2);
+               if (reg & BIT(5))
+                       sio_data->skip_fan |= BIT(3);
+
+               /* Check if AVCC is on VIN3 */
+               reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
+               if (reg & BIT(0))
+                       sio_data->internal |= BIT(0);
+
+               sio_data->beep_pin = superio_inb(sioaddr,
+                                                IT87_SIO_BEEP_PIN_REG) & 0x3f;
+       } else if (sio_data->type == it8665) {
+               int reg;
+
+               superio_select(sioaddr, GPIO);
+
+               /* Check for pwm2 */
+               reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
+               if (reg & BIT(1))
+                       sio_data->skip_pwm |= BIT(1);
+
+               /* Check for fan2 */
+               reg = superio_inb(sioaddr, IT87_SIO_PINX4_REG);
+               if (reg & BIT(4))
+                       sio_data->skip_fan |= BIT(1);
+
+               /* Check for pwm3, fan3 */
+               reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
+               if (reg & BIT(6))
+                       sio_data->skip_pwm |= BIT(2);
+               if (reg & BIT(7))
+                       sio_data->skip_fan |= BIT(2);
+
+               /* Check for pwm5, fan5 */
+               reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
+               if (reg & BIT(5))
+                       sio_data->skip_pwm |= BIT(4);
+               if (!(reg & BIT(4)))
+                       sio_data->skip_fan |= BIT(4);
+
+               /* Check for pwm4, fan4, pwm6, fan6 */
+               reg = superio_inb(sioaddr, IT87_SIO_GPIO9_REG);
+               if (reg & BIT(2))
+                       sio_data->skip_pwm |= BIT(3);
+               if (reg & BIT(3))
+                       sio_data->skip_fan |= BIT(3);
+               if (reg & BIT(0))
+                       sio_data->skip_pwm |= BIT(5);
+               if (reg & BIT(1))
+                       sio_data->skip_fan |= BIT(5);
+
                sio_data->beep_pin = superio_inb(sioaddr,
                                                 IT87_SIO_BEEP_PIN_REG) & 0x3f;
        } else {
@@ -2901,26 +3075,43 @@ static void it87_init_device(struct platform_device *pdev)
        }
 
        /* Check for additional fans */
-       if (has_five_fans(data)) {
-               if (tmp & BIT(4))
-                       data->has_fan |= BIT(3); /* fan4 enabled */
-               if (tmp & BIT(5))
-                       data->has_fan |= BIT(4); /* fan5 enabled */
-               if (has_six_fans(data) && (tmp & BIT(2)))
-                       data->has_fan |= BIT(5); /* fan6 enabled */
+       if (has_four_fans(data) && (tmp & BIT(4)))
+               data->has_fan |= BIT(3); /* fan4 enabled */
+       if (has_five_fans(data) && (tmp & BIT(5)))
+               data->has_fan |= BIT(4); /* fan5 enabled */
+       if (has_six_fans(data)) {
+               switch (data->type) {
+               case it8620:
+               case it8628:
+               case it8686:
+                       if (tmp & BIT(2))
+                               data->has_fan |= BIT(5); /* fan6 enabled */
+                       break;
+               case it8665:
+                       tmp = it87_read_value(data, IT87_REG_FAN_DIV);
+                       if (tmp & BIT(3))
+                               data->has_fan |= BIT(5); /* fan6 enabled */
+                       break;
+               default:
+                       break;
+               }
        }
 
        /* Fan input pins may be used for alternative functions */
        data->has_fan &= ~sio_data->skip_fan;
 
-       /* Check if pwm5, pwm6 are enabled */
+       /* Check if pwm6 is enabled */
        if (has_six_pwm(data)) {
-               /* The following code may be IT8620E specific */
-               tmp = it87_read_value(data, IT87_REG_FAN_DIV);
-               if ((tmp & 0xc0) == 0xc0)
-                       sio_data->skip_pwm |= BIT(4);
-               if (!(tmp & BIT(3)))
-                       sio_data->skip_pwm |= BIT(5);
+               switch (data->type) {
+               case it8620:
+               case it8686:
+                       tmp = it87_read_value(data, IT87_REG_FAN_DIV);
+                       if (!(tmp & BIT(3)))
+                               sio_data->skip_pwm |= BIT(5);
+                       break;
+               default:
+                       break;
+               }
        }
 
        /* Start monitoring */
@@ -3014,6 +3205,8 @@ static int it87_probe(struct platform_device *pdev)
        data->features = it87_devices[sio_data->type].features;
        data->peci_mask = it87_devices[sio_data->type].peci_mask;
        data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
+       data->bank = 0xff;
+
        /*
         * IT8705F Datasheet 0.4.1, 3h == Version G.
         * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
@@ -3050,7 +3243,7 @@ static int it87_probe(struct platform_device *pdev)
        enable_pwm_interface = it87_check_pwm(dev);
 
        /* Starting with IT8721F, we handle scaling of internal voltages */
-       if (has_12mv_adc(data)) {
+       if (has_scaling(data)) {
                if (sio_data->internal & BIT(0))
                        data->in_scaled |= BIT(3);      /* in3 is AVCC */
                if (sio_data->internal & BIT(1))