From a92e84fe2ad0e4f1cb1b36c88175b1e9ecba5d03 Mon Sep 17 00:00:00 2001 From: Kyosti Malkki Date: Mon, 26 Jul 1999 15:31:45 +0000 Subject: [PATCH] =?UTF-8?q?(Ky=C3=B6sti)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * GL518 & GL520: setting fan{1,2}_min 0 masks alarm & beep * GL518SM rev 0x00 : Run iteration code in kernel thread Every run of "sensors" now reports results of the previous iteration run, and triggers a new one. * GL520: Reads all inputs now * GL520: Select between Temp2 or -12V input. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@520 7894878c-1315-0410-8ee3-d5d059ff63e0 --- etc/sensors.conf.eg | 2 + kernel/chips/gl518sm.c | 239 ++++++++++++++++++++++++++--------------- kernel/chips/gl520sm.c | 120 ++++++++++++++------- 3 files changed, 236 insertions(+), 125 deletions(-) diff --git a/etc/sensors.conf.eg b/etc/sensors.conf.eg index b57e6bcd..9f4298de 100644 --- a/etc/sensors.conf.eg +++ b/etc/sensors.conf.eg @@ -276,6 +276,7 @@ chip "gl518sm-*" set vin3_min 2.10 set vin3_max 2.30 set fan1_off 0 + set fan2_min 0 set iterate 0 chip "gl520sm-*" @@ -309,6 +310,7 @@ chip "gl520sm-*" set vin2_max 13.0 set vin3_min 2.10 set vin3_max 2.30 + set two_temps 1 chip "lm80-*" diff --git a/kernel/chips/gl518sm.c b/kernel/chips/gl518sm.c index 50ac10d0..8de8048f 100644 --- a/kernel/chips/gl518sm.c +++ b/kernel/chips/gl518sm.c @@ -109,7 +109,7 @@ extern inline u8 FAN_TO_REG(long rpm, int div) #define BEEP_ENABLE_FROM_REG(val) ((val)?0:1) #define BEEPS_TO_REG(val) ((val) & 0x7f) -#define BEEPS_FROM_REG(val) (val) +#define BEEPS_FROM_REG(val) ((val) & 0x7f) /* Initial values */ #define GL518_INIT_TEMP_OVER 600 @@ -149,6 +149,11 @@ struct gl518_data { enum chips type; struct semaphore update_lock; + + int iterate_lock, quit_thread; + struct task_struct *thread; + struct wait_queue *wq; + char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned long last_updated_v00; @@ -164,10 +169,10 @@ struct gl518_data { u8 temp_over; /* Register values */ u8 temp_hyst; /* Register values */ u8 alarms,beeps; /* Register value */ + u8 alarm_mask; /* Register value */ u8 fan_div[2]; /* Register encoding, shifted right */ u8 beep_enable; /* Boolean */ u8 iterate; /* Voltage iteration mode */ - u8 fan1conf; /* Fan1 on/off control */ }; #ifdef MODULE @@ -194,8 +199,10 @@ static u16 swap_bytes(u16 val); static int gl518_read_value(struct i2c_client *client, u8 reg); static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); static void gl518_update_client(struct i2c_client *client); + static void gl518_update_client_rev00(struct i2c_client *client); -static void gl518_update_vins(struct i2c_client *client); +static int gl518_update_thread(void *data); +static void gl518_update_iterate(struct i2c_client *client); static void gl518_vin(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); @@ -381,6 +388,10 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) /* Initialize the GL518SM chip */ data->iterate = 0; + data->iterate_lock = 0; + data->quit_thread = 0; + data->thread = NULL; + data->alarm_mask = 0xff; gl518_init_client((struct i2c_client *) new_client); return 0; @@ -562,15 +573,9 @@ void gl518_update_client(struct i2c_client *client) val = gl518_read_value(client,GL518_REG_MISC); data->fan_div[0] = (val >> 6) & 0x03; data->fan_div[1] = (val >> 4) & 0x03; - data->fan1conf = (val >> 3) & 1; - if (((data->fan1conf) && (data->temp < data->temp_over)) || - (data->fan_min[0]==0xff)) - data->alarms &= ~GL518_ALARM_FAN1; - - if (data->fan_min[1]==0xff) - data->alarms &= ~GL518_ALARM_FAN2; - + data->alarms &= data->alarm_mask; + val = gl518_read_value(client, GL518_REG_CONF); data->beep_enable = (val >> 2) & 1; @@ -603,26 +608,68 @@ void gl518_update_client_rev00(struct i2c_client *client) if (data->iterate == 1) { /* 10 sec delay */ /* as that update is slow, we consider the data valid for 30 seconds */ - if ((jiffies - data->last_updated_v00 > 30*HZ) || (data->alarms & 7) - || (! data->valid)) { - gl518_update_vins(client); - for (i=0; i<4; i++) - data->voltage[i]=data->iter_voltage[i]; + if (((jiffies - data->last_updated_v00 > 30*HZ) || (data->alarms & 7) + || (! data->valid)) && (! data->iterate_lock)) { + data->iterate_lock=1; + gl518_update_iterate(client); + data->iterate_lock=0; } + for (i=0; i<4; i++) + data->voltage[i]=data->iter_voltage[i]; } else if (data->iterate == 2) { /* show results of last iteration */ for (i=0; i<4; i++) data->voltage[i]=data->iter_voltage[i]; - /* if (! already_running) trigger(gl518sm_update_vins) */ + wake_up_interruptible(&data->wq); } else { /* no iteration */ data->voltage[3] = gl518_read_value(client,GL518_REG_VIN3); } } + +int gl518_update_thread(void *c) +{ + struct i2c_client *client = c; + struct gl518_data *data = client->data; + +#ifdef __SMP__ + lock_kernel(); +#endif + exit_mm(current); + current->session = 1; + current->pgrp = 1; + sigfillset(¤t->blocked); + current->fs->umask = 0; + strcpy(current->comm,"gl518sm"); + + data->wq = NULL; + data->thread = current; + +#ifdef __SMP__ + unlock_kernel(); +#endif + + for (;;) { + if (! data->iterate_lock) { + data->iterate_lock=1; + gl518_update_iterate(client); + data->iterate_lock=0; + } + + if ((data->quit_thread) || signal_pending(current)) + break; + interruptible_sleep_on(&data->wq); + } + + data->thread = NULL; + data->quit_thread = 0; + return 0; +} + /* This updates vdd, vin1, vin2 values by doing slow and multiple comparisons for the GL518SM rev 00 that lacks support for direct reading of these values. Values are kept in iter_voltage */ -void gl518_update_vins(struct i2c_client *client) +void gl518_update_iterate(struct i2c_client *client) { struct gl518_data *data = client->data; int i, j, loop_more=1, min[3], max[3], delta[3]; @@ -640,71 +687,79 @@ void gl518_update_vins(struct i2c_client *client) alarm = data->alarms; - for (i=0; i<3; i++) { - if (alarm & (1<voltage_min[i]; - max[i] = (data->voltage_max[i]+data->voltage_min[i]) / 2; - } - delta[i] = (max[i] - min[i]) / 2; + for (i=0; i<3; i++) { + if (alarm & (1<voltage_min[i]; + max[i] = (data->voltage_max[i]+data->voltage_min[i]) / 2; } + delta[i] = (max[i] - min[i]) / 2; + } + + for (j=0; (j<10 && loop_more); j++) { - for (j=0; (j<10 && loop_more); j++) { - - for (i=0; i<3; i++) - gl518_write_value(client, VIN_REG(i), max[i] << 8 | min[i]); - - /* we wait now 1.5 seconds before comparing */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ + HZ/2); - alarm = gl518_read_value(client,GL518_REG_INT); - -#ifdef DEBUG_VIN - printk("gl518sm: iteration %2d: %4d%c %4d%c %4d%c\n", j, - max[0], (alarm&1)?'!':' ', - max[1], (alarm&2)?'!':' ', - max[2], (alarm&4)?'!':' '); -#endif - - for (loop_more=0, i=0; i<3; i++) { - if (alarm & (1<>= 1; - } - } - for (i=0; i<3; i++) - if (alarm & (1<thread) && + ((data->quit_thread) || signal_pending(current))) + goto finish; + + /* we wait now 1.5 seconds before comparing */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ + HZ/2); + alarm = gl518_read_value(client,GL518_REG_INT); + #ifdef DEBUG_VIN - printk("gl518sm: final :%5d %5d %5d\n", max[0], max[1], max[2]); - printk("gl518sm: meter :%5d %5d %5d\n", data->voltage[0], - data->voltage[1], data->voltage[2]); + printk("gl518sm: iteration %2d: %4d%c %4d%c %4d%c\n", j, + max[0], (alarm&1)?'!':' ', + max[1], (alarm&2)?'!':' ', + max[2], (alarm&4)?'!':' '); #endif - data->last_updated_v00 = jiffies; - - /* reset beeps & irqs for vin0-2*/ - gl518_write_value(client,GL518_REG_ALARM, beeps); - gl518_write_value(client,GL518_REG_MASK, irqs); + for (loop_more=0, i=0; i<3; i++) { + if (alarm & (1<iter_voltage[i] = max[i]; - gl518_write_value(client, VIN_REG(i), - data->voltage_max[i] << 8 | data->voltage_min[i]); - } + if (delta[i]) + loop_more++; + delta[i] >>= 1; + } + + } - /* finally read the vin3 meter */ - data->iter_voltage[3] = gl518_read_value(client,GL518_REG_VIN3); + for (i=0; i<3; i++) + if (alarm & (1<voltage[0], + data->voltage[1], data->voltage[2]); +#endif + + /* update values, including vin3 */ + for (i=0; i<3; i++) { + data->iter_voltage[i] = max[i]; + } + data->iter_voltage[3] = gl518_read_value(client,GL518_REG_VIN3); + data->last_updated_v00 = jiffies; + +finish: + + /* reset values */ + for (i=0; i<3; i++) { + gl518_write_value(client, VIN_REG(i), + data->voltage_max[i] << 8 | data->voltage_min[i]); + } + + gl518_write_value(client,GL518_REG_ALARM, beeps); + gl518_write_value(client,GL518_REG_MASK, irqs); #undef VIN_REG } @@ -790,11 +845,19 @@ void gl518_fan(struct i2c_client *client, int operation, int ctl_name, DIV_FROM_REG(data->fan_div[nr])); old = gl518_read_value(client,GL518_REG_FAN_LIMIT); - if (nr == 0) - old = (old & 0x00ff) | (data->fan_min[nr] << 8); - else - old = (old & 0xff00) | data->fan_min[nr]; - + if (nr == 0) { + old = (old & 0x00ff) | (data->fan_min[0] << 8); + if (results[0]==0) + data->alarm_mask &= ~0x20; + else + data->alarm_mask |= 0x20; + } else { + old = (old & 0xff00) | data->fan_min[1]; + if (results[0]==0) + data->alarm_mask &= ~0x40; + else + data->alarm_mask |= 0x40; + } gl518_write_value(client,GL518_REG_FAN_LIMIT,old); } } @@ -833,7 +896,7 @@ void gl518_beep(struct i2c_client *client, int operation, int ctl_name, (data->beep_enable << 2)); } if (*nrels_mag >= 2) { - data->beeps = BEEPS_TO_REG(results[1]); + data->beeps = BEEPS_TO_REG(results[1]) & data->alarm_mask; gl518_write_value(client,GL518_REG_ALARM,data->beeps); } } @@ -904,12 +967,20 @@ void gl518_iterate(struct i2c_client *client, int operation, int ctl_name, *nrels_mag = 1; } else if (operation == SENSORS_PROC_REAL_WRITE) { if ((*nrels_mag >= 1) && (data->iterate!=results[0])) { - for (i=0; i<4; i++) { - data->voltage[i] = 0; - data->iter_voltage[i] = 105; /* bogus */ - } data->iterate=results[0]; + for (i=0; i<4; i++) { + data->voltage[i]=0; + data->iter_voltage[i]=0; + } data->valid=0; + + if ((data->iterate != 2) && (data->thread)) { + data->quit_thread = 1; + wake_up_interruptible(&data->wq); + } else if ((data->iterate==2) && (! data->thread)) { + data->wq = NULL; + kernel_thread(gl518_update_thread, (void*) client, 0); + } } } } diff --git a/kernel/chips/gl520sm.c b/kernel/chips/gl520sm.c index c97bcb52..9abdecc1 100644 --- a/kernel/chips/gl520sm.c +++ b/kernel/chips/gl520sm.c @@ -75,7 +75,9 @@ That's why _TEMP2 and _VIN4 access the same register #define GL520_REG_VIN1 0x14 #define GL520_REG_VDD 0x15 #define GL520_REG_TEMP2_OVER 0x17 +#define GL520_REG_VIN4_MAX 0x17 #define GL520_REG_TEMP2_HYST 0x18 +#define GL520_REG_VIN4_MIN 0x18 /* Conversions. Rounding and limit checking is only done on the TO_REG @@ -128,6 +130,7 @@ extern inline u8 FAN_TO_REG(long rpm, int div) #define GL520_INIT_VIN_1 330 /* 3.3 V */ #define GL520_INIT_VIN_2 286 /* 12 V */ #define GL520_INIT_VIN_3 260 /* Vcore */ +#define GL520_INIT_VIN_4 160 /* -12 V */ #define GL520_INIT_VDD 500 /* 5 V */ #define GL520_INIT_PERCENTAGE 10 @@ -170,8 +173,10 @@ struct gl520_data { u8 temp_over[2]; /* Register values */ u8 temp_hyst[2]; /* Register values */ u8 alarms,beeps,vid; /* Register value */ + u8 alarm_mask; /* Register value */ u8 fan_div[2]; /* Register encoding, shifted right */ u8 beep_enable; /* Boolean */ + u8 two_temps; /* Boolean */ }; #ifdef MODULE @@ -375,6 +380,8 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) data->sysctl_id = i; /* Initialize the GL520SM chip */ + data->two_temps=1; + data->alarm_mask=0xff; gl520_init_client((struct i2c_client *) new_client); return 0; @@ -413,6 +420,7 @@ void gl520_init_client(struct i2c_client *client) gl520_write_value(client,GL520_REG_TEMP1_OVER, TEMP_TO_REG(GL520_INIT_TEMP_OVER)); + /* We set Temp2, but not Vin4. */ gl520_write_value(client,GL520_REG_TEMP2_HYST, TEMP_TO_REG(GL520_INIT_TEMP_HYST)); gl520_write_value(client,GL520_REG_TEMP2_OVER, @@ -534,6 +542,7 @@ void gl520_update_client(struct i2c_client *client) data->alarms = gl520_read_value(client,GL520_REG_INT); data->beeps = gl520_read_value(client,GL520_REG_ALARM); + data->vid = gl520_read_value(client,GL520_REG_VID) & 0x1f; val = gl520_read_value(client,GL520_REG_VDD_LIMIT); data->voltage_min[0] = val & 0xff; @@ -548,11 +557,6 @@ void gl520_update_client(struct i2c_client *client) data->voltage_min[3] = val & 0xff; data->voltage_max[3] = (val >> 8) & 0xff; - data->voltage[0] = gl520_read_value(client,GL520_REG_VDD); - data->voltage[1] = gl520_read_value(client,GL520_REG_VIN1); - data->voltage[2] = gl520_read_value(client,GL520_REG_VIN2); - data->voltage[3] = gl520_read_value(client,GL520_REG_VIN3); - val = gl520_read_value(client,GL520_REG_FAN_COUNT); data->fan[0] = (val >> 8) & 0xff; data->fan[1] = val & 0xff; @@ -560,28 +564,34 @@ void gl520_update_client(struct i2c_client *client) val = gl520_read_value(client,GL520_REG_FAN_LIMIT); data->fan_min[0] = (val >> 8) & 0xff; data->fan_min[1] = val & 0xff; - + data->temp[0] = gl520_read_value(client,GL520_REG_TEMP1); data->temp_over[0] = gl520_read_value(client,GL520_REG_TEMP1_OVER); data->temp_hyst[0] = gl520_read_value(client,GL520_REG_TEMP1_HYST); - data->temp[1] = gl520_read_value(client,GL520_REG_TEMP2); - data->temp_over[1] = gl520_read_value(client,GL520_REG_TEMP2_OVER); - data->temp_hyst[1] = gl520_read_value(client,GL520_REG_TEMP2_HYST); - val = gl520_read_value(client,GL520_REG_MISC); data->fan_div[0] = (val >> 6) & 0x03; data->fan_div[1] = (val >> 4) & 0x03; + + data->alarms &= data->alarm_mask; - if (data->fan_min[0]==0xff) - data->alarms &= ~GL520_ALARM_FAN1; - - if (data->fan_min[1]==0xff) - data->alarms &= ~GL520_ALARM_FAN2; - val = gl520_read_value(client, GL520_REG_CONF); data->beep_enable = (val >> 2) & 1; + data->voltage[0] = gl520_read_value(client,GL520_REG_VDD); + data->voltage[1] = gl520_read_value(client,GL520_REG_VIN1); + data->voltage[2] = gl520_read_value(client,GL520_REG_VIN2); + data->voltage[3] = gl520_read_value(client,GL520_REG_VIN3); + + /* Temp1 and Vin4 are the same input */ + data->temp[1] = gl520_read_value(client,GL520_REG_TEMP2); + data->temp_over[1] = gl520_read_value(client,GL520_REG_TEMP2_OVER); + data->temp_hyst[1] = gl520_read_value(client,GL520_REG_TEMP2_HYST); + + data->voltage[4] = gl520_read_value(client,GL520_REG_VIN4); + data->voltage_min[4] = gl520_read_value(client,GL520_REG_VIN4_MIN); + data->voltage_max[4] = gl520_read_value(client,GL520_REG_VIN4_MAX); + data->last_updated = jiffies; data->valid = 1; } @@ -593,22 +603,29 @@ void gl520_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct gl520_data *data = client->data; + int nr = ctl_name - GL520_SYSCTL_TEMP1; + int regnr; + if (operation == SENSORS_PROC_REAL_INFO) *nrels_mag = 1; else if (operation == SENSORS_PROC_REAL_READ) { gl520_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over[0]); - results[1] = TEMP_FROM_REG(data->temp_hyst[0]); - results[2] = TEMP_FROM_REG(data->temp[0]); + results[0] = TEMP_FROM_REG(data->temp_over[nr]); + results[1] = TEMP_FROM_REG(data->temp_hyst[nr]); + results[2] = TEMP_FROM_REG(data->temp[nr]); *nrels_mag = 3; } else if (operation == SENSORS_PROC_REAL_WRITE) { + if ((nr==0) && (! data->two_temps)) + return; + regnr=nr==0?GL520_REG_TEMP1_OVER:GL520_REG_TEMP2_OVER; if (*nrels_mag >= 1) { - data->temp_over[0] = TEMP_TO_REG(results[0]); - gl520_write_value(client,GL520_REG_TEMP1_OVER,data->temp_over[0]); + data->temp_over[nr] = TEMP_TO_REG(results[nr]); + gl520_write_value(client,regnr,data->temp_over[nr]); } + regnr=nr==0?GL520_REG_TEMP1_HYST:GL520_REG_TEMP2_HYST; if (*nrels_mag >= 2) { - data->temp_hyst[0] = TEMP_TO_REG(results[1]); - gl520_write_value(client,GL520_REG_TEMP1_HYST,data->temp_hyst[0]); + data->temp_hyst[nr] = TEMP_TO_REG(results[nr]); + gl520_write_value(client,regnr,data->temp_hyst[nr]); } } } @@ -632,18 +649,25 @@ void gl520_vin(struct i2c_client *client, int operation, int ctl_name, VDD_FROM_REG(data->voltage[nr]); *nrels_mag = 3; } else if (operation == SENSORS_PROC_REAL_WRITE) { - regnr=nr==0?GL520_REG_VDD_LIMIT:nr==1?GL520_REG_VIN1_LIMIT:nr==2? - GL520_REG_VIN2_LIMIT:GL520_REG_VIN3_LIMIT; - if (*nrels_mag == 1) - old = gl520_read_value(client,regnr) & 0xff00; - if (*nrels_mag >= 2) { - data->voltage_max[nr] = nr?IN_TO_REG(results[1]):VDD_TO_REG(results[1]); - old = data->voltage_max[nr] << 8; - } - if (*nrels_mag >= 1) { - data->voltage_min[nr] = nr?IN_TO_REG(results[0]):VDD_TO_REG(results[0]); - old |= data->voltage_min[nr]; - gl520_write_value(client,regnr,old); + if (nr!=4) { + regnr=nr==0?GL520_REG_VDD_LIMIT:nr==1?GL520_REG_VIN1_LIMIT:nr==2? + GL520_REG_VIN2_LIMIT:GL520_REG_VIN3_LIMIT; + if (*nrels_mag == 1) + old = gl520_read_value(client,regnr) & 0xff00; + if (*nrels_mag >= 2) { + data->voltage_max[nr] = nr?IN_TO_REG(results[1]):VDD_TO_REG(results[1]); + old = data->voltage_max[nr] << 8; + } + if (*nrels_mag >= 1) { + data->voltage_min[nr] = nr?IN_TO_REG(results[0]):VDD_TO_REG(results[0]); + old |= data->voltage_min[nr]; + gl520_write_value(client,regnr,old); + } + } else if (! data->two_temps) { + if (*nrels_mag == 1) + gl520_write_value(client,GL520_REG_VIN4_MIN,IN_TO_REG(results[0])); + if (*nrels_mag >= 2) + gl520_write_value(client,GL520_REG_VIN4_MAX,IN_TO_REG(results[1])); } } } @@ -670,11 +694,19 @@ void gl520_fan(struct i2c_client *client, int operation, int ctl_name, DIV_FROM_REG(data->fan_div[nr])); old = gl520_read_value(client,GL520_REG_FAN_LIMIT); - if (nr == 0) + if (nr == 0) { old = (old & 0x00ff) | (data->fan_min[nr] << 8); - else + if (results[0]==0) + data->alarm_mask &= ~0x20; + else + data->alarm_mask |= 0x20; + } else { old = (old & 0xff00) | data->fan_min[nr]; - + if (results[0]==0) + data->alarm_mask &= ~0x40; + else + data->alarm_mask |= 0x40; + } gl520_write_value(client,GL520_REG_FAN_LIMIT,old); } } @@ -713,7 +745,7 @@ void gl520_beep(struct i2c_client *client, int operation, int ctl_name, (data->beep_enable << 2)); } if (*nrels_mag >= 2) { - data->beeps = BEEPS_TO_REG(results[1]); + data->beeps = BEEPS_TO_REG(results[1]) & data->alarm_mask; gl520_write_value(client,GL520_REG_ALARM,data->beeps); } } @@ -781,17 +813,23 @@ void gl520_fan1off(struct i2c_client *client, int operation, int ctl_name, void gl520_config(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { + struct gl520_data *data = client->data; int old; if (operation == SENSORS_PROC_REAL_INFO) *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { results[0] = ((gl520_read_value(client, GL520_REG_CONF) & 0x10)==0); + data->two_temps = results[0]; *nrels_mag = 1; } else if (operation == SENSORS_PROC_REAL_WRITE) { if (*nrels_mag >= 1) { old = gl520_read_value(client, GL520_REG_CONF) & 0xef; - if (! results[1]) + if (! results[1]) { old |= 0x10; + data->two_temps=0; + } else { + data->two_temps=1; + } gl520_write_value(client,GL520_REG_CONF,old); } } @@ -831,7 +869,7 @@ EXPORT_NO_SYMBOLS; #ifdef MODULE -MODULE_AUTHOR("Frodo Looijaard "); +MODULE_AUTHOR("Frodo Looijaard and Kyösti Mälkki "); MODULE_DESCRIPTION("GL520SM driver"); int init_module(void)