Commit 6229cdb2 authored by Jean Delvare's avatar Jean Delvare Committed by Jean Delvare

hwmon: (it87) Fix manual fan speed control on IT8721F

The manual fan speed control logic of the IT8721F is much different
from what older devices had. Update the code to properly support that.
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Acked-by: default avatarGuenter Roeck <guenter.roeck@ericsson.com>
parent 6313e3c2
...@@ -187,6 +187,7 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; ...@@ -187,6 +187,7 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
#define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14 #define IT87_REG_FAN_CTL 0x14
#define IT87_REG_PWM(nr) (0x15 + (nr)) #define IT87_REG_PWM(nr) (0x15 + (nr))
#define IT87_REG_PWM_DUTY(nr) (0x63 + (nr) * 8)
#define IT87_REG_VIN(nr) (0x20 + (nr)) #define IT87_REG_VIN(nr) (0x20 + (nr))
#define IT87_REG_TEMP(nr) (0x29 + (nr)) #define IT87_REG_TEMP(nr) (0x29 + (nr))
...@@ -251,12 +252,16 @@ struct it87_data { ...@@ -251,12 +252,16 @@ struct it87_data {
u8 fan_main_ctrl; /* Register value */ u8 fan_main_ctrl; /* Register value */
u8 fan_ctl; /* Register value */ u8 fan_ctl; /* Register value */
/* The following 3 arrays correspond to the same registers. The /* The following 3 arrays correspond to the same registers up to
* meaning of bits 6-0 depends on the value of bit 7, and we want * the IT8720F. The meaning of bits 6-0 depends on the value of bit
* to preserve settings on mode changes, so we have to track all * 7, and we want to preserve settings on mode changes, so we have
* values separately. */ * to track all values separately.
* Starting with the IT8721F, the manual PWM duty cycles are stored
* in separate registers (8-bit values), so the separate tracking
* is no longer needed, but it is still done to keep the driver
* simple. */
u8 pwm_ctrl[3]; /* Register value */ u8 pwm_ctrl[3]; /* Register value */
u8 pwm_duty[3]; /* Manual PWM value set by user (bit 6-0) */ u8 pwm_duty[3]; /* Manual PWM value set by user */
u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */ u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */
/* Automatic fan speed control registers */ /* Automatic fan speed control registers */
...@@ -832,7 +837,9 @@ static ssize_t set_pwm_enable(struct device *dev, ...@@ -832,7 +837,9 @@ static ssize_t set_pwm_enable(struct device *dev,
data->fan_main_ctrl); data->fan_main_ctrl);
} else { } else {
if (val == 1) /* Manual mode */ if (val == 1) /* Manual mode */
data->pwm_ctrl[nr] = data->pwm_duty[nr]; data->pwm_ctrl[nr] = data->type == it8721 ?
data->pwm_temp_map[nr] :
data->pwm_duty[nr];
else /* Automatic mode */ else /* Automatic mode */
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr]; data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]); it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
...@@ -858,12 +865,25 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, ...@@ -858,12 +865,25 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->pwm_duty[nr] = pwm_to_reg(data, val); if (data->type == it8721) {
/* If we are in manual mode, write the duty cycle immediately; /* If we are in automatic mode, the PWM duty cycle register
* otherwise, just store it for later use. */ * is read-only so we can't write the value */
if (!(data->pwm_ctrl[nr] & 0x80)) { if (data->pwm_ctrl[nr] & 0x80) {
data->pwm_ctrl[nr] = data->pwm_duty[nr]; mutex_unlock(&data->update_lock);
it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]); return -EBUSY;
}
data->pwm_duty[nr] = pwm_to_reg(data, val);
it87_write_value(data, IT87_REG_PWM_DUTY(nr),
data->pwm_duty[nr]);
} else {
data->pwm_duty[nr] = pwm_to_reg(data, val);
/* If we are in manual mode, write the duty cycle immediately;
* otherwise, just store it for later use. */
if (!(data->pwm_ctrl[nr] & 0x80)) {
data->pwm_ctrl[nr] = data->pwm_duty[nr];
it87_write_value(data, IT87_REG_PWM(nr),
data->pwm_ctrl[nr]);
}
} }
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
...@@ -1958,7 +1978,10 @@ static void __devinit it87_init_device(struct platform_device *pdev) ...@@ -1958,7 +1978,10 @@ static void __devinit it87_init_device(struct platform_device *pdev)
* channels to use when later setting to automatic mode later. * channels to use when later setting to automatic mode later.
* Use a 1:1 mapping by default (we are clueless.) * Use a 1:1 mapping by default (we are clueless.)
* In both cases, the value can (and should) be changed by the user * In both cases, the value can (and should) be changed by the user
* prior to switching to a different mode. */ * prior to switching to a different mode.
* Note that this is no longer needed for the IT8721F and later, as
* these have separate registers for the temperature mapping and the
* manual duty cycle. */
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
data->pwm_temp_map[i] = i; data->pwm_temp_map[i] = i;
data->pwm_duty[i] = 0x7f; /* Full speed */ data->pwm_duty[i] = 0x7f; /* Full speed */
...@@ -2034,10 +2057,16 @@ static void __devinit it87_init_device(struct platform_device *pdev) ...@@ -2034,10 +2057,16 @@ static void __devinit it87_init_device(struct platform_device *pdev)
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, IT87_REG_PWM(nr)); data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */ if (data->type == it8721) {
data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
else /* Manual mode */ data->pwm_duty[nr] = it87_read_value(data,
data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f; IT87_REG_PWM_DUTY(nr));
} else {
if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
else /* Manual mode */
data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
}
if (has_old_autopwm(data)) { if (has_old_autopwm(data)) {
int i; int i;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment