From aeafb7be7c845d3a60691a32c6e1d86eca623691 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 4 Sep 2017 08:27:19 -0700 Subject: [PATCH] Rework pwm temperature mapping Various chips have different numbers of valid values for pwm temperature mapping. Rework the code to take this into account. No longer keep map as bitmap, but maintain it as number 1..X. Do not try to define a separate mapping entry for pwm4..6 on chips where the temperature map for those pwm controls is taken from a different temperature input. Introduce helpers to convert the control register contents to a map and vice versa. Reflect that IT8607 uses the new temperature map in bit 3..5 of the pwm control register. Signed-off-by: Guenter Roeck --- it87.c | 149 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 68 deletions(-) diff --git a/it87.c b/it87.c index 8404802..eae64f3 100644 --- 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)) { @@ -1644,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]; } @@ -1656,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 { @@ -1761,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, @@ -1785,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); @@ -3439,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 @@ -3453,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 */ } @@ -3645,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; -- 2.39.2