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