w83627ehf fan controll?

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

 



On Sat, Dec 31, 2005 at 08:12:16PM +0100, Jean Delvare wrote:
> Hi Yuan & all,
Hi!

> > I have add some entries to test the chip (in my local CVS), But I have
> > not finished the test. Did anyone do the same work on this driver?
> 
> A number of persons are supposedly working on improving this driver.
> Cadu said he would improve the driver back in July but we didn't hear
> back since. I think Rudolf has a W83627EHF chip and may be willing to
> help too. And I also seem to remember that Aurelien has such a chip and
> wanted to help with the driver some times ago.
> 
> It's rare to have that many persons working on the same driver, so it's
> quite sad that nothing has been merged into the driver yet :(
>
> If you have a patch to contribute, please do! :)
>

Yes I have started to work on it, but I have then stopped due to lack of
time. Please find attached a patch between the current version in the
kernel and my local version. It adds support for voltage inputs and it
factorizes some code.

> > Actually I'm quiet confusing about the naming rule of device file, it
> > did not cover all the PWM/SmartFan functions.
> 
> Same old story. We tried to standardize the PWM interface, but in the
> end nobody seems to be happy with that standard. I'm a bit tired of all
> this, so just implement any interface you like as long as it makes
> sense. All I am asking for is that fan stopped is PWM=0 and fan at full
> speed is PWM=255.
> 
I have also started to work on pwm, until I understood the Asus guys
have wired the fans directly to +12V. That's why I finally used a
hardware solution instead of a software one :(

Bye,
Aurelien

-- 
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   aurel32 at debian.org         | aurelien at aurel32.net
   `-    people.debian.org/~aurel32 | www.aurel32.net
-------------- next part --------------
--- /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 };
+
 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]);
+		}
+
 		/* 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); \
+	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);
+
+#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);
 }
 
 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;
 


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

  Powered by Linux