/*
* National Semiconductor LM85 and compatible hardware monitor chips
*
***************************************************************
* 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
lm85 3 5 4 yes no
Analog Devices
Chip Temp Volt Fan SMBus IOport
adm1024 2 5 2 yes no
adm1025 2 5 - yes no
adm1027 3 5 4 yes no
adt7463 3 5 4 yes no
Standard Microsystem
Chip Temp Volt Fan SMBus IOport
emc6d10x 3 5 4 yes no
*
* by YRS
*/
#include <stdio.h>
#include <string.h>
#include "sensors.h"
/* external (global) data */
extern int smb_slave;
extern LM_METHODS method_isa, method_smb;
extern int numSMBSlave, canSMBSlave[128];
#define LM85_ADDR_START 0x58 /*0x58-0x5A*/
#define LM85_ADDR_END 0x5C
#define LM85_DEVID 0x3D
#define LM85_VENDID 0x3E
#define LM85_VERSTEP 0x3F
#define LM85_CONF 0x40
#define LM85_TEMP(nr) (0x25 + (nr))
#define LM85_VOLT(nr) (0x20 + (nr))
#define LM85_FANLSB(nr) (0x28 + (nr) * 2)
#define LM85_FANMSB(nr) (0x29 + (nr) * 2)
#define LM85_VID 0x43
#define ADM_24FAN(nr) (0x28 + (nr))
#define ADM_24FANDIV 0x47
#define ADM_24MODE 0x16
#define ADM_EXTRES1 0x76
#define ADM_EXTRES2 0x77
#define ADM_FANPPR 0x7B
static int lm85chipid = 0;
static float Vfac;
static int lm85_probe(LM_METHODS *);
static int lm85_chk(LM_METHODS *);
static float lm85_temp(LM_METHODS *, int);
static int lm85_fanrpm(LM_METHODS *, int);
static float lm85_volt(LM_METHODS *, int);
#if 0
static int lm85_fan_ppr(LM_METHODS *, int);
static void lm85_fan_ppr_set(LM_METHODS *, int, int);
#endif
#define BUFF_LEN 128
static char buff[BUFF_LEN];
static int adm_24fan[2] = {0, 0};
SENSOR lm85 = {
buff,
lm85_probe,
lm85_temp,
lm85_volt,
lm85_fanrpm
};
enum lm85_chips {
NOSENSER,
LM85,
EMC6D10X,
ADM1024,
ADM1025,
ADM1027,
ADT7463,
};
static char *lm85chip[] = {
"No Sensor",
"Nat.Semi.Con. Chip LM85",
"SMSC Chip EMC6D10X",
"Analog Dev. Chip ADM1024",
"Analog Dev. Chip ADM1025",
"Analog Dev. Chip ADM1027",
"Analog Dev. Chip ADT7463",
NULL };
#define LM85_chkRegNum 20
/* Register checked for probing */
static int chkReg[] = {
0x20, 0x21, 0x22, 0x23,
0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x2B,
0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33,
0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B,
0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43,
0x70, 0x71, 0x72, 0x73,
0x76, 0x77, 0x78, 0x7B,
-1 };
/*
* return 0 if not probed
*/
static int lm85_probe(LM_METHODS *method)
{
int n, save;
if (method != &method_smb)
return 0;
save = smb_slave;
for (n = LM85_ADDR_START; n <= LM85_ADDR_END;) {
if (!(smb_slave = get_smb_slave(n, LM85_ADDR_END)))
goto ret0;
else {
if (lm85_chk(method)
&& chkReg_Probe(smb_slave,
"Probing LM85/compatible chip:\n", chkReg, method)
>= LM85_chkRegNum)
goto ret1;
else
n = smb_slave + 2;
}
}
ret0:
smb_slave = save;
return 0;
ret1:
kill_smb_slave(smb_slave);
if (lm85chipid == ADM1024) {
n = method->Read(ADM_24MODE);
adm_24fan[0] = n & 0x01; /* fan1 present if n & 0x01 = 0 */
adm_24fan[1] = n & 0x02; /* fan2 present if n & 0x02 = 0 */
}
if (lm85chipid < ADM1027)
Vfac = 1. / (float) 0xFF;
else
Vfac = 1. / (float) 0x3FF;
return lm85chipid;
}
static int lm85_chk(LM_METHODS *method)
{
int vendor, verstep;
vendor = method->Read(LM85_VENDID);
verstep = method->Read(LM85_VERSTEP);
if (vendor == 0x01) { /* National Semicon. */
if ((verstep & 0xf0) == 0x60)
lm85chipid = LM85;
else
goto ret0;
} else if (vendor == 0x41) { /* Analog Devices */
if ((verstep & 0xF0) == 0x10)
lm85chipid = ADM1024;
else if ((verstep & 0xF0) == 0x20)
lm85chipid = ADM1025;
else if (verstep == 0x60)
lm85chipid = ADM1027;
else if (verstep == 0x62)
lm85chipid = ADT7463;
else
goto ret0;
} else if (vendor == 0x5C) { /* Standard Microsystem Corp. */
if ((verstep & 0xF0) == 0x60)
lm85chipid = EMC6D10X;
else
goto ret0;
} else
goto ret0;
strcpy(buff, lm85chip[lm85chipid]);
return lm85chipid;
ret0:
return 0;
}
/*
* \retval 0xFFFF no sensor
* \retval other temperature
* no = 0,1,...
*/
static float lm85_temp( LM_METHODS *method, int no )
{
int n, ne;
float ext = 0.0;
if (no < 0 || 2 < no)
return 0xFFFF;
if (lm85chipid == ADM1024 || lm85chipid == ADM1025) {
if (no == 2)
return 0xFFFF;
else
no++;
} else if (lm85chipid >= ADM1027) {
ne = method->Read(ADM_EXTRES2);
ext = 0.25 * ((ne >> ((no + 1) * 2)) & 0x03);
/* Unlock temperature registers. */
if (no != 0) method->Read(LM85_TEMP(0));
if (no != 1) method->Read(LM85_TEMP(1));
if (no != 2) method->Read(LM85_TEMP(2));
/* Unlock voltage register. */
method->Read(LM85_VOLT(4));
}
n = method->Read(LM85_TEMP(no));
if (n == 0x80)
return 0xFFFF;
else if (n > 0x80)
return (float) (n - 0xFF) + ext;
else
return (float) n + ext;
}
/*
* \retval 0x0000FFFF no sensor
* no = 0,1,2,...
*/
static float Vtab[5] = {
2.5 * 4./3., /* 2.5V */
2.25 * 4./3., /* Vcore (2.25) */
3.3 * 4./3., /* 3.3V */
5.0 * 4./3., /* 5.0V */
12.0 * 4./3. /* 12.0V */
};
static float lm85_volt(LM_METHODS *method, int no)
{
int n, ne = 0;
if (no < 0 || 4 < no)
return 0xFFFF;
if (lm85chipid >= ADM1027) {
if (no == 4) {
ne = method->Read(ADM_EXTRES2) & 0x03;
/* Unlock temperature registers. */
method->Read(LM85_TEMP(0));
method->Read(LM85_TEMP(1));
method->Read(LM85_TEMP(2));
} else {
ne = (method->Read(ADM_EXTRES1) >> (no * 2)) & 0x03;
/* Unlock voltage registers. */
if (no != 0) method->Read(LM85_VOLT(0));
if (no != 1) method->Read(LM85_VOLT(1));
if (no != 2) method->Read(LM85_VOLT(2));
if (no != 3) method->Read(LM85_VOLT(3));
}
}
n = method->Read(LM85_VOLT(no));
if (lm85chipid >= ADM1027)
n = (n << 2) | ne;
return Vtab[no] * Vfac * (float) n;
}
/*
* \retval 0x0000FFFF no sensor
* no = 0,1,...
*
* Clock is 90kHz (90,000 x 60 = 5400000 counts/minute)
*/
static int lm85_fanrpm(LM_METHODS *method, int no)
{
int lsb, msb, r, n;
int p = 2; /* default number of pulse per revolution */
static int ppr[4] = {2,2,2,2}, div[2] = {1,1};
if (no < 0 || 3 < no || lm85chipid == ADM1025)
return 0xFFFF;
if (lm85chipid == ADM1024) {
if (no > 1 || adm_24fan[no])
return 0xFFFF;
n = method->Read(ADM_24FANDIV);
div[0] = (n >> 4) & 0x03;
div[1] = n >> 6;
r = method->Read(ADM_24FAN(no));
if (r == 0)
return 0xFFFF;
else if (r == 0xFF) {
/* change divisor for the sake of next call ! */
if (div[no] < 3)
++(div[no]);
else
div[no] = 0;
r = (n & 0x0F) | (div[0] << 4) | (div[1] << 6);
method->Write(ADM_24FANDIV, r);
return 0xFFFF;
} else
return 1350000 / (r * (1 << div[no]));
}
if (lm85chipid >= ADM1027)
p = ((method->Read(ADM_FANPPR) >> (no * 2)) & 0x03) + 1;
ppr[no] = p;
lsb = method->Read(LM85_FANLSB(no));
msb = method->Read(LM85_FANMSB(no));
if ((lsb == 0xFF && msb == 0xFF) || (lsb == 0 && msb == 0))
return 0xFFFF;
else
return 5400000 / (p * ((msb << 8) | lsb));
}
#if 0
static int lm85_fan_ppr(LM_METHODS *method, int no)
{
int p = 2;
if (lm85chipid >= ADM1027)
p = ((method->Read(ADM_FANPPR) >> (no * 2)) & 0x03) + 1;
return p;
}
static void lm85_fan_ppr_set(LM_METHODS *method, int no, int p)
{
int n;
if (lm85chipid >= ADM1027) {
n = method->Read(ADM_FANPPR);
n &= ((p - 1) & 0x03) << (no * 2);
method->Write(ADM_FANPPR, n);
}
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1