(Kyösti)

* 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
This commit is contained in:
Kyosti Malkki committed 1999-07-26 15:31:45 +00:00
1 parent a55703e80b
commit a92e84fe2a
3 files changed
+236 -125

No files matched your search

+2
View File
@@ -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-*"
+155 -84
View File
@@ -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(&current->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<<i)) {
min[i] = 0;
max[i] = 127;
} else {
min[i] = data->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<<i)) {
min[i] = 0;
max[i] = 127;
} else {
min[i] = data->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<<i))
max[i] += delta[i];
else
max[i] -= delta[i];
if (delta[i])
loop_more++;
delta[i] >>= 1;
}
}
for (i=0; i<3; i++)
if (alarm & (1<<i))
max[i]++;
gl518_write_value(client, VIN_REG(i), max[i] << 8 | min[i]);
if ((data->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<<i))
max[i] += delta[i];
else
max[i] -= delta[i];
/* set values */
for (i=0; i<3; i++) {
data->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<<i))
max[i]++;
#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]);
#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);
}
}
}
}
+79 -41
View File
@@ -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 <frodol@dds.nl>");
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Kyösti Mälkki <kmalkki@cc.hut.fi>");
MODULE_DESCRIPTION("GL520SM driver");
int init_module(void)