1 /******************************************************************************
2  *
3  * Name:	sklm80.c
4  * Project:	Gigabit Ethernet Adapters, TWSI-Module
5  * Purpose:	Functions to access Voltage and Temperature Sensor (LM80)
6  *
7  ******************************************************************************/
8 
9 /******************************************************************************
10  *
11  *	(C)Copyright 1998-2002 SysKonnect.
12  *	(C)Copyright 2002-2003 Marvell.
13  *
14  *	This program is free software; you can redistribute it and/or modify
15  *	it under the terms of the GNU General Public License as published by
16  *	the Free Software Foundation; either version 2 of the License, or
17  *	(at your option) any later version.
18  *
19  *	The information in this file is provided "AS IS" without warranty.
20  *
21  ******************************************************************************/
22 
23 /*
24 	LM80 functions
25 */
26 #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
27 static const char SysKonnectFileId[] =
28 	"@(#) $Id: sklm80.c,v 1.22 2003/10/20 09:08:21 rschmidt Exp $ (C) Marvell. ";
29 #endif
30 
31 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
32 #include "h/lm80.h"
33 #include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
34 
35 #ifdef	SK_DIAG
36 #define	BREAK_OR_WAIT(pAC,IoC,Event)	SkI2cWait(pAC,IoC,Event)
37 #else	/* nSK_DIAG */
38 #define	BREAK_OR_WAIT(pAC,IoC,Event)	break
39 #endif	/* nSK_DIAG */
40 
41 #ifdef	SK_DIAG
42 /*
43  * read the register 'Reg' from the device 'Dev'
44  *
45  * return 	read error	-1
46  *		success		the read value
47  */
SkLm80RcvReg(SK_IOC IoC,int Dev,int Reg)48 int	SkLm80RcvReg(
49 SK_IOC	IoC,		/* Adapter Context */
50 int		Dev,		/* I2C device address */
51 int		Reg)		/* register to read */
52 {
53 	int	Val = 0;
54 	int	TempExt;
55 
56 	/* Signal device number */
57 	if (SkI2cSndDev(IoC, Dev, I2C_WRITE)) {
58 		return(-1);
59 	}
60 
61 	if (SkI2cSndByte(IoC, Reg)) {
62 		return(-1);
63 	}
64 
65 	/* repeat start */
66 	if (SkI2cSndDev(IoC, Dev, I2C_READ)) {
67 		return(-1);
68 	}
69 
70 	switch (Reg) {
71 	case LM80_TEMP_IN:
72 		Val = (int)SkI2cRcvByte(IoC, 1);
73 
74 		/* First: correct the value: it might be negative */
75 		if ((Val & 0x80) != 0) {
76 			/* Value is negative */
77 			Val = Val - 256;
78 		}
79 		Val = Val * SK_LM80_TEMP_LSB;
80 		SkI2cStop(IoC);
81 
82 		TempExt = (int)SkLm80RcvReg(IoC, LM80_ADDR, LM80_TEMP_CTRL);
83 
84 		if (Val > 0) {
85 			Val += ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB);
86 		}
87 		else {
88 			Val -= ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB);
89 		}
90 		return(Val);
91 		break;
92 	case LM80_VT0_IN:
93 	case LM80_VT1_IN:
94 	case LM80_VT2_IN:
95 	case LM80_VT3_IN:
96 		Val = (int)SkI2cRcvByte(IoC, 1) * SK_LM80_VT_LSB;
97 		break;
98 
99 	default:
100 		Val = (int)SkI2cRcvByte(IoC, 1);
101 		break;
102 	}
103 
104 	SkI2cStop(IoC);
105 	return(Val);
106 }
107 #endif	/* SK_DIAG */
108 
109 /*
110  * read a sensors value (LM80 specific)
111  *
112  * This function reads a sensors value from the I2C sensor chip LM80.
113  * The sensor is defined by its index into the sensors database in the struct
114  * pAC points to.
115  *
116  * Returns	1 if the read is completed
117  *		0 if the read must be continued (I2C Bus still allocated)
118  */
SkLm80ReadSensor(SK_AC * pAC,SK_IOC IoC,SK_SENSOR * pSen)119 int SkLm80ReadSensor(
120 SK_AC		*pAC,	/* Adapter Context */
121 SK_IOC		IoC,	/* I/O Context needed in level 1 and 2 */
122 SK_SENSOR	*pSen)	/* Sensor to be read */
123 {
124 	SK_I32		Value;
125 
126 	switch (pSen->SenState) {
127 	case SK_SEN_IDLE:
128 		/* Send address to ADDR register */
129 		SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, pSen->SenReg, 0);
130 
131 		pSen->SenState = SK_SEN_VALUE ;
132 		BREAK_OR_WAIT(pAC, IoC, I2C_READ);
133 
134 	case SK_SEN_VALUE:
135 		/* Read value from data register */
136 		SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
137 
138 		Value &= 0xff; /* only least significant byte is valid */
139 
140 		/* Do NOT check the Value against the thresholds */
141 		/* Checking is done in the calling instance */
142 
143 		if (pSen->SenType == SK_SEN_VOLT) {
144 			/* Voltage sensor */
145 			pSen->SenValue = Value * SK_LM80_VT_LSB;
146 			pSen->SenState = SK_SEN_IDLE ;
147 			return(1);
148 		}
149 
150 		if (pSen->SenType == SK_SEN_FAN) {
151 			if (Value != 0 && Value != 0xff) {
152 				/* Fan speed counter */
153 				pSen->SenValue = SK_LM80_FAN_FAKTOR/Value;
154 			}
155 			else {
156 				/* Indicate Fan error */
157 				pSen->SenValue = 0;
158 			}
159 			pSen->SenState = SK_SEN_IDLE ;
160 			return(1);
161 		}
162 
163 		/* First: correct the value: it might be negative */
164 		if ((Value & 0x80) != 0) {
165 			/* Value is negative */
166 			Value = Value - 256;
167 		}
168 
169 		/* We have a temperature sensor and need to get the signed extension.
170 		 * For now we get the extension from the last reading, so in the normal
171 		 * case we won't see flickering temperatures.
172 		 */
173 		pSen->SenValue = (Value * SK_LM80_TEMP_LSB) +
174 			(pSen->SenValue % SK_LM80_TEMP_LSB);
175 
176 		/* Send address to ADDR register */
177 		SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, LM80_TEMP_CTRL, 0);
178 
179 		pSen->SenState = SK_SEN_VALEXT ;
180 		BREAK_OR_WAIT(pAC, IoC, I2C_READ);
181 
182 	case SK_SEN_VALEXT:
183 		/* Read value from data register */
184 		SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
185 		Value &= LM80_TEMP_LSB_9; /* only bit 7 is valid */
186 
187 		/* cut the LSB bit */
188 		pSen->SenValue = ((pSen->SenValue / SK_LM80_TEMP_LSB) *
189 			SK_LM80_TEMP_LSB);
190 
191 		if (pSen->SenValue < 0) {
192 			/* Value negative: The bit value must be subtracted */
193 			pSen->SenValue -= ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
194 		}
195 		else {
196 			/* Value positive: The bit value must be added */
197 			pSen->SenValue += ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
198 		}
199 
200 		pSen->SenState = SK_SEN_IDLE ;
201 		return(1);
202 
203 	default:
204 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E007, SKERR_I2C_E007MSG);
205 		return(1);
206 	}
207 
208 	/* Not completed */
209 	return(0);
210 }
211 
212