]> git.sur5r.net Git - groeck-it87/blobdiff - it87.c
Improve temperature sensor type detection for IT8686
[groeck-it87] / it87.c
diff --git a/it87.c b/it87.c
index 84048028821145678065e995f18a4a7471124483..50489971715ec2cfaf3f5d8296c90c5c4d6095d3 100644 (file)
--- a/it87.c
+++ b/it87.c
@@ -86,6 +86,10 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
+static bool ignore_resource_conflict;
+module_param(ignore_resource_conflict, bool, 0);
+MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
+
 static struct platform_device *it87_pdev[2];
 
 #define        REG_2E  0x2e    /* The register to read/write */
@@ -327,6 +331,7 @@ struct it87_devices {
        u32 features;
        u8 num_temp_limit;
        u8 num_temp_offset;
+       u8 num_temp_map;        /* Number of temperature sources for pwm */
        u8 peci_mask;
        u8 old_peci_mask;
 };
@@ -365,6 +370,7 @@ static const struct it87_devices it87_devices[] = {
                                                /* may need to overwrite */
                .num_temp_limit = 3,
                .num_temp_offset = 0,
+               .num_temp_map = 3,
        },
        [it8712] = {
                .name = "it8712",
@@ -373,6 +379,7 @@ static const struct it87_devices it87_devices[] = {
                                                /* may need to overwrite */
                .num_temp_limit = 3,
                .num_temp_offset = 0,
+               .num_temp_map = 3,
        },
        [it8716] = {
                .name = "it8716",
@@ -382,6 +389,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
        },
        [it8718] = {
                .name = "it8718",
@@ -391,6 +399,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .old_peci_mask = 0x4,
        },
        [it8720] = {
@@ -401,6 +410,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .old_peci_mask = 0x4,
        },
        [it8721] = {
@@ -412,6 +422,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_PWM_FREQ2 | FEAT_SCALING | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x05,
                .old_peci_mask = 0x02,  /* Actually reports PCH */
        },
@@ -424,6 +435,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 6,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x07,
        },
        [it8732] = {
@@ -435,6 +447,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x07,
                .old_peci_mask = 0x02,  /* Actually reports PCH */
        },
@@ -450,6 +463,7 @@ static const struct it87_devices it87_devices[] = {
                                /* three fans, always 16 bit (guesswork) */
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x07,
        },
        [it8772] = {
@@ -464,6 +478,7 @@ static const struct it87_devices it87_devices[] = {
                                /* three fans, always 16 bit (datasheet) */
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x07,
        },
        [it8781] = {
@@ -474,6 +489,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .old_peci_mask = 0x4,
        },
        [it8782] = {
@@ -484,6 +500,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .old_peci_mask = 0x4,
        },
        [it8783] = {
@@ -494,6 +511,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .old_peci_mask = 0x4,
        },
        [it8786] = {
@@ -504,6 +522,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x07,
        },
        [it8790] = {
@@ -514,6 +533,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x07,
        },
        [it8792] = {
@@ -524,6 +544,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x07,
        },
        [it8603] = {
@@ -534,17 +555,19 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_AVCC3 | FEAT_PWM_FREQ2 | FEAT_SCALING,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 4,
                .peci_mask = 0x07,
        },
        [it8607] = {
                .name = "it8607",
                .suffix = "E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
-                 | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+                 | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL | FEAT_NEW_TEMPMAP
                  | FEAT_AVCC3 | FEAT_PWM_FREQ2 | FEAT_SCALING
                  | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 6,
                .peci_mask = 0x07,
        },
        [it8613] = {
@@ -556,6 +579,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_AVCC3 | FEAT_SCALING | FEAT_NEW_TEMPMAP,
                .num_temp_limit = 6,
                .num_temp_offset = 6,
+               .num_temp_map = 6,
                .peci_mask = 0x07,
        },
        [it8620] = {
@@ -568,6 +592,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x07,
        },
        [it8622] = {
@@ -579,6 +604,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_SCALING,
                .num_temp_limit = 3,
                .num_temp_offset = 3,
+               .num_temp_map = 4,
                .peci_mask = 0x07,
        },
        [it8625] = {
@@ -590,6 +616,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_SIX_PWM | FEAT_BANK_SEL | FEAT_SCALING,
                .num_temp_limit = 6,
                .num_temp_offset = 6,
+               .num_temp_map = 6,
        },
        [it8628] = {
                .name = "it8628",
@@ -601,6 +628,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_FANCTL_ONOFF,
                .num_temp_limit = 6,
                .num_temp_offset = 3,
+               .num_temp_map = 3,
                .peci_mask = 0x07,
        },
        [it8655] = {
@@ -611,6 +639,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_BANK_SEL,
                .num_temp_limit = 6,
                .num_temp_offset = 6,
+               .num_temp_map = 6,
        },
        [it8665] = {
                .name = "it8665",
@@ -621,6 +650,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_SIX_PWM | FEAT_BANK_SEL,
                .num_temp_limit = 6,
                .num_temp_offset = 6,
+               .num_temp_map = 6,
        },
        [it8686] = {
                .name = "it8686",
@@ -631,6 +661,7 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_SIX_TEMP | FEAT_BANK_SEL | FEAT_SCALING | FEAT_AVCC3,
                .num_temp_limit = 6,
                .num_temp_offset = 6,
+               .num_temp_map = 7,
        },
 };
 
@@ -749,6 +780,9 @@ struct it87_data {
        u8 pwm_ctrl[NUM_PWM];   /* Register value */
        u8 pwm_duty[NUM_PWM];   /* Manual PWM value set by user */
        u8 pwm_temp_map[NUM_PWM];/* PWM to temp. chan. mapping (bits 1-0) */
+       u8 pwm_temp_map_mask;   /* 0x03 for old, 0x07 for new temp map */
+       u8 pwm_temp_map_shift;  /* 0 for old, 3 for new temp map */
+       u8 pwm_num_temp_map;    /* from config data, 3..7 depending on chip */
 
        /* Automatic fan speed control registers */
        u8 auto_pwm[NUM_AUTO_PWM][4];   /* [nr][3] is hard-coded */
@@ -835,6 +869,25 @@ static int DIV_TO_REG(int val)
 
 #define DIV_FROM_REG(val) BIT(val)
 
+static u8 temp_map_from_reg(const struct it87_data *data, u8 reg)
+{
+       u8 map;
+
+       map  = (reg >> data->pwm_temp_map_shift) & data->pwm_temp_map_mask;
+       if (map >= data->pwm_num_temp_map)      /* map is 0-based */
+               map = 0;
+
+       return map;
+}
+
+static u8 temp_map_to_reg(const struct it87_data *data, int nr, u8 map)
+{
+       u8 ctrl = data->pwm_ctrl[nr];
+
+       return (ctrl & ~(data->pwm_temp_map_mask << data->pwm_temp_map_shift)) |
+              (map << data->pwm_temp_map_shift);
+}
+
 /*
  * PWM base frequencies. The frequency has to be divided by either 128 or 256,
  * depending on the chip type, to calculate the actual PWM frequency.
@@ -904,19 +957,19 @@ static void it87_write_value(struct it87_data *data, u16 reg, u8 value)
 
 static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
 {
-       data->pwm_ctrl[nr] = it87_read_value(data, data->REG_PWM[nr]);
+       u8 ctrl;
+
+       ctrl = it87_read_value(data, data->REG_PWM[nr]);
+       data->pwm_ctrl[nr] = ctrl;
        if (has_newer_autopwm(data)) {
-               if (has_new_tempmap(data))
-                       data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x38;
-               else
-                       data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+               data->pwm_temp_map[nr] = temp_map_from_reg(data, ctrl);
                data->pwm_duty[nr] = it87_read_value(data,
                                                     IT87_REG_PWM_DUTY[nr]);
        } else {
-               if (data->pwm_ctrl[nr] & 0x80)  /* Automatic mode */
-                       data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+               if (ctrl & 0x80)        /* Automatic mode */
+                       data->pwm_temp_map[nr] = temp_map_from_reg(data, ctrl);
                else                            /* Manual mode */
-                       data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+                       data->pwm_duty[nr] = ctrl & 0x7f;
        }
 
        if (has_old_autopwm(data)) {
@@ -1255,6 +1308,15 @@ static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
 static SENSOR_DEVICE_ATTR_2(temp6_offset, S_IRUGO | S_IWUSR, show_temp,
                            set_temp, 5, 3);
 
+static const u8 temp_types_8686[NUM_TEMP][9] = {
+       { 0, 8, 8, 8, 8, 8, 8, 8, 7 },
+       { 0, 6, 8, 8, 6, 0, 0, 0, 7 },
+       { 0, 6, 5, 8, 6, 0, 0, 0, 7 },
+       { 4, 8, 8, 8, 8, 8, 8, 8, 7 },
+       { 4, 6, 8, 8, 6, 0, 0, 0, 7 },
+       { 4, 6, 5, 8, 6, 0, 0, 0, 7 },
+};
+
 static int get_temp_type(struct it87_data *data, int index)
 {
        u8 reg, extra;
@@ -1265,27 +1327,11 @@ static int get_temp_type(struct it87_data *data, int index)
                u8 src1, src2;
 
                src1 = (it87_read_value(data, s1reg) >> ((index % 2) * 4)) & 0x0f;
-               src2 = it87_read_value(data, IT87_REG_TEMP_SRC2);
 
                switch (data->type) {
                case it8686:
-                       switch (src1) {
-                       case 0:
-                               if (index >= 3)
-                                       return 4;
-                               break;
-                       case 1:
-                               if (index == 1 || index == 2 ||
-                                         index == 4 || index == 5)
-                                       return 6;
-                               break;
-                       case 2:
-                               if (index == 2 || index == 6)
-                                       return 5;
-                               break;
-                       default:
-                               break;
-                       }
+                       if (src1 < 9)
+                               type = temp_types_8686[index][src1];
                        break;
                case it8625:
                        if (index < 3)
@@ -1296,6 +1342,7 @@ static int get_temp_type(struct it87_data *data, int index)
                                index = src1;
                                break;
                        }
+                       src2 = it87_read_value(data, IT87_REG_TEMP_SRC2);
                        switch(src1) {
                        case 3:
                                type = (src2 & BIT(index)) ? 6 : 5;
@@ -1314,8 +1361,8 @@ static int get_temp_type(struct it87_data *data, int index)
                        return 0;
                }
        }
-       if (index >= 3)
-               return 0;
+       if (type || index >= 3)
+               return type;
 
        reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
        extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
@@ -1644,8 +1691,9 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
                                         data->pwm_duty[nr]);
                        /* and set manual mode */
                        if (has_newer_autopwm(data)) {
-                               ctrl = (data->pwm_ctrl[nr] & 0x7c) |
-                                       data->pwm_temp_map[nr];
+                               ctrl = temp_map_to_reg(data, nr,
+                                                      data->pwm_temp_map[nr]);
+                               ctrl &= 0x7f;
                        } else {
                                ctrl = data->pwm_duty[nr];
                        }
@@ -1656,9 +1704,11 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
                u8 ctrl;
 
                if (has_newer_autopwm(data)) {
-                       ctrl = (data->pwm_ctrl[nr] & 0x7c) |
-                               data->pwm_temp_map[nr];
-                       if (val != 1)
+                       ctrl = temp_map_to_reg(data, nr,
+                                              data->pwm_temp_map[nr]);
+                       if (val == 1)
+                               ctrl &= 0x7f;
+                       else
                                ctrl |= 0x80;
                } else {
                        ctrl = (val == 1 ? data->pwm_duty[nr] : 0x80);
@@ -1761,21 +1811,8 @@ static ssize_t show_pwm_temp_map(struct device *dev,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        struct it87_data *data = it87_update_device(dev);
        int nr = sensor_attr->index;
-       int map;
-
-       map = data->pwm_temp_map[nr];
-       if (has_new_tempmap(data)) {
-               map >>= 3;
-               if (map >= 6)
-                       map = 0;        /* Should never happen */
-       } else {
-               if (map >= 3)
-                       map = 0;        /* Should never happen */
-               if (nr >= 3)            /* pwm channels 3..6 map to temp4..6 */
-                       map += 3;
-       }
 
-       return sprintf(buf, "%d\n", (int)BIT(map));
+       return sprintf(buf, "%d\n", data->pwm_temp_map[nr] + 1);
 }
 
 static ssize_t set_pwm_temp_map(struct device *dev,
@@ -1785,58 +1822,26 @@ static ssize_t set_pwm_temp_map(struct device *dev,
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        struct it87_data *data = dev_get_drvdata(dev);
        int nr = sensor_attr->index;
-       long val;
-       u8 reg;
+       unsigned long val;
+       u8 map;
 
-       if (kstrtol(buf, 10, &val) < 0)
+       if (kstrtoul(buf, 10, &val) < 0)
                return -EINVAL;
 
-       if (nr >= 3 && !has_new_tempmap(data))
-               val -= 3;
-
-       switch (val) {
-       case BIT(0):
-               reg = 0x00;
-               break;
-       case BIT(1):
-               reg = 0x01;
-               break;
-       case BIT(2):
-               reg = 0x02;
-               break;
-       case BIT(3):
-               reg = 0x03;
-               break;
-       case BIT(4):
-               reg = 0x04;
-               break;
-       case BIT(5):
-               reg = 0x05;
-               break;
-       case BIT(6):
-               reg = 0x06;
-               break;
-       default:
+       if (!val || val > data->pwm_num_temp_map)
                return -EINVAL;
-       }
 
-       if (has_new_tempmap(data))
-               reg <<= 3;
-       else if (reg > 0x02)
-               return -EINVAL;
+       map = val - 1;
 
        mutex_lock(&data->update_lock);
        it87_update_pwm_ctrl(data, nr);
-       data->pwm_temp_map[nr] = reg;
+       data->pwm_temp_map[nr] = map;
        /*
         * If we are in automatic mode, write the temp mapping immediately;
         * otherwise, just store it for later use.
         */
        if (data->pwm_ctrl[nr] & 0x80) {
-               u8 mask = has_new_tempmap(data) ? 0xc7 : 0xfc;
-
-               data->pwm_ctrl[nr] = (data->pwm_ctrl[nr] & mask) |
-                                               data->pwm_temp_map[nr];
+               data->pwm_ctrl[nr] = temp_map_to_reg(data, nr, map);
                it87_write_value(data, data->REG_PWM[nr], data->pwm_ctrl[nr]);
        }
        mutex_unlock(&data->update_lock);
@@ -3439,13 +3444,21 @@ static void it87_init_device(struct platform_device *pdev)
        int tmp, i;
        u8 mask;
 
+       if (has_new_tempmap(data)) {
+               data->pwm_temp_map_shift = 3;
+               data->pwm_temp_map_mask = 0x07;
+       } else {
+               data->pwm_temp_map_shift = 0;
+               data->pwm_temp_map_mask = 0x03;
+       }
+
        /*
         * For each PWM channel:
         * - If it is in automatic mode, setting to manual mode should set
         *   the fan to full speed by default.
         * - If it is in manual mode, we need a mapping to temperature
         *   channels to use when later setting to automatic mode later.
-        *   Use a 1:1 mapping by default (we are clueless.)
+        *   Map to the first sensor by default (we are clueless.)
         * In both cases, the value can (and should) be changed by the user
         * prior to switching to a different mode.
         * Note that this is no longer needed for the IT8721F and later, as
@@ -3453,7 +3466,7 @@ static void it87_init_device(struct platform_device *pdev)
         * manual duty cycle.
         */
        for (i = 0; i < NUM_AUTO_PWM; i++) {
-               data->pwm_temp_map[i] = i;
+               data->pwm_temp_map[i] = 0;
                data->pwm_duty[i] = 0x7f;       /* Full speed */
                data->auto_pwm[i][3] = 0x7f;    /* Full speed, hard-coded */
        }
@@ -3645,6 +3658,7 @@ static int it87_probe(struct platform_device *pdev)
        data->features = it87_devices[sio_data->type].features;
        data->num_temp_limit = it87_devices[sio_data->type].num_temp_limit;
        data->num_temp_offset = it87_devices[sio_data->type].num_temp_offset;
+       data->pwm_num_temp_map = it87_devices[sio_data->type].num_temp_map;
        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;
@@ -3788,8 +3802,10 @@ static int __init it87_device_add(int index, unsigned short address,
        int err;
 
        err = acpi_check_resource_conflict(&res);
-       if (err)
-               return err;
+       if (err) {
+               if (!ignore_resource_conflict)
+                       return err;
+       }
 
        pdev = platform_device_alloc(DRVNAME, address);
        if (!pdev)
@@ -3835,7 +3851,7 @@ struct it87_dmi_data {
  * the second chip may have been accessed prior to loading this driver.
  *
  * The problem is also reported to affect IT8795E, which is used on X299 boards
- * and has the same chip ID as IT9792E (0x8733). It also appears to affect
+ * and has the same chip ID as IT8792E (0x8733). It also appears to affect
  * systems with IT8790E, which is used on some Z97X-Gaming boards as well as
  * Z87X-OC.
  * DMI entries for those systems will be added as they become available and