Changeset 484

Show
Ignore:
Timestamp:
06/17/99 00:16:48 (9 years ago)
Author:
kmalkki
Message:

(Kyösti) gl518sm driver code updates

* rewrote iteration code for rev 0x00
* fan1 on/off control

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • lm-sensors/trunk/TODO

    r467 r484  
    3838* Test SIS5595(/91/98) sensor support. Write generic i2c support.  
    3939  Thomas Dickel <Thomas.Dickel@mni.fh-giessen.de> owns one SIS5595. 
    40 * Make GL518SM rev 00 voltage iteration run as a kernel thread. 
    41   Add libsensors support for the new readable registers. 
    4240* adm9240: check whether the current voltage computations are correct. 
    4341  Probably not, as they are different from the datasheet specifications. 
     
    4543* lm80: Check how OS alarms work. At page 17 of the sheet, it tells 
    4644  something completely different from the description at page 25. 
    47 * gl518sm: Update binary search to 'trinary' search: because we have 
    48   both upper and lower limits, you can see the difference between three 
    49   pieces of the current range. 
    50   Also, you can assume that new values are close to old values, so start 
    51   with trying to use a small range near the old values (already partially 
    52   done?) 
     45* gl518sm: Assume that new values are close to old values, so start with 
     46  trying to use a small range near the old values (already partially done) 
    5347 
    5448LIBRARY 
  • lm-sensors/trunk/doc/chips/gl518sm

    r403 r484  
    1212    Prefix `gl518sm-r80' 
    1313    Addresses scanned: I2C 0x2c and 0x2d 
    14     Datasheet: Not available at all, as far as we know 
     14    Datasheet: Not available 
    1515 
    1616Author: Frodo Looijaard <frodol@dds.nl> 
     
    3636* probe_range: short array (min = 1, max = 48) 
    3737  List of adapter,start-addr,end-addr triples to scan additionally 
    38 * readall: int 
    39   Enable the experimental code, which tries to find the voltages of 
    40   revision zero chips by slow (10 seconds) interpolation 
    41  
    4238 
    4339Description 
     
    5955 
    6056FAN rotation speeds are reported in RPM (rotations per minute). An alarm is 
    61 triggered if the rotation speed has dropped below a programmable limit. FAN  
    62 readings can be divided by a programmable divider (1, 2, 4 or 8) to give 
     57triggered if the rotation speed has dropped below a programmable limit. 
     58In case when you have selected to turn Fan1 off, no Fan1 alarm is triggered 
     59if measured temperature is below 'over temperature' limit. 
     60 
     61FAN readings can be divided by a programmable divider (1, 2, 4 or 8) to give 
    6362the readings more range or accuracy. This is important because some FANs 
    64 report only one 'tick' each rotation, while others report two - making 
    65 all readings twice as high. Not all RPM values can accurately be represented, 
    66 so some rounding is done. With a divider of 2, the lowest representable 
    67 value is around 1900 RPM. 
    68  
    69 Voltage sensors (also known as VIN sensors) report their values in volts. 
    70 An alarm is triggered if the voltage has crossed a programmable minimum  
    71 or maximum limit. Note that minimum in this case always means 'closest to 
     63report only one 'tick' each rotation, while others report two. 
     64Not all RPM values can accurately be represented, so some rounding is done. 
     65With a divider of 2, the lowest representable value is around 1900 RPM. 
     66 
     67Voltage sensors (also known as VIN sensors) report their values in volts. An 
     68alarm is triggered if the voltage has crossed a programmable minimum or 
     69maximum limit. Note that minimum in this case always means 'closest to 
    7270zero'; this is important for negative voltage measurements. The VDD input 
    7371measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023 
    74 volt. The other inputs measure voltages between 0.000 and 4.845 volt, with 
    75 a resolution of 0.019 volt. Note that revision 0x00 chips do not support 
    76 reading the current voltage of any input except for VIN3; limit setting 
    77 and alarms work fine, though. Yes, this is weird. There is experimental 
    78 code to compute them by interpolation; see the 'readall' module parameter. 
     72volt. The other inputs measure voltages between 0.000 and 4.845 volt, with a 
     73resolution of 0.019 volt. Note that revision 0x00 chips do not support 
     74reading the current voltage of any input except for VIN3; limit setting and 
     75alarms work fine, though. There is code to compute them by iterating. 
    7976 
    8077When an alarm goes off, you can be warned by a beeping signal through 
     
    9188The GL518SM only updates its values each 1.5 seconds; reading it more often 
    9289will do no harm, but will return 'old' values. 
    93  
    94 Not supported is the option to use only one fan, and to enable/disable the  
    95 speed of that fan automatically as function of the current temperature. 
    96  
    9790 
    9891Chip Features 
  • lm-sensors/trunk/kernel/chips/gl518sm.c

    r478 r484  
    159159         u8 fan_div[2];              /* Register encoding, shifted right */ 
    160160         u8 beep_enable;             /* Boolean */ 
    161          u8 sw_alarm_mask;           /* Mask unwanted HW alarms */ 
     161         u8 iterate;                 /* Voltage iteration mode */ 
     162         u8 fan1conf;                /* Fan1 on/off control */ 
    162163}; 
    163164 
     
    172173MODULE_PARM_DESC(readall,"Enable the experimental code, which tries to find " 
    173174                         "the voltages of revision zero chips by " 
    174                          "slow (10 seconds) interpolation"); 
     175                         "slow (10 seconds) iteration"); 
    175176#endif /* MODULE */ 
    176177 
     
    203204static void gl518_beep(struct i2c_client *client, int operation, int ctl_name,  
    204205                int *nrels_mag, long *results); 
     206static void gl518_fan1off(struct i2c_client *client, int operation, 
     207                int ctl_name, int *nrels_mag, long *results); 
     208static void gl518_iterate(struct i2c_client *client, int operation, 
     209                int ctl_name, int *nrels_mag, long *results); 
    205210 
    206211/* This is the driver that will be inserted */ 
     
    242247  { GL518_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &sensors_proc_real, 
    243248    &sensors_sysctl_real, NULL, &gl518_beep }, 
     249  { GL518_SYSCTL_FAN1OFF, "fan1off", NULL, 0, 0644, NULL, &sensors_proc_real, 
     250    &sensors_sysctl_real, NULL, &gl518_fan1off }, 
     251  { GL518_SYSCTL_ITERATE, "iterate", NULL, 0, 0644, NULL, &sensors_proc_real, 
     252    &sensors_sysctl_real, NULL, &gl518_iterate }, 
    244253  { 0 } 
    245254}; 
     
    427436  gl518_write_value(client,GL518_REG_CONF,0x44); 
    428437   
    429   /* Sometimes we want to report no alarm, even when 
    430      the hardware tells the opposite */ 
    431   data->sw_alarm_mask = 0xff; 
     438  data->iterate=readall; 
    432439} 
    433440 
     
    538545    data->voltage_max[3] = (val >> 8) & 0xff; 
    539546 
     547    data->voltage[3] = gl518_read_value(client,GL518_REG_VIN3); 
     548#ifndef DEBUG_VIN     
    540549    if (data->type != gl518sm_r00) { 
    541550      data->voltage[0] = gl518_read_value(client,GL518_REG_VDD); 
    542551      data->voltage[1] = gl518_read_value(client,GL518_REG_VIN1); 
    543552      data->voltage[2] = gl518_read_value(client,GL518_REG_VIN2); 
    544     } else { 
    545       if (!readall) { 
    546         data->voltage[0] = 0; 
    547         data->voltage[1] = 0
    548         data->voltage[2] = 0
    549       } 
    550     } 
    551     data->voltage[3] = gl518_read_value(client,GL518_REG_VIN3); 
     553    } else 
     554      gl518_update_client_rev00(client); 
     555#else 
     556    data->voltage[0] = gl518_read_value(client,GL518_REG_VDD)
     557    data->voltage[1] = gl518_read_value(client,GL518_REG_VIN1)
     558    data->voltage[2] = gl518_read_value(client,GL518_REG_VIN2); 
     559    gl518_update_client_rev00(client); 
     560#endif 
    552561 
    553562    val = gl518_read_value(client,GL518_REG_FAN_COUNT); 
     
    566575    data->fan_div[0] = (val >> 6) & 0x03; 
    567576    data->fan_div[1] = (val >> 4) & 0x03; 
    568     data->beep_enable = (gl518_read_value(client,GL518_REG_CONF) >> 2) & 1; 
     577    data->fan1conf = (val >> 3) & 1; 
     578 
     579    if (((data->fan1conf) && (data->temp < data->temp_over)) || 
     580        (data->fan_min[0]==0xff)) 
     581       data->alarms &= ~GL518_ALARM_FAN1; 
     582        
     583    if (data->fan_min[1]==0xff) 
     584       data->alarms &= ~GL518_ALARM_FAN2; 
     585        
     586    val = gl518_read_value(client, GL518_REG_CONF); 
     587    data->beep_enable = (val >> 2) & 1; 
    569588 
    570589    data->last_updated = jiffies; 
     
    575594} 
    576595 
    577 /* Similar to gl518_update_client() but updates vdd, vin1, vin2 values  
    578    by doing slow and multiple comparisons for the GL518SM rev 00 that 
    579    lacks support for direct reading of these values. 
    580    (added by Ludovic Drolez (ldrolez@usa.net) */ 
     596/* This updates vdd, vin1, vin2 values by doing slow and multiple 
     597   comparisons for the GL518SM rev 00 that lacks support for direct 
     598   reading of these values. */ 
    581599 
    582600void gl518_update_client_rev00(struct i2c_client *client) 
    583601{ 
    584602  struct gl518_data *data = client->data; 
    585   int j, min, max[3], delta; 
    586  
    587   down(&data->update_lock); 
     603  int i, j, loop_more=1, min[3], max[3], delta[3]; 
     604  int alarm, config; 
     605 
     606#define VIN_REG(c) c==0?GL518_REG_VDD_LIMIT:\ 
     607                   c==1?GL518_REG_VIN1_LIMIT:\ 
     608                   GL518_REG_VIN2_LIMIT 
     609   
     610  config = gl518_read_value(client, GL518_REG_CONF) & 0xfb; 
     611  alarm = data->alarms; 
     612   
     613  if (data->iterate==0) { 
     614     for (i=0; i<3; i++) 
     615       data->voltage[i]=0; 
     616    return; 
     617  } 
    588618 
    589619#ifndef DEBUG_VIN 
    590620  /* as that update is slow, we consider the data valid for 30 seconds */ 
    591   if (jiffies - data->last_updated_v00 > 30*HZ ) { 
     621  if ((jiffies - data->last_updated_v00 > 30*HZ) || (alarm & 7)) { 
    592622#else 
    593623  if (jiffies - data->last_updated_v00 > HZ+HZ/2 ) { 
    594624#endif 
    595625 
    596      /* disable audible alarm */ 
    597      gl518_write_value(client,GL518_REG_CONF, 
    598                         (gl518_read_value(client,GL518_REG_CONF) & 0xfb)); 
    599  
    600     min = 1; 
    601     max[0] = VDD_TO_REG(GL518_INIT_VDD); 
    602     max[1] = IN_TO_REG(GL518_INIT_VIN_1);  
    603     max[2] = IN_TO_REG(GL518_INIT_VIN_2); 
    604     delta = 32; 
    605     do {                         
    606       gl518_write_value(client,GL518_REG_VDD_LIMIT,(max[0] << 8) | min); 
    607       gl518_write_value(client,GL518_REG_VIN1_LIMIT,(max[1] << 8) | min); 
    608       gl518_write_value(client,GL518_REG_VIN2_LIMIT,(max[2] << 8) | min); 
     626    for (i=0; i<3; i++) { 
     627      if (alarm & (1<<i)) { 
     628        min[i] = 0; 
     629        max[i] = 127; 
     630      } else { 
     631        min[i] = data->voltage_min[i]; 
     632        max[i] = (data->voltage_max[i]+data->voltage_min[i]) / 2; 
     633      } 
     634      delta[i] = (max[i] - min[i]) / 2; 
     635    } 
     636   
     637    /* disable beeps */ 
     638    gl518_write_value(client,GL518_REG_CONF,config); 
     639 
     640    for (j=0; (j<10 && loop_more); j++) { 
     641     
     642      for (i=0; i<3; i++) 
     643        gl518_write_value(client, VIN_REG(i), max[i] << 8 | min[i]); 
    609644 
    610645      /* we wait now 1.5 seconds before comparing */ 
    611646      current->state = TASK_INTERRUPTIBLE; 
    612647      schedule_timeout(HZ + HZ/2); 
    613  
    614       /* read comparators */     
    615       j = gl518_read_value(client,GL518_REG_INT); 
    616       if ((j & 1) == 0) { 
    617         max[0] = max[0] - delta;     
    618       } else { 
    619         max[0] = max[0] + delta; 
     648      alarm = gl518_read_value(client,GL518_REG_INT); 
     649 
     650#ifdef DEBUG_VIN    
     651     printk("gl518sm: iteration %2d: %4d%c %4d%c %4d%c\n", j, 
     652             max[0], (alarm&1)?'!':' ', 
     653             max[1], (alarm&2)?'!':' ', 
     654             max[2], (alarm&4)?'!':' '); 
     655#endif 
     656 
     657      for (loop_more=0, i=0; i<3; i++) { 
     658        if (alarm & (1<<i)) 
     659          max[i] += delta[i]; 
     660        else 
     661          max[i] -= delta[i]; 
     662 
     663        if (delta[i]) 
     664          loop_more++; 
     665        delta[i] >>= 1; 
    620666      } 
    621       if ((j & 2) == 0) { 
    622         max[1] = max[1] - delta;     
    623       } else { 
    624         max[1] = max[1] + delta; 
    625       } 
    626       if ((j & 4) == 0) { 
    627         max[2] = max[2] - delta;     
    628       } else { 
    629         max[2] = max[2] + delta; 
    630       } 
    631       delta >>= 1; 
    632 #ifdef DEBUG_VIN 
    633       printk("Iterations: %3d %3d %3d \n", max[0], max[1], max[2]); 
     667    } 
     668     
     669   for (i=0; i<3; i++) 
     670     if (alarm & (1<<i)) 
     671       max[i]++; 
     672     
     673#ifdef DEBUG_VIN    
     674    printk("gl518sm:    final   :%5d %5d %5d\n", max[0], max[1], max[2]); 
     675    printk("gl518sm:    meter   :%5d %5d %5d\n", data->voltage[0], 
     676           data->voltage[1], data->voltage[2]); 
    634677#endif 
    635     } while (delta != 0); 
    636      
    637     /* do a final comparison to get to least significant bit */ 
    638     gl518_write_value(client,GL518_REG_VDD_LIMIT,(max[0] << 8) | min); 
    639     gl518_write_value(client,GL518_REG_VIN1_LIMIT,(max[1] << 8) | min); 
    640     gl518_write_value(client,GL518_REG_VIN2_LIMIT,(max[2] << 8) | min); 
    641   
    642     /* we wait now 1.5 seconds before comparing */ 
    643     current->state = TASK_INTERRUPTIBLE; 
    644     schedule_timeout(HZ + HZ/2); 
    645  
    646     /* read comparators */       
    647     j = gl518_read_value(client,GL518_REG_INT); 
    648     if ((j & 1) == 0) max[0]--; 
    649     if ((j & 2) == 0) max[1]--; 
    650     if ((j & 4) == 0) max[2]--; 
    651  
    652 #ifdef DEBUG_VIN 
    653   if (data->type == gl518sm_r00) { 
    654      printk("Avdd: Meter: %3d, Search: %3d, Diff: %3d mV\n", 
    655              data->voltage[0], max[0], (max[0] - data->voltage[0]) * 23); 
    656      printk("Vin1: Meter: %3d, Search: %3d, Diff: %3d mV\n", 
    657              data->voltage[1], max[1], (max[1] - data->voltage[1]) * 19); 
    658      printk("Vin2: Meter: %3d, Search: %3d, Diff: %3d mV\n", 
    659              data->voltage[2], max[2], (max[2] - data->voltage[2]) * 19); 
    660   } else 
    661      printk("No voltage meter to read on rev 00 ICs\n");      
    662 #endif   
    663  
    664     /* update voltages values */     
    665     data->voltage[0] = max[0]; 
    666     data->voltage[1] = max[1]; 
    667     data->voltage[2] = max[2]; 
    668      
    669     /* restore original comparator values */ 
    670     gl518_write_value(client,GL518_REG_VDD_LIMIT, 
    671                       (data->voltage_max[0] << 8) | data->voltage_min[0]); 
    672     gl518_write_value(client,GL518_REG_VIN1_LIMIT, 
    673                       (data->voltage_max[1] << 8) | data->voltage_min[1]); 
    674     gl518_write_value(client,GL518_REG_VIN2_LIMIT, 
    675                       (data->voltage_max[2] << 8) | data->voltage_min[2]); 
    676678 
    677679    data->last_updated_v00 = jiffies; 
    678      
    679     /* reset audible alarm state */ 
    680     gl518_write_value(client,GL518_REG_CONF, 
    681            (gl518_read_value(client,GL518_REG_CONF) & 0xfb) |  
    682            (data->beep_enable << 2)); 
    683   } 
    684   up(&data->update_lock); 
     680   
     681    /* reset beeps */ 
     682    gl518_write_value(client, GL518_REG_CONF, 
     683       (config | (data->beep_enable << 2))); 
     684 
     685    /* reset values */ 
     686    for (i=0; i<3; i++) { 
     687      data->voltage[i] = max[i]; 
     688      gl518_write_value(client, VIN_REG(i), 
     689        data->voltage_max[i] << 8 | data->voltage_min[i]); 
     690    }  
     691  } 
     692#undef VIN_REG 
    685693} 
    686694 
     
    720728  else if (operation == SENSORS_PROC_REAL_READ) { 
    721729    gl518_update_client(client); 
    722 #ifndef DEBUG_VIN     
    723     if ((data->type == gl518sm_r00) && (nr != 3) && readall) 
    724        /* only update VDD, VIN1, VIN2 voltages */ 
    725        gl518_update_client_rev00(client); 
    726 #else 
    727     gl518_update_client_rev00(client); 
    728 #endif 
    729730    results[0] = nr?IN_FROM_REG(data->voltage_min[nr]): 
    730731                    VDD_FROM_REG(data->voltage_min[nr]); 
     
    778779        old = (old & 0xff00) | data->fan_min[nr]; 
    779780 
    780       if (results[0]) 
    781           data->sw_alarm_mask |= (nr ? GL518_ALARM_FAN2 : GL518_ALARM_FAN1); 
    782       else 
    783           data->sw_alarm_mask &= ~(nr ? GL518_ALARM_FAN2 : GL518_ALARM_FAN1); 
    784  
    785781      gl518_write_value(client,GL518_REG_FAN_LIMIT,old); 
    786782    } 
     
    797793  else if (operation == SENSORS_PROC_REAL_READ) { 
    798794    gl518_update_client(client); 
    799     results[0] = ALARMS_FROM_REG(data->alarms & data->sw_alarm_mask); 
     795    results[0] = ALARMS_FROM_REG(data->alarms); 
    800796    *nrels_mag = 1; 
    801797  } 
     
    827823} 
    828824 
     825 
    829826void gl518_fan_div(struct i2c_client *client, int operation, int ctl_name, 
    830827                   int *nrels_mag, long *results) 
     
    853850} 
    854851 
     852void gl518_fan1off(struct i2c_client *client, int operation, int ctl_name,  
     853                int *nrels_mag, long *results) 
     854{ 
     855  int old; 
     856  if (operation == SENSORS_PROC_REAL_INFO) 
     857    *nrels_mag = 0; 
     858  else if (operation == SENSORS_PROC_REAL_READ) { 
     859    results[0] = ((gl518_read_value(client, GL518_REG_MISC) & 0x08) !=0); 
     860    results[1] = ((gl518_read_value(client, GL518_REG_CONF) & 0x10) !=0); 
     861    *nrels_mag = 2; 
     862  } else if (operation == SENSORS_PROC_REAL_WRITE) { 
     863    if (*nrels_mag >= 1) { 
     864      old = gl518_read_value(client, GL518_REG_MISC) & 0xf7; 
     865      if (results[0]) 
     866        old |= 0x08; 
     867      gl518_write_value(client,GL518_REG_MISC,old); 
     868    } 
     869    if (*nrels_mag >= 2) { 
     870      old = gl518_read_value(client, GL518_REG_CONF) & 0xef; 
     871      if (results[1]) 
     872        old |= 0x10; 
     873      gl518_write_value(client,GL518_REG_CONF,old); 
     874    } 
     875  } 
     876} 
     877 
     878void gl518_iterate(struct i2c_client *client, int operation, int ctl_name,  
     879                int *nrels_mag, long *results) 
     880{ 
     881  struct gl518_data *data = client->data; 
     882  if (operation == SENSORS_PROC_REAL_INFO) 
     883    *nrels_mag = 0; 
     884  else if (operation == SENSORS_PROC_REAL_READ) { 
     885    results[0] = data->iterate; 
     886    *nrels_mag = 1; 
     887  } else if (operation == SENSORS_PROC_REAL_WRITE) { 
     888    if (*nrels_mag >= 1) 
     889      data->iterate=results[0]; 
     890  } 
     891} 
    855892 
    856893int gl518_init(void) 
     
    901938 
    902939#endif /* MODULE */ 
     940 
  • lm-sensors/trunk/kernel/include/sensors.h

    r464 r484  
    435435#define GL518_SYSCTL_ALARMS 2001   /* bitvector */ 
    436436#define GL518_SYSCTL_BEEP 2002     /* bitvector */ 
     437#define GL518_SYSCTL_FAN1OFF 2003 
     438#define GL518_SYSCTL_ITERATE 2004 
    437439 
    438440#define GL518_ALARM_VDD 0x01