diff --git a/doc/chips/w83781d b/doc/chips/w83781d index 7ceee95e..172162a0 100644 --- a/doc/chips/w83781d +++ b/doc/chips/w83781d @@ -18,7 +18,24 @@ w83783s: untested /PROC ENTRIES ------------- -Varies depending on chip type. +Varies depending on chip type. Most are identical to the lm78 entries. +See the lm78 documentation for details. + +Additional entries: + pwm[1-4]: (782d/783s only) + Controls the speed of the fans with PWM (Pulse Width Modulation) + Valid values: + 0 - 255. 255 = max speed. + + sensor[1-3]: (782d/783s only) + Controls the sensor type. To change to a different + sensor type, for example, do 'echo 2 > sensor1'. + Valid values: + 1: Pentium II / Celeron diode + 2: 2N3904 Transistor in a diode configuration + 3435: Thermistor with Beta = 3435. Beta is a measure + of sensitivity to temperature. + The driver only updates its values each 1.5 seconds; reading it more often will do no harm, but will return 'old' values. @@ -31,7 +48,6 @@ TO DO: 783s temp2 (labeled as temp1 in data sheet) at different location than 781d/782d, not implemented yet. 781d R-T table - 782d/783s undocumented thermistor/PII/3904 select bits for pins 38-40 782d/783s clock speed select diff --git a/kernel/chips/w83781d.c b/kernel/chips/w83781d.c index 26e2c880..ece9886b 100644 --- a/kernel/chips/w83781d.c +++ b/kernel/chips/w83781d.c @@ -45,6 +45,9 @@ #include "i2c.h" #include "compat.h" +/* RT Table support experimental - define this to enable */ +#undef W83781D_RT + /* Many W83781D constants specified below */ /* Length of ISA address segment */ @@ -105,6 +108,19 @@ const u8 regpwm[] = {W83781D_REG_PWM1, W83781D_REG_PWM2, W83781D_REG_PWM3, W83781D_REG_PWM4}; #define W83781D_REG_PWM(nr) (regpwm[(nr) - 1]) +/* The following are undocumented in the data sheets however we + received the information in an email from Winbond tech support */ +/* Sensor selection 782D/783S only */ +#define W83781D_REG_SCFG1 0x5D +const u8 BIT_SCFG1[] = {0x02, 0x04, 0x08}; +#define W83781D_REG_SCFG2 0x59 +const u8 BIT_SCFG2[] = {0x10, 0x04, 0x08}; +#define W83781D_DEFAULT_BETA 3435 + +/* RT Table registers */ +#define W83781D_REG_RT_IDX 0x50 +#define W83781D_REG_RT_VAL 0x51 + #define W83781D_WCHIPID 0x10 #define W83782D_WCHIPID 0x30 #define W83783S_WCHIPID 0x40 @@ -297,6 +313,13 @@ struct w83781d_data { u8 beep_enable; /* Boolean */ u8 wchipid; /* Register value */ u8 pwm[4]; /* Register value */ + u16 sens[3]; /* 782D/783S only. + 1 = pentium diode; 2 = 3904 diode; + 3000-5000 = thermistor beta. + Default = 3435. Other Betas unimplemented */ +#ifdef W83781D_RT + u8 rt[3][32]; /* Register value */ +#endif }; @@ -342,6 +365,12 @@ static void w83781d_fan_div(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); static void w83781d_pwm(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); +static void w83781d_sens(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +#ifdef W83781D_RT +static void w83781d_rt(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +#endif /* I choose here for semi-static W83781D allocation. Complete dynamic allocation could also be used; the code needed for this would probably @@ -406,6 +435,14 @@ static ctl_table w83781d_dir_table_template[] = { &sensors_sysctl_real, NULL, &w83781d_alarms }, { W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &w83781d_beep }, +#ifdef W83781D_RT + { W83781D_SYSCTL_RT1, "rt1", NULL, 0, 0444, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_rt }, + { W83781D_SYSCTL_RT2, "rt2", NULL, 0, 0444, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_rt }, + { W83781D_SYSCTL_RT3, "rt3", NULL, 0, 0444, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_rt }, +#endif { 0 } }; @@ -453,6 +490,12 @@ static ctl_table w83782d_isa_dir_table_template[] = { &sensors_sysctl_real, NULL, &w83781d_pwm }, { W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &w83781d_pwm }, + { W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_sens }, + { W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_sens }, + { W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_sens }, { 0 } }; @@ -504,6 +547,12 @@ static ctl_table w83782d_i2c_dir_table_template[] = { &sensors_sysctl_real, NULL, &w83781d_pwm }, { W83781D_SYSCTL_PWM4, "pwm4", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &w83781d_pwm }, + { W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_sens }, + { W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_sens }, + { W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_sens }, { 0 } }; @@ -543,6 +592,10 @@ static ctl_table w83783s_dir_table_template[] = { &sensors_sysctl_real, NULL, &w83781d_pwm }, { W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &w83781d_pwm }, + { W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_sens }, + { W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &w83781d_sens }, { 0 } }; @@ -988,9 +1041,12 @@ int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) /* Called when we have found a new W83781D. It should set limits, etc. */ void w83781d_init_client(struct i2c_client *client) { + struct w83781d_data *data = client->data; int vid,wchipid; + int i; + u8 tmp; - wchipid = ((struct w83781d_data *) (client->data))->wchipid; + wchipid = data->wchipid; /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others */ w83781d_write_value(client,W83781D_REG_CONFIG,0x80); @@ -999,6 +1055,47 @@ void w83781d_init_client(struct i2c_client *client) vid |= (w83781d_read_value(client,W83781D_REG_CHIPID) & 0x01) << 4; vid = VID_FROM_REG(vid); + if(wchipid != W83781D_WCHIPID) { + tmp = w83781d_read_value(client,W83781D_REG_SCFG1); + for (i = 1; i <= 3; i++) { + if(!(tmp & BIT_SCFG1[i-1])) { + data->sens[i-1] = W83781D_DEFAULT_BETA; + } else { + if(w83781d_read_value(client,W83781D_REG_TEMP) & BIT_SCFG2[i-1]) + data->sens[i-1] = 1; + else + data->sens[i-1] = 2; + } + if(data->wchipid == W83783S_WCHIPID && i == 2) + break; + } + } + +#ifdef W83781D_RT +/* + Fill up the RT Tables. + We assume that they are 32 bytes long, in order for temp 1-3. + Data sheet documentation is sparse. + We also assume that it is only for the 781D although I suspect + that the 782D/783D support it as well.... +*/ + + if(wchipid == W83781D_WCHIPID) { +/* + Auto-indexing doesn't seem to work... + w83781d_write_value(client,W83781D_REG_RT_IDX,0); +*/ + for (i = 0; i < 3; i++) { + int j; + for (j = 0; j < 32; j++) { + u16 k = 0; + w83781d_write_value(client,W83781D_REG_RT_IDX,k++); + data->rt[i][j] = w83781d_read_value(client,W83781D_REG_RT_VAL); + } + } + } +#endif + w83781d_write_value(client,W83781D_REG_IN_MIN(0), IN_TO_REG(W83781D_INIT_IN_MIN_0,0)); w83781d_write_value(client,W83781D_REG_IN_MAX(0), @@ -1382,6 +1479,67 @@ void w83781d_pwm(struct i2c_client *client, int operation, int ctl_name, } } +void w83781d_sens(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct w83781d_data *data = client->data; + int nr = 1 + ctl_name - W83781D_SYSCTL_SENS1; + u8 tmp; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + results[0] = data->sens[nr-1]; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + switch(results[0]) { + case 1: /* PII/Celeron diode */ + tmp = w83781d_read_value(client,W83781D_REG_SCFG1); + w83781d_write_value(client,W83781D_REG_SCFG1, tmp | BIT_SCFG2[nr-1]); + tmp = w83781d_read_value(client,W83781D_REG_SCFG2); + w83781d_write_value(client,W83781D_REG_SCFG2, tmp | BIT_SCFG2[nr-1]); + data->sens[nr-1] = results[0]; + break; + case 2: /* 3904 */ + tmp = w83781d_read_value(client,W83781D_REG_SCFG1); + w83781d_write_value(client,W83781D_REG_SCFG1, tmp | BIT_SCFG2[nr-1]); + tmp = w83781d_read_value(client,W83781D_REG_SCFG2); + w83781d_write_value(client,W83781D_REG_SCFG2, tmp & ~ BIT_SCFG2[nr-1]); + data->sens[nr-1] = results[0]; + break; + case W83781D_DEFAULT_BETA: /* thermistor */ + tmp = w83781d_read_value(client,W83781D_REG_SCFG1); + w83781d_write_value(client,W83781D_REG_SCFG1, tmp & ~ BIT_SCFG2[nr-1]); + data->sens[nr-1] = results[0]; + break; + default: + printk("w83781d.o: Invalid sensor type %ld; must be 1, 2, or %d\n", results[0], W83781D_DEFAULT_BETA); + break; + } + } + } +} + +#ifdef W83781D_RT +void w83781d_rt(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct w83781d_data *data = client->data; + int nr = 1 + ctl_name - W83781D_SYSCTL_RT1; + int i; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + for(i = 0; i < 32; i++) { + results[i] = data->rt[nr-1][i]; + } + *nrels_mag = 32; + } +} +#endif + int w83781d_init(void) { int res; diff --git a/kernel/include/sensors.h b/kernel/include/sensors.h index 61620453..ba5179bf 100644 --- a/kernel/include/sensors.h +++ b/kernel/include/sensors.h @@ -352,6 +352,12 @@ struct sensors_chips_data { #define W83781D_SYSCTL_PWM2 1402 #define W83781D_SYSCTL_PWM3 1403 #define W83781D_SYSCTL_PWM4 1404 +#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define W83781D_SYSCTL_SENS2 1502 +#define W83781D_SYSCTL_SENS3 1503 +#define W83781D_SYSCTL_RT1 1601 /* 32-entry table */ +#define W83781D_SYSCTL_RT2 1602 /* 32-entry table */ +#define W83781D_SYSCTL_RT3 1603 /* 32-entry table */ #define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ #define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ #define W83781D_SYSCTL_BEEP 2002 /* bitvector */ diff --git a/kernel/sensors.c b/kernel/sensors.c index 326ee2b1..f5321767 100644 --- a/kernel/sensors.c +++ b/kernel/sensors.c @@ -334,7 +334,7 @@ int sensors_sysctl_chips (ctl_table *table, int *name, int nlen, void *oldval, int sensors_proc_real(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp) { -#define MAX_RESULTS 20 +#define MAX_RESULTS 32 int mag,nrels=MAX_RESULTS; long results[MAX_RESULTS]; sensors_real_callback callback = ctl -> extra1;