VT8231 patch for review

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

 



Hi Roger,

On 2005-11-16, Roger Lucas wrote:
> Firstly, I really like Quilt.  It makes the whole patch process much
> easier.

True :) I'd suggest that you add the following to your ~/.quiltrc:

QUILT_NO_DIFF_INDEX=1
QUILT_REFRESH_ARGS="--diffstat --strip-trailing-whitespace"

This will help you produce patches the kernel folks will enjoy.

> To answer the question in your last mail, "Yes, I am happy to be the
> maintainer of this driver".

Great. Then please submit a patch adding yourself to MAINTAINERS. Copy my
LM90 entry for example, and adapt to you and the VT8231. Pay attention
to the fact that the entries are alphabetically sorted.

Note that all your patches should include a "Signed-off-by" line. This
one lacked it.

> Once we go around the loop to get this into the kernel, I'll take a look
> at the user-space utility as it throws up a load of errors at the moment.
> It also seems to get the alarm wrong on the fans.

Please look into it *before* the driver is accepted into the Linux 2.6
kernel tree. Maybe the bugs are in the user-space part, but maybe not.
We better don't merge a bogus driver.

There's still one thing I am not happy with: temp 2-6. We agreed to
export the raw register value for the diode-based temperature (temp1)
because there's nothing better we can do, but for the thermistor-based
ones we should be able to export the value as a voltage.

The BIOS porting guide states that the register value is equal to 253 -
R6/(R6+R5) * 210, where R5 is a thermisor (10K at 25C) and R6 is a 10K
resistor. These 253 and 210 constants are inherent to the chip and do
not depend on the motherboard. R6 and R5 form a standard thermistor
divider, effectively converting a temperature into a voltage.

So I believe we should have the following for temp 2-6:

TEMP_FROM_REG(reg)    ((253 - (reg)) * 1000 / 210)

TEMP_TO_REG(val)      (253 - (val) * 210 / 1000)

Of course we would then need to update the formula in sensors.conf.eg.

To the code itself now:

> 	Copyright (c) 2005 Roger Lucas <roger at planbit.co.uk>
> 		      2002 Mark D. Studebaker <mdsxyz123 at yahoo.com>

I think you have to repeat "Copyright (c)" before "2002".

> #define VT8231_REG_TEMP_LOW01	0x49
> #define VT8231_REG_TEMP_LOW25	0x4d
> (...)
> **     All the on-chip hardware temperature comparisons for the alarms
>                                                               are only
> **     8-bits wide, and compare against the 8 MSBs of the temperature.
>                                                               The bits
> **     in the registers VT8231_REG_TEMP_LOW12 and VT8231_REG_TEMP_LOW36
>                                                                    are
> **     ignored.

Conflicting conventions.

> 	u8 fan[2];		/* Register value */
> 	u8 fan_min[2];		/* Register value */
> (...)
> 		for (i = 1; i < 3; i++) {
> 			data->fan[i - 1] = vt8231_read_value(client,
> 						VT8231_REG_FAN(i));
> 			data->fan_min[i - 1] = vt8231_read_value(client,
> 						VT8231_REG_FAN_MIN(i));
> 		}

Array overflow! Sorry for not noticing before.

> static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in5, NULL, 5);
> static SENSOR_DEVICE_ATTR(in5_min, S_IRUGO | S_IWUSR, show_in5_min,
>                           set_in5_min, 5);
> static SENSOR_DEVICE_ATTR(in5_max, S_IRUGO | S_IWUSR, show_in5_max,
>                           set_in5_max, 5);

Please use DEVICE_ATTR instead. You are not using the extra parameter in
the callback functions.

> /* Temperatures */
> static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
> 		char *buf)
> {
> 	struct sensor_device_attribute *sensor_attr =
>                                          to_sensor_dev_attr(attr);
> 	int nr = sensor_attr->index;
> 	struct vt8231_data *data = vt8231_update_device(dev);
> 	return sprintf(buf, "%d\n",  data->temp[nr] * 250);
> }

Double space on last line.

> /* NOTE THAT THESE MAP THE LINUX TEMPERATURE SENSOR NUMBERING (1-6) TO
>                                                                THE VIA
> ** TEMPERATURE SENSOR NUMBERING (0-5)
> */

No caps please. Yelling never makes you more right.

> #define CFG_INFO_TEMP(id)	{ id - 1, \
> 				&sensor_dev_attr_temp##id##_input.dev_attr, \
> 				&sensor_dev_attr_temp##id##_min.dev_attr, \
> 				&sensor_dev_attr_temp##id##_max.dev_attr }
> #define CFG_INFO_VOLT(id)	{ id, \
> 				&sensor_dev_attr_in##id##_input.dev_attr, \
> 				&sensor_dev_attr_in##id##_min.dev_attr, \
> 				&sensor_dev_attr_in##id##_max.dev_attr, \
> 				}
> 
> struct str_device_attr_table {
> 	int	id;
> 	struct device_attribute *input;
> 	struct device_attribute *min;
> 	struct device_attribute *max;
> };
> 
> static struct str_device_attr_table cfg_info_temp[] = {
> 	CFG_INFO_TEMP(1),
> 	CFG_INFO_TEMP(2),
> 	CFG_INFO_TEMP(3),
> 	CFG_INFO_TEMP(4),
> 	CFG_INFO_TEMP(5),
> 	CFG_INFO_TEMP(6),
> 	{ .id = -1 }
> };
> 
> static struct str_device_attr_table cfg_info_volt[] = {
> 	CFG_INFO_VOLT(0),
> 	CFG_INFO_VOLT(1),
> 	CFG_INFO_VOLT(2),
> 	CFG_INFO_VOLT(3),
> 	CFG_INFO_VOLT(4),
> 	CFG_INFO_VOLT(5),
> 	{ .id = -1 }
> };

You can make these tables smaller. First, use the ARRAY_SIZE macro
instead of a list terminator. Second, you can easily deduce the value of
.id from the position in the array (in fact, .id *is* the position in
the array) so you don't need this field.

> static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
> 		char *buf)
> {
> 	struct sensor_device_attribute *sensor_attr =
>                                           to_sensor_dev_attr(attr);
> 	int nr = sensor_attr->index - 1;

That "- 1" should no more be there, right?

> 	vt8231_write_value(client, VT8231_REG_FAN_MIN(nr+1),
>                                                    data->fan_min[nr]);

I think I said it before, but why don't you change the definition of
VT8231_REG_FAN and VT8231_REG_FAN_MIN to:

#define VT8231_REG_FAN_MIN(nr)	(0x3b + (nr))
#define VT8231_REG_FAN(nr)	(0x29 + (nr))

And then call them with 0..1 rather than 1..2? This would make the code
more simple and easier to check against the datasheet.

> 	/* Correct the fan minimum speed */
> 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));

You additionally need to write the value to the chip, else it will be
overwritten on next update.

> int vt8231_detect(struct i2c_adapter *adapter)
> {
> 	struct i2c_client *new_client;

BTW, feel free to name it simply "client" if you want to. This "new_"
prefix really doesn't add any value.

> 	/* Fill in the remaining client fields and put into the global
>                                                                list */
>	strcpy(new_client->name, "vt8231");

Ideally this should be strlcpy(new_client->name, "vt8231",
I2C_NAME_SIZE);

> 		for (i = 0; i < 6; i++) {
> 			if (ISTEMP(i, data->uch_config)) {
> 				data->temp[i] = vt8231_read_value(client,
> 						       regtemp[i]) << 2;
> 				switch(i) {
> 				case 0:	j = (vt8231_read_value(client,
> 						VT8231_REG_TEMP_LOW01)
> 					      >> 6) & 0x03;
> 					break;
> 
> 				case 1:	j = (vt8231_read_value(client,
> 						VT8231_REG_TEMP_LOW01)
> 					      >> 4) & 0x03;
> 					break;
> 				case 2:
> 				case 3:
> 				case 4:
> 				case 5:	j = (vt8231_read_value(client,
> 					  	VT8231_REG_TEMP_LOW25)
> 						 >> ((i-2)*2)) & 0x03;
> 					break;
> 
> 				default: j = 0;
> 					break;
> 				}
> 				data->temp[i] |= j;
> (...)
> 			}
> 		}

I just realized how inefficient this part is. What about the following
instead:

u16 low = vt8231_read_value(client, VT8231_REG_TEMP_LOW01);
low = (low >> 6) | ((low & 0x30) >> 2); /* swap and shift */
    | (vt8231_read_value(client, VT8231_REG_TEMP_LOW25) << 4);
for (i = 0; i < 6; i++) {
	if (ISTEMP(i, data->uch_config)) {
		data->temp[i] = (vt8231_read_value(client, regtemp[i]) << 2)
		              | ((low >> 2*i) & 0x03);
(...)
	}
}

(You can even drop j if you do that.)

> module_init(sm_vt8231_init);
> module_exit(sm_vt8231_exit);
> 
> 

No blank lines at end of file please ;)

Thanks a lot for your good work! Keep it up, we're getting closer :)

--
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