Logo Search packages:      
Sourcecode: xmbmon version File versions  Download package

sens_lm80.c

/*
 * Natinal Semiconductor LM80 hardware monitor chip
 *
 ***************************************************************
 * Before calling these routines, one must call method->Open() *
 * After calling these routines, one must call method->Close() *
 ***************************************************************
 *

National Semiconductor
         Chip         Temp    Volt    Fan     SMBus   IOport
        lm80           1       7       2       yes     no

 *
 *    Copyright Shin-ichi Nagamura
 */


#include    <stdio.h>
#include    "sensors.h"

/* external (global) data */
extern int smb_slave;
extern LM_METHODS method_smb;


#undef      DEBUG

#define     LM80_ADDR_START         0x50  /*0x50-0x5E*/
#define     LM80_ADDR_END           0x5E

#define     LM80_CONFIG             0x00
#define     LM80_ISR1               0x01
#define     LM80_ISR2               0x02
#define     LM80_FANDIV             0x05
#define     LM80_RESOLUTION         0x06
#define     LM80_IN0                0x20
#define     LM80_TEMPERATURE  0x27
#define     LM80_FANRPM1            0x28
#define     LM80_FANRPM2            0x29

#define     LM80_CONFIG_START 0x01
#define     LM80_CONFIG_INTEN 0x02
#define     LM80_CONFIG_INTOPEN     0x04
#define     LM80_CONFIG_INTCLR      0x08
#define     LM80_CONFIG_RESET 0x10
#define     LM80_CONFIG_CHACLR      0x20
#define     LM80_CONFIG_GPO         0x40
#define     LM80_CONFIG_INIT  0x80

#define     LM80_R06_OSACTHI  0x02
#define     LM80_R06_TEMPRES  0x08
#define     LM80_R06_TEMP11         0xF0
#define     LM80_R06_TEMP8          0x80

static      int         lm80_probe(LM_METHODS *);
static      float lm80_temp(LM_METHODS *, int);
static      int         lm80_fanrpm(LM_METHODS *, int);
static      float lm80_volt(LM_METHODS *, int);

#if defined(DEBUG)
static      void  dumpreg( void );
#endif      /*DEBUG*/

SENSOR lm80 = {
      "Nat.Semi.Con. Chip LM80",
      lm80_probe,
      lm80_temp,
      lm80_volt,
      lm80_fanrpm
};


#define LM80_chkRegNum 20

/* Register checked for probing */
static int chkReg[] = {
      0x00, 0x01, 0x02, 0x04,
      0x05, 0x06, 0x20, 0x21,
      0x22, 0x24, 0x25, 0x26,
      0x27, 0x28, 0x29, 0x2B,
      0x2D, 0x2F, 0x31, 0x33,
      0x35, 0x37, 0x39, 0x3B,
      0x3C, 0x3D,
      -1 };


/*
 *  return 0 if not probed
 */
static      int     lm80_probe(LM_METHODS *method)
{
      int n, dat, reg, save;

      if( method != &method_smb )
            return 0;

      save = smb_slave;

      for (n = LM80_ADDR_START; n <= LM80_ADDR_END;) {
            if (!(smb_slave = get_smb_slave(n, LM80_ADDR_END)))
                  goto ret0;
            else {
                  if (method->Read(LM80_ISR2) & 0xC0) {
                        n = smb_slave + 2;
                        continue;
                  }
                  for (reg = 0x2A; reg <= 0x3D; reg++) {
                        dat = method->Read(reg);
                        if (method->Read(reg + 0x40) != dat ||
                            method->Read(reg + 0x80) != dat ||
                            method->Read(reg + 0xC0) != dat)
                              break;
                  }
                  if (reg > 0x3D
                        && chkReg_Probe(smb_slave, "Probing LM80 chip:\n",
                                    chkReg, method) >= LM80_chkRegNum)
                              goto ret1;
                  else
                        n = smb_slave + 2;
            }
      }

ret0:
      smb_slave = save;
      return 0;
ret1:
      if((method->Read(LM80_CONFIG ) & LM80_CONFIG_START) == 0) {
            method->Write(LM80_CONFIG, LM80_CONFIG_RESET);
            method->Write(LM80_CONFIG, LM80_CONFIG_START);
      }

      method->Write(LM80_FANDIV,
            (method->Read(LM80_FANDIV) & 0x3C) | 0x40);
      method->Write(LM80_RESOLUTION,
            LM80_R06_TEMPRES | LM80_R06_OSACTHI);

#if defined(DEBUG)
      dumpreg();
#endif      /*DEBUG*/

      kill_smb_slave(smb_slave);
      return 1;
}


/*!
 *    \retval     0xFFFF      no sensor
 *    \retval     other temperature
 *  no = 0,1,2,...
 */
static      float lm80_temp(LM_METHODS *method, int no)
{
      int         reg, val, sft;
      float ret;

      if (no != 0)
            return 0xFFFF;

      reg   = method->Read(LM80_RESOLUTION);
      val   = method->Read(LM80_TEMPERATURE);

      sft   = ((( reg & LM80_R06_TEMPRES ) >> 3 ) * 3 ) + 1;

      val   <<= sft;
      val   |= reg >> (8 - sft);

      ret   = (float)val;
      if (reg & LM80_R06_TEMPRES)
            ret   *= 0.0625;
      else
            ret   *= 0.5;

      return ret;
}



/*!
 *    \retval     0x0000FFFF  no sensor
 *  no = 0,1,2,...
 */
static      float lm80_volt(LM_METHODS *method, int no)
{
      const float r1[7] = { 23.7, 23.7, 22.1, 24,  160,   27, 180 };
      const float r2[7] = { 75,   75,   30,   14.7, 30.1, 3.4, 42.2     };
      float vout, val;

      if( no < 0 || 6 < no )
            return 0xFFFF;

      vout  = method->Read(LM80_IN0 + no);
      vout *= 0.01;     /*LSB is 10mv*/

      /*
       *VOUT = ( VCC * R2 ) / ( R1 + R2 )
       *VCC  = ( VOUT * ( R1 + R2 )) / R2
       */
      val   = ( vout * ( r1[no] + r2[no] )) / r2[no];
      if( no >= 5 )
            val   = ( val - 5 ) * -1;
/*
 *                ((( vout * ( r1[no] + r2[no] )) / r2[no] ) - 5 ) * -1;
 */

      return val;
}


/*!
 *    \retval     0x0000FFFF  no sensor
 *    \retval     0x00010000  unknown (maybe no sensor)
 *  no = 0,1,2,...
 *
 *  Clock is 22.5kHz (22,500 x 60 = 1350000 counts/minute)
 */
static      int         lm80_fanrpm(LM_METHODS *method, int no)
{
      int         reg, val;
      int         div, sft;
      long  rpm;

#if defined(DEBUG)
printf("lm80_fanrpm(): no=%d\n", no);
#endif      /*DEBUG*/
      if (no < 0 || 1 < no)
            return 0xFFFF;

      reg   = method->Read(LM80_FANDIV);
      val   = method->Read(LM80_FANRPM1 + no);
#if defined(DEBUG)
printf("lm80_fanrpm(): reg=0x%02X, val=0x%02X\n", reg, val);
#endif      /*DEBUG*/
      sft   = (no + 1) * 2;
      div   = (reg >> sft) & 0x03;
#if defined(DEBUG)
printf( "lm80_fanrpm(): sft=%d, div=%d\n", sft, div );
#endif      /*DEBUG*/

      if (val == 0xFF) {
            if (div < 3) {
                  reg   += 1 << sft;
                  (*method->Write)(LM80_FANDIV, reg);
            }
#if defined(DEBUG)
printf( "lm80_fanrpm(): write new reg 0x%02X\n", reg );
#endif      /*DEBUG*/
            return 0x10000;
      }

#if defined(DEBUG)
printf( "lm80_fanrpm(): val=%d, div=%d\n", val, div );
#endif      /*DEBUG*/
      rpm         = 1350000 / ( val * ( 1 << div ));
      return rpm;
}


#if defined(DEBUG)
static  void    dumpreg(void)
{
      int cmd;

      printf( "SlaveAddress=0x%04X", smb_slave );

#if 0
      printf( "Reg00 :" );
      for( cmd=0; cmd<=6; cmd++ )
            printf( " 0x%02X", (*method_smb.Read)(cmd));
#endif

      for( cmd=0x00; cmd<=0x7F; cmd++ ) {
            if(( cmd & 0x0F ) == 0 )
                  printf( "\nReg%02X :", cmd );
            printf("%c%02X", ((cmd&0x0F)==8)?'-':' ',(*method_smb.Read)(cmd));
      }
      printf("\n");
}
#endif  /*DEBUG*/

Generated by  Doxygen 1.6.0   Back to index