[PATCH]: Add automatic PWM mode to it87.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Sebastian,

> Ok, here's a patch against 2.6.12-rc6.
> (...)
> I've now added only support for the auto-pwm with slope setting and a
> check for  revision 3.

Here is my review of your patch. Sorry for the delay.

>  static u16 chip_type;
> +static u8  chip_revision;

No space alignment in the kernel code. Either align with tabs, or don't
align.

> +#define IT87_REG_SG_TEMP_OFF(nr) 	(0x60 + (nr) * 8)
> +#define IT87_REG_SG_TEMP_START(nr)	(0x61 + (nr) * 8)
> +#define IT87_REG_SG_TEMP_FULL(nr)	(0x62 + (nr) * 8)
> +#define IT87_REG_SG_START_PWM(nr)	(0x63 + (nr) * 8)

This last name isn't logical, should be IT87_REG_SG_PWM_START (or swap
the other ones, at your option).

> +#define SLOPE_FROM_REG(val) ((val) ? (1 << (val-1)) : 0)

Parentheses are not properly placed for macro safety. It should be:

#define SLOPE_FROM_REG(val) ((val) ? 1 << ((val)-1) : 0)

> +	u8 fan_limit_off[3];	/* Register value */
> +	u8 fan_limit_start[3];	/* Register value */
> +	u8 fan_limit_full[3];	/* Register value */
> +	u8 fan_limit_stpwm[3];	/* Register value */
> +	u8 fan_am_ctrl[3];	/* Register value */
> +	u8 fan_point2_pwm[3];	/* Used for slope calculation */

I don't much like the names you chose. For one thing, it's not obvious
that they are for SmartGuardian/auto-PWM. You should prefix them with
sg_ or auto_pwm_ rather than fan_. For another, temperature values
aren't clearly labelled as such. What about sg_temp_off, sg_temp_start,
sg_temp_full, sg_pwm_start, sg_am_ctrl and sg_pwm_point2?

> +static void calc_slope(struct it87_data *data, int nr)
> +{
> +	u8 val = data->fan_point2_pwm[nr];
> +	
> +	if (data->fan_limit_full[nr] <= data->fan_limit_start[nr])
> +		val = 14;
> +	else {
> +		val -= data->fan_limit_stpwm[nr];
> +		val /= (data->fan_limit_full[nr] - data->fan_limit_start[nr]);
> +	}

Where does this "14" value come from? If full speed temperature happens
to be below the start temperature, we're in trouble anyway, so why
bother?

+	data->fan_am_ctrl[nr] &= ~0x03;

Shouldn't this be ~0x07?

+	if (val > 48)
+		data->fan_am_ctrl[nr] |= 0x07;	/* 64 PWM / K */

What does the "K" stands for? Kelvin? I think "PWM/degree" would be
clearer.

> +	/* Automatic mode - SmartGuardian */
> +	val += (val && (data->manual_pwm_ctl[nr] & 0x80)) ? 1 : 0;

An "if" statement would be clearer IMHO.

> +	return sprintf(buf,"%d\n", val);

Add a space after the first comma (there are many of these in the rest
of the patch).

> +	/* Return 0 if automatic mode is enabled */
> +	return sprintf(buf,"%d\n", (data->manual_pwm_ctl[nr] & 0x80) ? 0 : PWM_FROM_REG(data->manual_pwm_ctl[nr]));

This is unsafe. You should hold the lock (&data->update_lock), else
data->manual_pwm_ctl[nr] may have a different on second read, and you
may display a completely bogus PWM value. Same is true for all other
functions in which you access more than one field of the data structure
(or one, but more than once), you have to hold the lock.

> +			/* Enable temperature smoothing and fan spin up  time */

Extra space between "up" and "time". What is this spin up time BTW? The
datasheet is unclear, to say the least.

> +			data->fan_am_ctrl[nr] = 0x80 | 0x18;
> +			it87_write_value(client, IT87_REG_SG_AM_CTRL(nr), data->fan_am_ctrl[nr]);
> +			/* If start pwm and pwm step size not set, apply safe values */
> +			if (data->fan_limit_stpwm[nr] == 0) {
> +				data->fan_limit_stpwm[nr] = PWM_TO_REG(128);
> +				it87_write_value(client, IT87_REG_SG_START_PWM(nr), data->fan_limit_stpwm[nr]);
> +			}
> +			if ((data->fan_am_ctrl[nr] & 0x07) == 0) {
> +				/* 16 PWM values / K */
> +				data->fan_am_ctrl[nr] |= 0x05;
> +				it87_write_value(client, IT87_REG_SG_AM_CTRL(nr), data->fan_am_ctrl[nr]);
> +			}

This isn't correct. Tracking data->fan_am_ctrl[nr], I can see you are
setting it to 0x98, then writing it to the chip, then testing it with &
0x07 == 0 (will always be true), set it to 0x9D and write it to the chip
again. This isn't correct. You must not change the slope value if it was
set to a sane value before, and you must not write twice to the same
register (waste of time).

> +	data->fan_limit_start[nr] = val;

This lacks a sanity check. Same for the two other ones.

As a side note, I think I would have forced point2's PWM value to 255,
rather than letting the user set it. Having this PWM value too low will
have bad effects due to the lack of hysteresis (the fan will go from low
speed to full speed and back again and again), forcing it to be as near
from full speed as possible would solve this problem.

> +static ssize_t set_pwm_auto_channels_temp(struct device *dev, struct device_attribute *attr,
> +		const char *buf, size_t count)
> (...)
> +	if (val < 0 || val > 4)
> +		return -EINVAL;

3 isn't a valid value, but will pass through.

> +		data->manual_pwm_ctl[nr] = 0x80 | (val >> 1);

This bit shifting is a trick which happens to work in this specific
case, but wouldn't work anymore if there were a 4th temperature channel,
for example. So please don't use it.

> +	/* Set current fan mode registers */
> +	for (i = 0; i < 3; i++) {
> +		data->manual_pwm_ctl[i] = it87_read_value(client, IT87_REG_PWM(i));
> +	
> +		/* Get fan control registers for SmartGuardian automatic mode */
> +		data->fan_limit_off[i] = it87_read_value(client, IT87_REG_SG_TEMP_OFF(i));
> +		data->fan_limit_start[i] = it87_read_value(client, IT87_REG_SG_TEMP_START(i));
> +		data->fan_limit_full[i] = it87_read_value(client, IT87_REG_SG_TEMP_FULL(i));
> +		data->fan_limit_stpwm[i] = it87_read_value(client, IT87_REG_SG_START_PWM(i));
> +		data->fan_am_ctrl[i] = it87_read_value(client, IT87_REG_SG_AM_CTRL(i));
> +	}

This doesn't belong to the init function but to the device_update
function. Additionally, you should do this if and only if the device
actually supports the auto-pwm code (so you have to remember this in
some structure field).

Please provide an updated patch. Don't forget to also update the
revision detection code. You have to check for different revision for
the IT8705F and IT8712F chips, so you really have to test the
combination of chip and revision.

Thanks,
-- 
Jean Delvare




[Index of Archives]     [Linux Kernel]     [Linux Hardware Monitoring]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux