/*
* Winbond new chips
*
***************************************************************
* Before calling these routines, one must call method->Open() *
* After calling these routines, one must call method->Close() *
***************************************************************
*
* Winbond chip: W83L784R, W83L785R, W83L785TS-S
*
Winbond
Chip Temp Volt Fan SMBus IOport
W83L784R 3 4 2 yes no
W83L785R 2 4 2 yes no
W83L785TS-S 1 0 0 yes no
*
* by YRS
*/
/* To allow "unknown" (fuzzy probing), define this */
/* #define ALLOW_UNKNOWN */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "pci_pm.h"
#include "sensors.h"
#include "sens_wl784.h"
/* external (global) data */
extern int pm_smb_detected;
extern int smb_slave;
extern int smb_wbtemp1, smb_wbtemp2;
extern int smb_wbtemp1_flag, smb_wbtemp2_flag;
extern LM_METHODS method_isa, method_smb;
extern int numSMBSlave, canSMBSlave[128];
#define WINBD_ADDR_START 0x50 /* 0x50-0x5E (0x28-0x2F) */
#define WINBD_ADDR_END 0x5E
#define WINBD_CONFIG 0x40
#define WINBD_SMBADDR 0x4A
#define WINBD_VENDIDL 0x4C
#define WINBD_VENDIDH 0x4D
#define WINBD_CHIPID 0x4E
/* temp nr=0,1,2; volt nr=0,...3; fan nr=0,1 */
#define WINBD_TEMP0 0x27
#define WINBD_TEMP1 0x26
#define WINBD_TEMPADDR 0x4B
#define WINBD_VOLT(nr) (0x20 + (nr))
#define WINBD_FAN(nr) (0x28 + (nr))
#define WINBD_FANDIV 0x49
#define WINBD_DIOSEL 0x53
static int wl784_probe(LM_METHODS *);
static int wl784_probe_act(LM_METHODS *, int);
static float wl784_temp(LM_METHODS *, int);
static int wl784_fanrpm(LM_METHODS *, int);
static float wl784_volt(LM_METHODS *, int);
#define BUFF_LEN 128
static char buff[BUFF_LEN];
SENSOR wl784 = {
buff,
wl784_probe,
wl784_temp,
wl784_volt,
wl784_fanrpm
};
/* chip idenfication */
static int wbdchipid = 0;
/* temp1/2 flags address */
static int temp1_flag = 0; /* = 0 if enabled ! */
static int temp2_flag = 0; /* = 0 if enabled ! */
static int temp1_addr = 0;
static int temp2_addr = 0;
#define WINBD_chkRegNum 8
/* Register checked for probing */
static int chkReg[] = {
0x40, 0x41, 0x42, 0x43,
0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4A, 0x4B,
0x4C, 0x4D, 0x4E, 0x4F,
0x20, 0x21, 0x22, 0x23,
0x26, 0x27, 0x28, 0x29,
0x2B, 0x2C, 0x2D, 0x2E,
-1 };
/*
* return 0 if not probed
*/
static int wl784_probe(LM_METHODS *method)
{
int n, save, slave;
if (method != &method_smb)
return 0;
save = smb_slave;
for (n = WINBD_ADDR_START; n <= WINBD_ADDR_END;) {
if (!(slave = get_smb_slave(n, WINBD_ADDR_END)))
goto ret0;
else {
if (wl784_probe_act(method, slave))
goto ret1;
else
n = slave + 2;
}
}
ret0:
smb_slave = save;
return 0;
ret1:
kill_smb_slave(slave);
if(!smb_wbtemp1_flag)
kill_smb_slave(smb_wbtemp1);
if(!smb_wbtemp2_flag)
kill_smb_slave(smb_wbtemp2);
return wbdchipid;
}
static int wl784_probe_act(LM_METHODS *method, int slave)
{
int n, nc, nvl, nvh;
smb_slave = slave;
if (chkReg_Probe(slave, "Probing Winbond W83L78x chip:\n",
chkReg, method) < WINBD_chkRegNum)
goto ret0;
nvl = method->Read(WINBD_VENDIDL);
nvh = method->Read(WINBD_VENDIDH);
nc = method->Read(WINBD_CHIPID);
#ifdef DEBUG
printf("DEBUG 4C:0x%02X 4D:0x%02X 4E:0x%02X\n",nvl,nvh,nc);
#endif
if (nvl == 0xA3 && nvh == 0x5C) { /* Winbond Chip */
switch (nc & 0xFE) {
case 0x50: /* 0x50 (or 0x51) */
wbdchipid = W83L784R;
break;
case 0x60: /* 0x60 (or 0x61) */
wbdchipid = W83L785R;
break;
case 0x70: /* 0x70 (or 0x71) */
wbdchipid = W83L785TS;
break;
default:
goto ret0;
}
} else
goto ret0;
strcpy(wl784.Name, wlchip[wbdchipid]);
/* Checking Extra temperatures Temp1, Temp2 */
if (wbdchipid != W83L784R)
goto ret1;
n = method->Read(WINBD_TEMPADDR);
if (!(temp1_flag = (n & 0x08) >> 3)) {
temp1_addr = smb_wbtemp1;
smb_wbtemp1 = 2 * ( 0x48 + (n & 0x07) );
if (method->ReadTemp1() == 0xFFFF) {
temp1_flag = 1; /* disable! */
smb_wbtemp1 = temp1_addr;
}
}
if (!(temp2_flag = (n & 0x80) >> 7)) {
temp2_addr = smb_wbtemp2;
smb_wbtemp2 = 2 * ( 0x48 + ((n & 0x70) >> 4) );
if (method->ReadTemp2() == 0xFFFF) {
temp2_flag = 1; /* disable! */
smb_wbtemp2 = temp2_addr;
}
}
info_Extemp(method, temp1_flag, temp2_flag);
ret1:
smb_wbtemp1_flag = temp1_flag;
smb_wbtemp2_flag = temp2_flag;
return wbdchipid;
ret0:
return 0;
}
/*
* \retval 0xFFFF no sensor
* \retval other temperature
* no = 0,1,2
*/
static float wl784_temp(LM_METHODS *method, int no)
{
int n = 0;
float f;
if (no < 0 || 2 < no)
return 0xFFFF;
if (no == 2 && wbdchipid == W83L785R)
return 0xFFFF;
if (no >= 1 && wbdchipid == W83L785TS)
return 0xFFFF;
if (no == 0)
return (float) method->Read(WINBD_TEMP0);
else if (no == 1) {
if (wbdchipid == W83L785R)
return (float) method->Read(WINBD_TEMP1);
else
n = method->ReadTemp1();
} else if (no == 2) {
n = method->ReadTemp2();
}
if ((n & 0xFF) >= 0x80)
n = 0;
f = (float) (n & 0xFF) + 0.5 * ((n & 0xFF00) >> 15);
return f;
}
/*
* \retval 0x0000FFFF no sensor
* no = 0,1,2,...,6
*/
static float wl784_volt(LM_METHODS *method, int no)
{
int n;
float f = 0.0;
if (wbdchipid == W83L785TS)
return 0xFFFF;
if (no < 0 || 3 < no)
return 0xFFFF;
n = method->Read(WINBD_VOLT(no));
switch (no) {
case 0:
f = n * 0.016;
case 1:
if (wbdchipid == W83L784R)
f = n * 0.016 * 3.3434;
else
f = n * 0.016 * 2;
case 2:
f = n * 0.016;
break;
case 3:
if (wbdchipid == W83L784R)
f = n * 0.016 * 1.68;
else
f = n * 0.016 * 3;
break;
}
return f;
}
/*
Controlling Fan Divisor: CR = 0x49.
lowest 3bits for fan1, 4-6th bits for fan2.
7 3 0
+-+-+-+-+-+-+-+-+ xxx = 000,001,010,011,... div1fac = 1,2,4,8,...
| y y y| x x x| yyy = 000,001,010,011,... div2fac = 1,2,4,8,...
+-+-+-+-+-+-+-+-+ initial values: xx=001, yy=001
*/
/*
* \retval 0xFFFF no sensor
* no = 0,1
*
* Clock is 22.5kHz (22,500 x 60 = 1350000 counts/minute)
*/
static int wl784_fanrpm(LM_METHODS *method, int no)
{
int r, n1 = 0x11;
static int div[2] = {1,1};
if (wbdchipid == W83L785TS)
return 0xFFFF;
if (no < 0 || 1 < no)
return 0xFFFF;
n1 = method->Read(WINBD_FANDIV);
div[0] = n1 & 0x07 ;
div[1] = (n1 >> 4) & 0x07;
r = method->Read(WINBD_FAN(no));
if (r == 0xFF) {
/* change divisor for the sake of next call ! */
if (div[no] < 7)
++(div[no]);
else
div[no] = 0;
r = (n1 & 0x88) | div[0] | (div[1] << 4);
method->Write(WINBD_FANDIV, r);
return 0xFFFF;
} else if (r == 0) {
return 0xFFFF;
}
return 1350000 / (r * (1 << div[no]));
}
syntax highlighted by Code2HTML, v. 0.9.1