summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
21b0f8c)
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 <linux@roeck-us.net>
u32 features;
u8 num_temp_limit;
u8 num_temp_offset;
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;
};
u8 peci_mask;
u8 old_peci_mask;
};
/* may need to overwrite */
.num_temp_limit = 3,
.num_temp_offset = 0,
/* may need to overwrite */
.num_temp_limit = 3,
.num_temp_offset = 0,
},
[it8712] = {
.name = "it8712",
},
[it8712] = {
.name = "it8712",
/* may need to overwrite */
.num_temp_limit = 3,
.num_temp_offset = 0,
/* may need to overwrite */
.num_temp_limit = 3,
.num_temp_offset = 0,
},
[it8716] = {
.name = "it8716",
},
[it8716] = {
.name = "it8716",
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
},
[it8718] = {
.name = "it8718",
},
[it8718] = {
.name = "it8718",
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.old_peci_mask = 0x4,
},
[it8720] = {
.old_peci_mask = 0x4,
},
[it8720] = {
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.old_peci_mask = 0x4,
},
[it8721] = {
.old_peci_mask = 0x4,
},
[it8721] = {
| FEAT_PWM_FREQ2 | FEAT_SCALING | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_PWM_FREQ2 | FEAT_SCALING | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x05,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
.peci_mask = 0x05,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 6,
.num_temp_offset = 3,
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 6,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8732] = {
.peci_mask = 0x07,
},
[it8732] = {
| FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
/* three fans, always 16 bit (guesswork) */
.num_temp_limit = 3,
.num_temp_offset = 3,
/* three fans, always 16 bit (guesswork) */
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8772] = {
.peci_mask = 0x07,
},
[it8772] = {
/* three fans, always 16 bit (datasheet) */
.num_temp_limit = 3,
.num_temp_offset = 3,
/* three fans, always 16 bit (datasheet) */
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8781] = {
.peci_mask = 0x07,
},
[it8781] = {
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.old_peci_mask = 0x4,
},
[it8782] = {
.old_peci_mask = 0x4,
},
[it8782] = {
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.old_peci_mask = 0x4,
},
[it8783] = {
.old_peci_mask = 0x4,
},
[it8783] = {
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.old_peci_mask = 0x4,
},
[it8786] = {
.old_peci_mask = 0x4,
},
[it8786] = {
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8790] = {
.peci_mask = 0x07,
},
[it8790] = {
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8792] = {
.peci_mask = 0x07,
},
[it8792] = {
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8603] = {
.peci_mask = 0x07,
},
[it8603] = {
| FEAT_AVCC3 | FEAT_PWM_FREQ2 | FEAT_SCALING,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_AVCC3 | FEAT_PWM_FREQ2 | FEAT_SCALING,
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8607] = {
.name = "it8607",
.suffix = "E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
.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,
| FEAT_AVCC3 | FEAT_PWM_FREQ2 | FEAT_SCALING
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8613] = {
.peci_mask = 0x07,
},
[it8613] = {
| FEAT_AVCC3 | FEAT_SCALING | FEAT_NEW_TEMPMAP,
.num_temp_limit = 6,
.num_temp_offset = 6,
| FEAT_AVCC3 | FEAT_SCALING | FEAT_NEW_TEMPMAP,
.num_temp_limit = 6,
.num_temp_offset = 6,
.peci_mask = 0x07,
},
[it8620] = {
.peci_mask = 0x07,
},
[it8620] = {
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8622] = {
.peci_mask = 0x07,
},
[it8622] = {
| FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_SCALING,
.num_temp_limit = 3,
.num_temp_offset = 3,
| FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_SCALING,
.num_temp_limit = 3,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8625] = {
.peci_mask = 0x07,
},
[it8625] = {
| FEAT_SIX_PWM | FEAT_BANK_SEL | FEAT_SCALING,
.num_temp_limit = 6,
.num_temp_offset = 6,
| FEAT_SIX_PWM | FEAT_BANK_SEL | FEAT_SCALING,
.num_temp_limit = 6,
.num_temp_offset = 6,
},
[it8628] = {
.name = "it8628",
},
[it8628] = {
.name = "it8628",
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 6,
.num_temp_offset = 3,
| FEAT_FANCTL_ONOFF,
.num_temp_limit = 6,
.num_temp_offset = 3,
.peci_mask = 0x07,
},
[it8655] = {
.peci_mask = 0x07,
},
[it8655] = {
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_BANK_SEL,
.num_temp_limit = 6,
.num_temp_offset = 6,
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_BANK_SEL,
.num_temp_limit = 6,
.num_temp_offset = 6,
},
[it8665] = {
.name = "it8665",
},
[it8665] = {
.name = "it8665",
| FEAT_SIX_PWM | FEAT_BANK_SEL,
.num_temp_limit = 6,
.num_temp_offset = 6,
| FEAT_SIX_PWM | FEAT_BANK_SEL,
.num_temp_limit = 6,
.num_temp_offset = 6,
},
[it8686] = {
.name = "it8686",
},
[it8686] = {
.name = "it8686",
| FEAT_SIX_TEMP | FEAT_BANK_SEL | FEAT_SCALING | FEAT_AVCC3,
.num_temp_limit = 6,
.num_temp_offset = 6,
| FEAT_SIX_TEMP | FEAT_BANK_SEL | FEAT_SCALING | FEAT_AVCC3,
.num_temp_limit = 6,
.num_temp_offset = 6,
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_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 */
/* Automatic fan speed control registers */
u8 auto_pwm[NUM_AUTO_PWM][4]; /* [nr][3] is hard-coded */
#define DIV_FROM_REG(val) BIT(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.
/*
* 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.
static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
{
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_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 {
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);
- data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+ data->pwm_duty[nr] = ctrl & 0x7f;
}
if (has_old_autopwm(data)) {
}
if (has_old_autopwm(data)) {
data->pwm_duty[nr]);
/* and set manual mode */
if (has_newer_autopwm(data)) {
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];
}
} else {
ctrl = data->pwm_duty[nr];
}
u8 ctrl;
if (has_newer_autopwm(data)) {
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 {
if (val != 1)
ctrl |= 0x80;
} else {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;
- 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,
}
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;
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = dev_get_drvdata(dev);
int nr = sensor_attr->index;
+ unsigned long val;
+ u8 map;
- if (kstrtol(buf, 10, &val) < 0)
+ if (kstrtoul(buf, 10, &val) < 0)
- 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)
- if (has_new_tempmap(data))
- reg <<= 3;
- else if (reg > 0x02)
- return -EINVAL;
mutex_lock(&data->update_lock);
it87_update_pwm_ctrl(data, nr);
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) {
/*
* 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);
it87_write_value(data, data->REG_PWM[nr], data->pwm_ctrl[nr]);
}
mutex_unlock(&data->update_lock);
+ 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.
/*
* 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
* 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
* manual duty cycle.
*/
for (i = 0; i < NUM_AUTO_PWM; i++) {
* 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 */
}
data->pwm_duty[i] = 0x7f; /* Full speed */
data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */
}
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->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;
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;