[lm-sensors] w83627ehf fan controll?
Rudolf Marek
r.marek at sh.cvut.cz
Sat Jan 21 20:23:30 CET 2006
Hi all,
Sorry for late response. I did some quick review of this code. Maybe Yuan can find it useful.
1) max and min regs are switched
2) code does not use sensor_dev_attr and uses old macro system
3) it contains some tweaks to force PWM (seems from Aurelian attempts to get his PWM working :)
I have a question now:
1) does anyone else has something to show?
2) does anyone has userspace voltage support?
I cant work much on this next moth (feb) busy with final exams. Well maybe I will - as brain relax subroutine :)
Yuan have you this on your own schedule?
Thanks,
Regards
Rudolf
> --- /usr/src/linux-2.6.14/drivers/hwmon/w83627ehf.c 2005-10-28 02:02:08.000000000 +0200
> +++ w83627ehf.c 2006-01-09 11:14:20.000000000 +0100
> @@ -30,7 +30,7 @@
> Supports the following chips:
>
> Chip #vin #fan #pwm #temp chip_id man_id
> - w83627ehf - 5 - 3 0x88 0x5ca3
> + w83627ehf 10 5 - 3 0x88 0x5ca3
>
> This is a preliminary version of the driver, only supporting the
> fan and temperature inputs. The chip does much more than that.
> @@ -114,6 +114,10 @@
> #define W83627EHF_REG_CHIP_ID 0x49
> #define W83627EHF_REG_MAN_ID 0x4F
>
> +static const u16 W83627EHF_REG_IN[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552 };
> +static const u16 W83627EHF_REG_IN_MIN[] = { 0x2B, 0x2D, 0x2F, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558 };
> +static const u16 W83627EHF_REG_IN_MAX[] = { 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559 };
> +
Min and max are switched.
> static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
> static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
>
> @@ -137,6 +141,22 @@
> */
>
> static inline unsigned int
> +in_from_reg(u8 reg)
> +{
> + return reg * 8;
> +}
> +
> +static inline u8
> +reg_from_in(int val)
> +{
> + if (val < 0)
> + return 0;
> + if (val > 2040)
> + return 255;
> + return (val + 4) / 8;
> +}
> +
> +static inline unsigned int
> fan_from_reg(u8 reg, unsigned int div)
> {
> if (reg == 0 || reg == 255)
> @@ -182,6 +202,9 @@
> unsigned long last_updated; /* In jiffies */
>
> /* Register values */
> + u8 in[10]; /* Register value */
> + u8 in_max[10]; /* Register value */
> + u8 in_min[10]; /* Register value */
> u8 fan[5];
> u8 fan_min[5];
> u8 fan_div[5];
> @@ -324,6 +347,16 @@
>
> if (time_after(jiffies, data->last_updated + HZ)
> || !data->valid) {
> + /* Measured voltages and limits */
> + for (i = 0; i < 10; i++) {
> + data->in[i] = w83627ehf_read_value(client,
> + W83627EHF_REG_IN[i]);
> + data->in_min[i] = w83627ehf_read_value(client,
> + W83627EHF_REG_IN_MIN[i]);
> + data->in_max[i] = w83627ehf_read_value(client,
> + W83627EHF_REG_IN_MAX[i]);
Maybe one tab missing?
> + }
> +
> /* Fan clock dividers */
> i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
> data->fan_div[0] = (i >> 4) & 0x03;
> @@ -402,6 +435,81 @@
> /*
> * Sysfs callback functions
> */
> +#define show_in_reg(reg) \
> +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
> +{ \
> + struct w83627ehf_data *data = w83627ehf_update_device(dev); \
> + return sprintf(buf,"%d\n", in_from_reg(data->reg[nr])); \
> +}
> +show_in_reg(in)
> +show_in_reg(in_min)
> +show_in_reg(in_max)
> +
> +#define store_in_reg(REG, reg) \
> +static ssize_t \
> +store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
> +{ \
> + struct i2c_client *client = to_i2c_client(dev); \
> + struct w83627ehf_data *data = i2c_get_clientdata(client); \
> + u32 val; \
> + \
> + val = simple_strtoul(buf, NULL, 10); \
> + \
> + down(&data->update_lock); \
> + data->in_##reg[nr] = reg_from_in(val); \
> + w83627ehf_write_value(client, W83627EHF_REG_IN_##REG[nr], \
> + data->in_##reg[nr]); \
> + \
> + up(&data->update_lock); \
I think I have seen some patch that is changing this semaphore to mutexes.
> + return count; \
> +}
> +store_in_reg(MIN, min)
> +store_in_reg(MAX, max)
> +
> +#define sysfs_in_offset(offset) \
> +static ssize_t \
> +show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
> +{ \
> + return show_in(dev, buf, offset); \
> +} \
> +static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
Why this way?
What about this:
static struct sensor_device_attribute sda_in_input[] = {
SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
and
static struct sensor_device_attribute sda_in_min[] = {
SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
/* following are the sysfs callback functions */
static ssize_t show_in(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 w83792d_data *data = w83792d_update_device(dev);
return sprintf(buf,"%ld\n", IN_FROM_REG(nr,(in_count_from_reg(nr, data))));
}
I think you get it :)
> +
> +#define sysfs_in_reg_offset(reg, offset) \
> +static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
> +{ \
> + return show_in_##reg (dev, buf, offset); \
> +} \
> +static ssize_t \
> +store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \
> + const char *buf, size_t count) \
> +{ \
> + return store_in_##reg (dev, buf, count, offset); \
> +} \
> +static DEVICE_ATTR(in##offset##_##reg, S_IRUGO | S_IWUSR, \
> + show_regs_in_##reg##offset, store_regs_in_##reg##offset);
> +
> +#define sysfs_in_offsets(offset) \
> +sysfs_in_offset(offset) \
> +sysfs_in_reg_offset(min, offset) \
> +sysfs_in_reg_offset(max, offset)
> +
> +sysfs_in_offsets(0);
> +sysfs_in_offsets(1);
> +sysfs_in_offsets(2);
> +sysfs_in_offsets(3);
> +sysfs_in_offsets(4);
> +sysfs_in_offsets(5);
> +sysfs_in_offsets(6);
> +sysfs_in_offsets(7);
> +sysfs_in_offsets(8);
> +sysfs_in_offsets(9);
> +
> +#define device_create_file_in(client, offset) \
> +do { \
> + device_create_file(&client->dev, &dev_attr_in##offset##_input); \
> + device_create_file(&client->dev, &dev_attr_in##offset##_max); \
> + device_create_file(&client->dev, &dev_attr_in##offset##_min); \
> +} while (0)
>
> #define show_fan_reg(reg) \
> static ssize_t \
> @@ -522,21 +630,23 @@
> static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
> show_reg_fan##offset##_div, NULL);
>
> -sysfs_fan_offset(1);
> -sysfs_fan_min_offset(1);
> -sysfs_fan_div_offset(1);
> -sysfs_fan_offset(2);
> -sysfs_fan_min_offset(2);
> -sysfs_fan_div_offset(2);
> -sysfs_fan_offset(3);
> -sysfs_fan_min_offset(3);
> -sysfs_fan_div_offset(3);
> -sysfs_fan_offset(4);
> -sysfs_fan_min_offset(4);
> -sysfs_fan_div_offset(4);
> -sysfs_fan_offset(5);
> -sysfs_fan_min_offset(5);
> -sysfs_fan_div_offset(5);
> +#define sysfs_fan_offsets(offset) \
> +sysfs_fan_offset(offset) \
> +sysfs_fan_min_offset(offset) \
> +sysfs_fan_div_offset(offset)
> +
> +sysfs_fan_offsets(1);
> +sysfs_fan_offsets(2);
> +sysfs_fan_offsets(3);
> +sysfs_fan_offsets(4);
> +sysfs_fan_offsets(5);
> +
> +#define device_create_file_fan(client, offset) \
> +do { \
> + device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
> + device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
> + device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
> +} while (0)
>
> #define show_temp1_reg(reg) \
> static ssize_t \
> @@ -639,6 +749,13 @@
> sysfs_temp_reg_offset(max, 3);
> sysfs_temp_reg_offset(max_hyst, 3);
>
> +#define device_create_file_temp(client, offset) \
> +do { \
> + device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
> + device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
> + device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
> +} while (0)
> +
> /*
> * Driver and client management
> */
> @@ -665,6 +782,13 @@
> W83627EHF_REG_TEMP_CONFIG[i],
> tmp & 0xfe);
> }
> + w83627ehf_write_value(client, 0x00, 0x04);
> + w83627ehf_write_value(client, 0x02, 0x04);
> + w83627ehf_write_value(client, 0x04, 0x00);
> + w83627ehf_write_value(client, 0x10, 0x04);
> + w83627ehf_write_value(client, 0x12, 0x00);
> + w83627ehf_write_value(client, 0x60, 0x04);
> + w83627ehf_write_value(client, 0x62, 0x00);
It seems this are your own tweaks. This needs to be removed.
> }
>
> static int w83627ehf_detect(struct i2c_adapter *adapter)
> @@ -724,36 +848,31 @@
> goto exit_detach;
> }
>
> - device_create_file(&client->dev, &dev_attr_fan1_input);
> - device_create_file(&client->dev, &dev_attr_fan1_min);
> - device_create_file(&client->dev, &dev_attr_fan1_div);
> - device_create_file(&client->dev, &dev_attr_fan2_input);
> - device_create_file(&client->dev, &dev_attr_fan2_min);
> - device_create_file(&client->dev, &dev_attr_fan2_div);
> - device_create_file(&client->dev, &dev_attr_fan3_input);
> - device_create_file(&client->dev, &dev_attr_fan3_min);
> - device_create_file(&client->dev, &dev_attr_fan3_div);
> + device_create_file_in(client, 0);
> + device_create_file_in(client, 1);
> + device_create_file_in(client, 2);
> + device_create_file_in(client, 3);
> + device_create_file_in(client, 4);
> + device_create_file_in(client, 5);
> + device_create_file_in(client, 6);
> + device_create_file_in(client, 7);
> + device_create_file_in(client, 8);
> + device_create_file_in(client, 9);
> +
> + device_create_file_fan(client, 1);
> + device_create_file_fan(client, 2);
> + device_create_file_fan(client, 3);
>
> if (data->has_fan & (1 << 3)) {
> - device_create_file(&client->dev, &dev_attr_fan4_input);
> - device_create_file(&client->dev, &dev_attr_fan4_min);
> - device_create_file(&client->dev, &dev_attr_fan4_div);
> + device_create_file_fan(client, 4);
> }
> if (data->has_fan & (1 << 4)) {
> - device_create_file(&client->dev, &dev_attr_fan5_input);
> - device_create_file(&client->dev, &dev_attr_fan5_min);
> - device_create_file(&client->dev, &dev_attr_fan5_div);
> + device_create_file_fan(client, 5);
> }
> -
> - device_create_file(&client->dev, &dev_attr_temp1_input);
> - device_create_file(&client->dev, &dev_attr_temp1_max);
> - device_create_file(&client->dev, &dev_attr_temp1_max_hyst);
> - device_create_file(&client->dev, &dev_attr_temp2_input);
> - device_create_file(&client->dev, &dev_attr_temp2_max);
> - device_create_file(&client->dev, &dev_attr_temp2_max_hyst);
> - device_create_file(&client->dev, &dev_attr_temp3_input);
> - device_create_file(&client->dev, &dev_attr_temp3_max);
> - device_create_file(&client->dev, &dev_attr_temp3_max_hyst);
> +
> + device_create_file_temp(client, 1);
> + device_create_file_temp(client, 2);
> + device_create_file_temp(client, 3);
>
> return 0;
>
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> lm-sensors mailing list
> lm-sensors at lm-sensors.org
> http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
More information about the lm-sensors
mailing list