]> git.sur5r.net Git - groeck-it87/blobdiff - it87.c
Rework pwm temperature mapping
[groeck-it87] / it87.c
diff --git a/it87.c b/it87.c
index 9bb5d5b3761d5603f3ee2befcf2f97b5bfe1221c..eae64f38ee1fe8d5927e8fba85efd2a1f7017230 100644 (file)
--- a/it87.c
+++ b/it87.c
@@ -327,6 +327,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 +366,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 +375,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 +385,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 +395,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 +406,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 +418,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 +431,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 +443,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 +459,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 +474,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 +485,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 +496,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 +507,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 +518,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 +529,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 +540,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 +551,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 +575,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 +588,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 +600,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 +612,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 +624,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 +635,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 +646,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 +657,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 +776,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 +865,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 +953,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)) {
@@ -1623,6 +1672,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
        }
 
        mutex_lock(&data->update_lock);
+       it87_update_pwm_ctrl(data, nr);
 
        if (val == 0) {
                if (nr < 3 && has_fanctl_onoff(data)) {
@@ -1643,8 +1693,8 @@ 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]);
                        } else {
                                ctrl = data->pwm_duty[nr];
                        }
@@ -1655,8 +1705,8 @@ 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];
+                       ctrl = temp_map_to_reg(data, nr,
+                                              data->pwm_temp_map[nr]);
                        if (val != 1)
                                ctrl |= 0x80;
                } else {
@@ -1760,21 +1810,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,
@@ -1784,58 +1821,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);
@@ -3438,13 +3443,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
@@ -3452,7 +3465,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 */
        }
@@ -3644,6 +3657,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;