diff options
Diffstat (limited to 'drivers/net/sk98lin/ski2c.c')
| -rw-r--r-- | drivers/net/sk98lin/ski2c.c | 1505 | 
1 files changed, 1505 insertions, 0 deletions
| diff --git a/drivers/net/sk98lin/ski2c.c b/drivers/net/sk98lin/ski2c.c new file mode 100644 index 000000000..2ab635a22 --- /dev/null +++ b/drivers/net/sk98lin/ski2c.c @@ -0,0 +1,1505 @@ +/****************************************************************************** + * + * Name:	ski2c.c + * Project:	GEnesis, PCI Gigabit Ethernet Adapter + * Version:	$Revision: 1.57 $ + * Date:	$Date: 2003/01/28 09:17:38 $ + * Purpose:	Functions to access Voltage and Temperature Sensor + * + ******************************************************************************/ + +/****************************************************************************** + * + *	(C)Copyright 1998-2003 SysKonnect GmbH. + * + *	This program is free software; you can redistribute it and/or modify + *	it under the terms of the GNU General Public License as published by + *	the Free Software Foundation; either version 2 of the License, or + *	(at your option) any later version. + * + *	The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * + *	$Log: ski2c.c,v $ + *	Revision 1.57  2003/01/28 09:17:38  rschmidt + *	Fixed handling for sensors on YUKON Fiber. + *	Editorial changes. + * + *	Revision 1.56  2002/12/19 14:20:41  rschmidt + *	Added debugging code in SkI2cWait(). + *	Replaced all I2C-write operations with function SkI2cWrite(). + *	Fixed compiler warning because of uninitialized 'Time' in SkI2cEvent(). + *	Editorial changes. + * + *	Revision 1.55  2002/10/15 07:23:55  rschmidt + *	Added setting of the GIYukon32Bit bool variable to distinguish + *	32-bit adapters. + *	Editorial changes (TWSI). + * + *	Revision 1.54  2002/08/13 09:05:06  rschmidt + *	Added new thresholds if VAUX is not available (GIVauxAvail). + *	Merged defines for PHY PLL 3V3 voltage (A and B). + *	Editorial changes. + * + *	Revision 1.53  2002/08/08 11:04:53  rwahl + *	Added missing comment for revision 1.51 + * + *	Revision 1.52  2002/08/08 10:09:02  jschmalz + *	Sensor init state caused wrong error log entry + * + *	Revision 1.51  2002/08/06 09:43:03  jschmalz + *	Extensions and changes for Yukon + * + *	Revision 1.50  2002/08/02 12:09:22  rschmidt + *	Added support for YUKON sensors. + *	Editorial changes. + * + *	Revision 1.49  2002/07/30 11:07:52  rschmidt + *	Replaced MaxSens init by update for Copper in SkI2cInit1(), + *	because it was already initialized in SkI2cInit0(). + *	Editorial changes. + * + *	Revision 1.48  2001/08/16 12:44:33  afischer + *	LM80 sensor init values corrected + * + *	Revision 1.47  2001/04/05 11:38:09  rassmann + *	Set SenState to idle in SkI2cWaitIrq(). + *	Changed error message in SkI2cWaitIrq(). + * + *	Revision 1.46  2001/04/02 14:03:35  rassmann + *	Changed pAC to IoC in SK_IN32(). + * + *	Revision 1.45  2001/03/21 12:12:49  rassmann + *	Resetting I2C_READY interrupt in SkI2cInit1(). + * + *	Revision 1.44  2000/08/07 15:49:03  gklug + *	Fix: SK_INFAST only in NetWare driver. + * + *	Revision 1.43  2000/08/03 14:28:17  rassmann + *	Added function to wait for I2C being ready before resetting the board. + *	Replaced one duplicate "out of range" message with correct one. + * + *	Revision 1.42  1999/11/22 13:35:12  cgoos + *	Changed license header to GPL. + * + *	Revision 1.41  1999/09/14 14:11:30  malthoff + *	The 1000BT Dual Link adapter has got only one Fan. + *	The second Fan has been removed. + * + *	Revision 1.40  1999/05/27 13:37:27  malthoff + *	Set divisor of 1 for fan count calculation. + * + *	Revision 1.39  1999/05/20 14:54:43  malthoff + *	I2c.DummyReads is not used in Diagnostics. + * + *	Revision 1.38  1999/05/20 09:20:56  cgoos + *	Changes for 1000Base-T (up to 9 sensors and fans). + * + *	Revision 1.37  1999/03/25 15:11:36  gklug + *	fix: reset error flag if sensor reads correct value + * + *	Revision 1.36  1999/01/07 14:11:16  gklug + *	fix: break added + * + *	Revision 1.35  1999/01/05 15:31:49  gklug + *	fix: CLEAR STAT command is now added correctly + * + *	Revision 1.34  1998/12/01 13:45:16  gklug + *	fix: introduced Init level, because we don't need reinits + * + *	Revision 1.33  1998/11/09 14:54:25  malthoff + *	Modify I2C Transfer Timeout handling for Diagnostics. + * + *	Revision 1.32  1998/11/03 06:54:35  gklug + *	fix: Need dummy reads at the beginning to init sensors + * + *	Revision 1.31  1998/11/03 06:42:42  gklug + *	fix: select correctVIO range only if between warning levels + * + *	Revision 1.30  1998/11/02 07:36:53  gklug + *	fix: Error should not include WARNING message + * + *	Revision 1.29  1998/10/30 15:07:43  malthoff + *	Disable 'I2C does not compelete' error log for diagnostics. + * + *	Revision 1.28  1998/10/22 09:48:11  gklug + *	fix: SysKonnectFileId typo + * + *	Revision 1.27  1998/10/20 09:59:46  gklug + *	add: parameter to SkOsGetTime + * + *	Revision 1.26  1998/10/09 06:10:59  malthoff + *	Remove ID_sccs by SysKonnectFileId. + * + *	Revision 1.25  1998/09/08 12:40:26  gklug + *	fix: syntax error in if clause + * + *	Revision 1.24  1998/09/08 12:19:42  gklug + *	chg: INIT Level checking + * + *	Revision 1.23  1998/09/08 07:37:20  gklug + *	fix: log error if PCI_IO voltage sensor could not be initialized + * + *	Revision 1.22  1998/09/04 08:30:03  malthoff + *	Bugfixes during SK_DIAG testing: + *	- correct NS2BCLK() macro + *	- correct SkI2cSndDev() + *	- correct SkI2cWait() loop waiting for an event + * + *	Revision 1.21  1998/08/27 14:46:01  gklug + *	chg: if-then-else replaced by switch + * + *	Revision 1.20  1998/08/27 14:40:07  gklug + *	test: integral types + * + *	Revision 1.19  1998/08/25 07:51:54  gklug + *	fix: typos for compiling + * + *	Revision 1.18  1998/08/25 06:12:24  gklug + *	add: count errors and warnings + *	fix: check not the sensor state but the ErrFlag! + * + *	Revision 1.17  1998/08/25 05:56:48  gklug + *	add: CheckSensor function + * + *	Revision 1.16  1998/08/20 11:41:10  gklug + *	chg: omit STRCPY macro by using char * as Sensor Description + * + *	Revision 1.15  1998/08/20 11:37:35  gklug + *	chg: change Ioc to IoC + * + *	Revision 1.14  1998/08/20 11:32:52  gklug + *	fix: Para compile error + * + *	Revision 1.13  1998/08/20 11:27:41  gklug + *	fix: Compile bugs with new awrning constants + * + *	Revision 1.12  1998/08/20 08:53:05  gklug + *	fix: compiler errors + *	add: Threshold values + * + *	Revision 1.11  1998/08/19 12:39:22  malthoff + *	Compiler Fix: Some names have changed. + * + *	Revision 1.10  1998/08/19 12:20:56  gklug + *	fix: remove struct from C files (see CCC) + * + *	Revision 1.9  1998/08/19 06:28:46  malthoff + *	SkOsGetTime returns SK_U64 now. + * + *	Revision 1.8  1998/08/17 13:53:33  gklug + *	fix: Parameter of event function and its result + * + *	Revision 1.7  1998/08/17 07:02:15  malthoff + *	Modify the functions for accessing the I2C SW Registers. + *	Modify SkI2cWait(). + *	Put Lm80RcvReg into sklm80.c + *	Remove Compiler Errors. + * + *	Revision 1.6  1998/08/14 07:13:20  malthoff + *	remove pAc with pAC + *	remove smc with pAC + *	change names to new convention + * + *	Revision 1.5  1998/08/14 06:24:49  gklug + *	add: init level 1 and 2 + * + *	Revision 1.4  1998/08/12 14:31:12  gklug + *	add: error log for unknown event + * + *	Revision 1.3  1998/08/12 13:37:04  gklug + *	add: Init 0 function + * + *	Revision 1.2  1998/08/11 07:27:15  gklug + *	add: functions of the interface + *	adapt rest of source to C coding Conventions + *	rmv: unnecessary code taken from Mona Lisa + * + *	Revision 1.1  1998/06/19 14:28:43  malthoff + *	Created. Sources taken from ML Projekt. + *	Sources have to be reworked for GE. + * + * + ******************************************************************************/ + + +#include <config.h> + +#ifdef CONFIG_SK98 + +/* + *	I2C Protocol + */ +static const char SysKonnectFileId[] = +	"$Id: ski2c.c,v 1.57 2003/01/28 09:17:38 rschmidt Exp $"; + +#include "h/skdrv1st.h"		/* Driver Specific Definitions */ +#include "h/lm80.h" +#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */ + +#ifdef __C2MAN__ +/* +	I2C protocol implementation. + +	General Description: + +	The I2C protocol is used for the temperature sensors and for +	the serial EEPROM which hold the configuration. + +	This file covers functions that allow to read write and do +	some bulk requests a specified I2C address. + +	The Genesis has 2 I2C buses. One for the EEPROM which holds +	the VPD Data and one for temperature and voltage sensor. +	The following picture shows the I2C buses, I2C devices and +	their control registers. + +	Note: The VPD functions are in skvpd.c +. +.	PCI Config I2C Bus for VPD Data: +. +.		      +------------+ +.		      | VPD EEPROM | +.		      +------------+ +.			     | +.			     | <-- I2C +.			     | +.		 +-----------+-----------+ +.		 |			 | +.	+-----------------+	+-----------------+ +.	| PCI_VPD_ADR_REG |	| PCI_VPD_DAT_REG | +.	+-----------------+	+-----------------+ +. +. +.	I2C Bus for LM80 sensor: +. +.			+-----------------+ +.			| Temperature and | +.			| Voltage Sensor  | +.			| 	LM80	  | +.			+-----------------+ +.				| +.				| +.			I2C --> | +.				| +.			     +----+ +.	     +-------------->| OR |<--+ +.	     |		     +----+   | +.     +------+------+		      | +.     |		    |		      | +. +--------+	+--------+	+----------+ +. | B2_I2C |	| B2_I2C |	|  B2_I2C  | +. | _CTRL  |	| _DATA  |	|   _SW    | +. +--------+	+--------+	+----------+ +. +	The I2C bus may be driven by the B2_I2C_SW or by the B2_I2C_CTRL +	and B2_I2C_DATA registers. +	For driver software it is recommended to use the I2C control and +	data register, because I2C bus timing is done by the ASIC and +	an interrupt may be received when the I2C request is completed. + +	Clock Rate Timing:			MIN	MAX	generated by +		VPD EEPROM:			50 kHz	100 kHz		HW +		LM80 over I2C Ctrl/Data reg.	50 kHz	100 kHz		HW +		LM80 over B2_I2C_SW register	0	400 kHz		SW + +	Note:	The clock generated by the hardware is dependend on the +		PCI clock. If the PCI bus clock is 33 MHz, the I2C/VPD +		clock is 50 kHz. + */ +intro() +{} +#endif + +#ifdef	SK_DIAG +/* + * I2C Fast Mode timing values used by the LM80. + * If new devices are added to the I2C bus the timing values have to be checked. + */ +#ifndef I2C_SLOW_TIMING +#define	T_CLK_LOW			1300L	/* clock low time in ns */ +#define	T_CLK_HIGH		 	 600L	/* clock high time in ns */ +#define T_DATA_IN_SETUP		 100L	/* data in Set-up Time */ +#define T_START_HOLD		 600L	/* start condition hold time */ +#define T_START_SETUP		 600L	/* start condition Set-up time */ +#define	T_STOP_SETUP		 600L	/* stop condition Set-up time */ +#define T_BUS_IDLE			1300L	/* time the bus must free after Tx */ +#define	T_CLK_2_DATA_OUT	 900L	/* max. clock low to data output valid */ +#else	/* I2C_SLOW_TIMING */ +/* I2C Standard Mode Timing */ +#define	T_CLK_LOW			4700L	/* clock low time in ns */ +#define	T_CLK_HIGH			4000L	/* clock high time in ns */ +#define T_DATA_IN_SETUP		 250L	/* data in Set-up Time */ +#define T_START_HOLD		4000L	/* start condition hold time */ +#define T_START_SETUP		4700L	/* start condition Set-up time */ +#define	T_STOP_SETUP		4000L	/* stop condition Set-up time */ +#define T_BUS_IDLE			4700L	/* time the bus must free after Tx */ +#endif	/* !I2C_SLOW_TIMING */ + +#define NS2BCLK(x)	(((x)*125)/10000) + +/* + * I2C Wire Operations + * + * About I2C_CLK_LOW(): + * + * The Data Direction bit (I2C_DATA_DIR) has to be set to input when setting + * clock to low, to prevent the ASIC and the I2C data client from driving the + * serial data line simultaneously (ASIC: last bit of a byte = '1', I2C client + * send an 'ACK'). See also Concentrator Bugreport No. 10192. + */ +#define I2C_DATA_HIGH(IoC)	SK_I2C_SET_BIT(IoC, I2C_DATA) +#define	I2C_DATA_LOW(IoC)	SK_I2C_CLR_BIT(IoC, I2C_DATA) +#define	I2C_DATA_OUT(IoC)	SK_I2C_SET_BIT(IoC, I2C_DATA_DIR) +#define	I2C_DATA_IN(IoC)	SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA) +#define	I2C_CLK_HIGH(IoC)	SK_I2C_SET_BIT(IoC, I2C_CLK) +#define	I2C_CLK_LOW(IoC)	SK_I2C_CLR_BIT(IoC, I2C_CLK | I2C_DATA_DIR) +#define	I2C_START_COND(IoC)	SK_I2C_CLR_BIT(IoC, I2C_CLK) + +#define NS2CLKT(x)	((x*125L)/10000) + +/*--------------- I2C Interface Register Functions --------------- */ + +/* + * sending one bit + */ +void SkI2cSndBit( +SK_IOC	IoC,	/* I/O Context */ +SK_U8	Bit)	/* Bit to send */ +{ +	I2C_DATA_OUT(IoC); +	if (Bit) { +		I2C_DATA_HIGH(IoC); +	} +	else { +		I2C_DATA_LOW(IoC); +	} +	SkDgWaitTime(IoC, NS2BCLK(T_DATA_IN_SETUP)); +	I2C_CLK_HIGH(IoC); +	SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH)); +	I2C_CLK_LOW(IoC); +}	/* SkI2cSndBit*/ + + +/* + * Signal a start to the I2C Bus. + * + * A start is signaled when data goes to low in a high clock cycle. + * + * Ends with Clock Low. + * + * Status: not tested + */ +void SkI2cStart( +SK_IOC	IoC)	/* I/O Context */ +{ +	/* Init data and Clock to output lines */ +	/* Set Data high */ +	I2C_DATA_OUT(IoC); +	I2C_DATA_HIGH(IoC); +	/* Set Clock high */ +	I2C_CLK_HIGH(IoC); + +	SkDgWaitTime(IoC, NS2BCLK(T_START_SETUP)); + +	/* Set Data Low */ +	I2C_DATA_LOW(IoC); + +	SkDgWaitTime(IoC, NS2BCLK(T_START_HOLD)); + +	/* Clock low without Data to Input */ +	I2C_START_COND(IoC); + +	SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW)); +}	/* SkI2cStart */ + + +void SkI2cStop( +SK_IOC	IoC)	/* I/O Context */ +{ +	/* Init data and Clock to output lines */ +	/* Set Data low */ +	I2C_DATA_OUT(IoC); +	I2C_DATA_LOW(IoC); + +	SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT)); + +	/* Set Clock high */ +	I2C_CLK_HIGH(IoC); + +	SkDgWaitTime(IoC, NS2BCLK(T_STOP_SETUP)); + +	/* +	 * Set Data High:	Do it by setting the Data Line to Input. +	 *			Because of a pull up resistor the Data Line +	 *			floods to high. +	 */ +	I2C_DATA_IN(IoC); + +	/* +	 *	When I2C activity is stopped +	 *	 o	DATA should be set to input and +	 *	 o	CLOCK should be set to high! +	 */ +	SkDgWaitTime(IoC, NS2BCLK(T_BUS_IDLE)); +}	/* SkI2cStop */ + + +/* + * Receive just one bit via the I2C bus. + * + * Note:	Clock must be set to LOW before calling this function. + * + * Returns The received bit. + */ +int SkI2cRcvBit( +SK_IOC	IoC)	/* I/O Context */ +{ +	int	Bit; +	SK_U8	I2cSwCtrl; + +	/* Init data as input line */ +	I2C_DATA_IN(IoC); + +	SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT)); + +	I2C_CLK_HIGH(IoC); + +	SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH)); + +	SK_I2C_GET_SW(IoC, &I2cSwCtrl); + +	Bit = (I2cSwCtrl & I2C_DATA) ? 1 : 0; + +	I2C_CLK_LOW(IoC); +	SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT)); + +	return(Bit); +}	/* SkI2cRcvBit */ + + +/* + * Receive an ACK. + * + * returns	0 If acknowledged + *		1 in case of an error + */ +int SkI2cRcvAck( +SK_IOC	IoC)	/* I/O Context */ +{ +	/* +	 * Received bit must be zero. +	 */ +	return(SkI2cRcvBit(IoC) != 0); +}	/* SkI2cRcvAck */ + + +/* + * Send an NACK. + */ +void SkI2cSndNAck( +SK_IOC	IoC)	/* I/O Context */ +{ +	/* +	 * Received bit must be zero. +	 */ +	SkI2cSndBit(IoC, 1); +}	/* SkI2cSndNAck */ + + +/* + * Send an ACK. + */ +void SkI2cSndAck( +SK_IOC IoC)	/* I/O Context */ +{ +	/* +	 * Received bit must be zero. +	 * +	 */ +	SkI2cSndBit(IoC, 0); +}	/* SkI2cSndAck */ + + +/* + * Send one byte to the I2C device and wait for ACK. + * + * Return acknowleged status. + */ +int SkI2cSndByte( +SK_IOC	IoC,	/* I/O Context */ +int		Byte)	/* byte to send */ +{ +	int	i; + +	for (i = 0; i < 8; i++) { +		if (Byte & (1<<(7-i))) { +			SkI2cSndBit(IoC, 1); +		} +		else { +			SkI2cSndBit(IoC, 0); +		} +	} + +	return(SkI2cRcvAck(IoC)); +}	/* SkI2cSndByte */ + + +/* + * Receive one byte and ack it. + * + * Return byte. + */ +int SkI2cRcvByte( +SK_IOC	IoC,	/* I/O Context */ +int		Last)	/* Last Byte Flag */ +{ +	int	i; +	int	Byte = 0; + +	for (i = 0; i < 8; i++) { +		Byte <<= 1; +		Byte |= SkI2cRcvBit(IoC); +	} + +	if (Last) { +		SkI2cSndNAck(IoC); +	} +	else { +		SkI2cSndAck(IoC); +	} + +	return(Byte); +}	/* SkI2cRcvByte */ + + +/* + * Start dialog and send device address + * + * Return 0 if acknowleged, 1 in case of an error + */ +int	SkI2cSndDev( +SK_IOC	IoC,	/* I/O Context */ +int		Addr,	/* Device Address */ +int		Rw)		/* Read / Write Flag */ +{ +	SkI2cStart(IoC); +	Rw = ~Rw; +	Rw &= I2C_WRITE; +	return(SkI2cSndByte(IoC, (Addr<<1) | Rw)); +}	/* SkI2cSndDev */ + +#endif	/* SK_DIAG */ + +/*----------------- I2C CTRL Register Functions ----------*/ + +/* + * waits for a completion of an I2C transfer + * + * returns	0:	success, transfer completes + *			1:	error,	 transfer does not complete, I2C transfer + *						 killed, wait loop terminated. + */ +int	SkI2cWait( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC,	/* I/O Context */ +int		Event)	/* complete event to wait for (I2C_READ or I2C_WRITE) */ +{ +	SK_U64	StartTime; +	SK_U64	CurrentTime; +	SK_U32	I2cCtrl; + +	StartTime = SkOsGetTime(pAC); + +	do { +		CurrentTime = SkOsGetTime(pAC); + +		if (CurrentTime - StartTime > SK_TICKS_PER_SEC / 8) { + +			SK_I2C_STOP(IoC); +#ifndef SK_DIAG +			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG); +#endif	/* !SK_DIAG */ +			return(1); +		} + +		SK_I2C_GET_CTL(IoC, &I2cCtrl); + +#ifdef xYUKON_DBG +		printf("StartTime=%lu, CurrentTime=%lu\n", +			StartTime, CurrentTime); +		if (kbhit()) { +			return(1); +		} +#endif /* YUKON_DBG */ + +	} while ((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31); + +	return(0); +}	/* SkI2cWait */ + + +/* + * waits for a completion of an I2C transfer + * + * Returns + *	Nothing + */ +void SkI2cWaitIrq( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC)	/* I/O Context */ +{ +	SK_SENSOR	*pSen; +	SK_U64		StartTime; +	SK_U32		IrqSrc; + +	pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; + +	if (pSen->SenState == SK_SEN_IDLE) { +		return; +	} + +	StartTime = SkOsGetTime(pAC); +	do { +		if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) { +			SK_I2C_STOP(IoC); +#ifndef SK_DIAG +			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG); +#endif	/* !SK_DIAG */ +			return; +		} +		SK_IN32(IoC, B0_ISRC, &IrqSrc); +	} while ((IrqSrc & IS_I2C_READY) == 0); + +	pSen->SenState = SK_SEN_IDLE; +	return; +}	/* SkI2cWaitIrq */ + +/* + * writes a single byte or 4 bytes into the I2C device + * + * returns	0:	success + *			1:	error + */ +int SkI2cWrite( +SK_AC	*pAC,		/* Adapter Context */ +SK_IOC	IoC,		/* I/O Context */ +SK_U32	I2cData,	/* I2C Data to write */ +int		I2cDev,		/* I2C Device Address */ +int		I2cReg,		/* I2C Device Register Address */ +int		I2cBurst)	/* I2C Burst Flag */ +{ +	SK_OUT32(IoC, B2_I2C_DATA, I2cData); +	SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cReg, I2cBurst); + +	return(SkI2cWait(pAC, IoC, I2C_WRITE)); +}	/* SkI2cWrite*/ + + +#ifdef	SK_DIAG + +/* + * reads a single byte or 4 bytes from the I2C device + * + * returns	the word read + */ +SK_U32 SkI2cRead( +SK_AC	*pAC,		/* Adapter Context */ +SK_IOC	IoC,		/* I/O Context */ +int		I2cDev,		/* I2C Device Address */ +int		I2cReg,		/* I2C Device Register Address */ +int		I2cBurst)	/* I2C Burst Flag */ +{ +	SK_U32	Data; + +	SK_OUT32(IoC, B2_I2C_DATA, 0); +	SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cReg, I2cBurst); + +	if (SkI2cWait(pAC, IoC, I2C_READ) != 0) { +		w_print("%s\n", SKERR_I2C_E002MSG); +	} + +	SK_IN32(IoC, B2_I2C_DATA, &Data); +	return(Data); +}	/* SkI2cRead */ + +#endif	/* SK_DIAG */ + + +/* + * read a sensor's value + * + * This function reads a sensor's value from the I2C sensor chip. The sensor + * is defined by its index into the sensors database in the struct pAC points + * to. + * Returns + *		1 if the read is completed + *		0 if the read must be continued (I2C Bus still allocated) + */ +int	SkI2cReadSensor( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_SENSOR	*pSen)	/* Sensor to be read */ +{ +    if (pSen->SenRead != NULL) { +	return((*pSen->SenRead)(pAC, IoC, pSen)); +    } +    else +	return(0); /* no success */ +}	/* SkI2cReadSensor*/ + +/* + * Do the Init state 0 initialization + */ +static int SkI2cInit0( +SK_AC	*pAC)	/* Adapter Context */ +{ +	int	i; + +	/* Begin with first sensor */ +	pAC->I2c.CurrSens = 0; + +	/* Begin with timeout control for state machine */ +	pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE; + +	/* Set sensor number to zero */ +	pAC->I2c.MaxSens = 0; + +#ifndef	SK_DIAG +	/* Initialize Number of Dummy Reads */ +	pAC->I2c.DummyReads = SK_MAX_SENSORS; +#endif + +	for (i = 0; i < SK_MAX_SENSORS; i++) { +		pAC->I2c.SenTable[i].SenDesc = "unknown"; +		pAC->I2c.SenTable[i].SenType = SK_SEN_UNKNOWN; +		pAC->I2c.SenTable[i].SenThreErrHigh = 0; +		pAC->I2c.SenTable[i].SenThreErrLow = 0; +		pAC->I2c.SenTable[i].SenThreWarnHigh = 0; +		pAC->I2c.SenTable[i].SenThreWarnLow = 0; +		pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN; +		pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_NONE; +		pAC->I2c.SenTable[i].SenValue = 0; +		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_NOT_PRESENT; +		pAC->I2c.SenTable[i].SenErrCts = 0; +		pAC->I2c.SenTable[i].SenBegErrTS = 0; +		pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE; +		pAC->I2c.SenTable[i].SenRead = NULL; +		pAC->I2c.SenTable[i].SenDev = 0; +	} + +	/* Now we are "INIT data"ed */ +	pAC->I2c.InitLevel = SK_INIT_DATA; +	return(0); +}	/* SkI2cInit0*/ + + +/* + * Do the init state 1 initialization + * + * initialize the following register of the LM80: + * Configuration register: + * - START, noINT, activeLOW, noINT#Clear, noRESET, noCI, noGPO#, noINIT + * + * Interrupt Mask Register 1: + * - all interrupts are Disabled (0xff) + * + * Interrupt Mask Register 2: + * - all interrupts are Disabled (0xff) Interrupt modi doesn't matter. + * + * Fan Divisor/RST_OUT register: + * - Divisors set to 1 (bits 00), all others 0s. + * + * OS# Configuration/Temperature resolution Register: + * - all 0s + * + */ +static int SkI2cInit1( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC)	/* I/O Context */ +{ +    int i; +    SK_U8 I2cSwCtrl; +	SK_GEPORT *pPrt;	/* GIni Port struct pointer */ + +	if (pAC->I2c.InitLevel != SK_INIT_DATA) { +		/* ReInit not needed in I2C module */ +		return(0); +	} + +    /* Set the Direction of I2C-Data Pin to IN */ +    SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA); +    /* Check for 32-Bit Yukon with Low at I2C-Data Pin */ +	SK_I2C_GET_SW(IoC, &I2cSwCtrl); + +	if ((I2cSwCtrl & I2C_DATA) == 0) { +		/* this is a 32-Bit board */ +		pAC->GIni.GIYukon32Bit = SK_TRUE; +	return(0); +    } + +	/* Check for 64 Bit Yukon without sensors */ +	if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_CFG, 0) != 0) { +	return(0); +    } + +	(void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_1, 0); + +	(void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_2, 0); + +	(void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_FAN_CTRL, 0); + +	(void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_TEMP_CTRL, 0); + +	(void)SkI2cWrite(pAC, IoC, LM80_CFG_START, LM80_ADDR, LM80_CFG, 0); + +	/* +	 * MaxSens has to be updated here, because PhyType is not +	 * set when performing Init Level 0 +	 */ +    pAC->I2c.MaxSens = 5; + +	pPrt = &pAC->GIni.GP[0]; + +	if (pAC->GIni.GIGenesis) { +		if (pPrt->PhyType == SK_PHY_BCOM) { +			if (pAC->GIni.GIMacsFound == 1) { +				pAC->I2c.MaxSens += 1; +			} +			else { +				pAC->I2c.MaxSens += 3; +			} +		} +	} +	else { +		pAC->I2c.MaxSens += 3; +	} + +	for (i = 0; i < pAC->I2c.MaxSens; i++) { +		switch (i) { +		case 0: +			pAC->I2c.SenTable[i].SenDesc = "Temperature"; +			pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP; +			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_TEMP_HIGH_ERR; +			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_TEMP_HIGH_WARN; +			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_TEMP_LOW_WARN; +			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_TEMP_LOW_ERR; +			pAC->I2c.SenTable[i].SenReg = LM80_TEMP_IN; +			break; +		case 1: +			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI"; +			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; +			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_5V_HIGH_ERR; +			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_5V_HIGH_WARN; +			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_5V_LOW_WARN; +			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_5V_LOW_ERR; +			pAC->I2c.SenTable[i].SenReg = LM80_VT0_IN; +			break; +		case 2: +			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI-IO"; +			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; +			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_IO_5V_HIGH_ERR; +			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_IO_5V_HIGH_WARN; +			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_IO_3V3_LOW_WARN; +			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_IO_3V3_LOW_ERR; +			pAC->I2c.SenTable[i].SenReg = LM80_VT1_IN; +			pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_PCI_IO; +			break; +		case 3: +			pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC"; +			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; +			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VDD_HIGH_ERR; +			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VDD_HIGH_WARN; +			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VDD_LOW_WARN; +			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VDD_LOW_ERR; +			pAC->I2c.SenTable[i].SenReg = LM80_VT2_IN; +			break; +		case 4: +			if (pAC->GIni.GIGenesis) { +				if (pPrt->PhyType == SK_PHY_BCOM) { +					pAC->I2c.SenTable[i].SenDesc = "Voltage PHY A PLL"; +					pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR; +					pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN; +					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN; +					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR; +				} +				else { +					pAC->I2c.SenTable[i].SenDesc = "Voltage PMA"; +					pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR; +					pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN; +					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN; +					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR; +				} +			} +			else { +				pAC->I2c.SenTable[i].SenDesc = "Voltage VAUX"; +				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VAUX_3V3_HIGH_ERR; +				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VAUX_3V3_HIGH_WARN; +				if (pAC->GIni.GIVauxAvail) { +					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN; +					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR; +				} +				else { +					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_0V_WARN_ERR; +					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_0V_WARN_ERR; +				} +			} +			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; +			pAC->I2c.SenTable[i].SenReg = LM80_VT3_IN; +			break; +		case 5: +			if (pAC->GIni.GIGenesis) { +				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5"; +				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR; +				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN; +				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN; +				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR; +			} +			else { +				pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC-Co 1V5"; +				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_CORE_1V5_HIGH_ERR; +				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_CORE_1V5_HIGH_WARN; +				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_CORE_1V5_LOW_WARN; +				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_CORE_1V5_LOW_ERR; +			} +			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; +			pAC->I2c.SenTable[i].SenReg = LM80_VT4_IN; +			break; +		case 6: +			if (pAC->GIni.GIGenesis) { +				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY B PLL"; +			} +			else { +				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 3V3"; +			} +			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; +			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR; +			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN; +			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN; +			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR; +			pAC->I2c.SenTable[i].SenReg = LM80_VT5_IN; +			break; +		case 7: +			if (pAC->GIni.GIGenesis) { +				pAC->I2c.SenTable[i].SenDesc = "Speed Fan"; +				pAC->I2c.SenTable[i].SenType = SK_SEN_FAN; +				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_FAN_HIGH_ERR; +				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_FAN_HIGH_WARN; +				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_FAN_LOW_WARN; +				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_FAN_LOW_ERR; +				pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN; +			} +			else { +				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5"; +				pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT; +				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR; +				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN; +				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN; +				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR; +				pAC->I2c.SenTable[i].SenReg = LM80_VT6_IN; +			} +			break; +		default: +			SK_ERR_LOG(pAC, SK_ERRCL_INIT | SK_ERRCL_SW, +				SKERR_I2C_E001, SKERR_I2C_E001MSG); +			break; +		} + +		pAC->I2c.SenTable[i].SenValue = 0; +		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK; +		pAC->I2c.SenTable[i].SenErrCts = 0; +		pAC->I2c.SenTable[i].SenBegErrTS = 0; +		pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE; +		pAC->I2c.SenTable[i].SenRead = SkLm80ReadSensor; +		pAC->I2c.SenTable[i].SenDev = LM80_ADDR; +	} + +#ifndef	SK_DIAG +	pAC->I2c.DummyReads = pAC->I2c.MaxSens; +#endif	/* !SK_DIAG */ + +	/* Clear I2C IRQ */ +	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ); + +	/* Now we are I/O initialized */ +	pAC->I2c.InitLevel = SK_INIT_IO; +	return(0); +}	/* SkI2cInit1 */ + + +/* + * Init level 2: Start first sensor read. + */ +static int SkI2cInit2( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC)	/* I/O Context */ +{ +	int		ReadComplete; +	SK_SENSOR	*pSen; + +	if (pAC->I2c.InitLevel != SK_INIT_IO) { +		/* ReInit not needed in I2C module */ +		/* Init0 and Init2 not permitted */ +		return(0); +	} + +	pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; +	ReadComplete = SkI2cReadSensor(pAC, IoC, pSen); + +	if (ReadComplete) { +		SK_ERR_LOG(pAC, SK_ERRCL_INIT, SKERR_I2C_E008, SKERR_I2C_E008MSG); +	} + +	/* Now we are correctly initialized */ +	pAC->I2c.InitLevel = SK_INIT_RUN; + +	return(0); +}	/* SkI2cInit2*/ + + +/* + * Initialize I2C devices + * + * Get the first voltage value and discard it. + * Go into temperature read mode. A default pointer is not set. + * + * The things to be done depend on the init level in the parameter list: + * Level 0: + *	Initialize only the data structures. Do NOT access hardware. + * Level 1: + *	Initialize hardware through SK_IN / SK_OUT commands. Do NOT use interrupts. + * Level 2: + *	Everything is possible. Interrupts may be used from now on. + * + * return: + *	0 = success + *	other = error. + */ +int	SkI2cInit( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC,	/* I/O Context needed in levels 1 and 2 */ +int		Level)	/* Init Level */ +{ + +	switch (Level) { +	case SK_INIT_DATA: +		return(SkI2cInit0(pAC)); +	case SK_INIT_IO: +		return(SkI2cInit1(pAC, IoC)); +	case SK_INIT_RUN: +		return(SkI2cInit2(pAC, IoC)); +	default: +		break; +	} + +	return(0); +}	/* SkI2cInit */ + + +#ifndef SK_DIAG + +/* + * Interrupt service function for the I2C Interface + * + * Clears the Interrupt source + * + * Reads the register and check it for sending a trap. + * + * Starts the timer if necessary. + */ +void SkI2cIsr( +SK_AC	*pAC,	/* Adapter Context */ +SK_IOC	IoC)	/* I/O Context */ +{ +	SK_EVPARA	Para; + +	/* Clear I2C IRQ */ +	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ); + +	Para.Para64 = 0; +	SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_IRQ, Para); +}	/* SkI2cIsr */ + + +/* + * Check this sensors Value against the threshold and send events. + */ +static void SkI2cCheckSensor( +SK_AC		*pAC,	/* Adapter Context */ +SK_SENSOR	*pSen) +{ +	SK_EVPARA	ParaLocal; +	SK_BOOL		TooHigh;	/* Is sensor too high? */ +	SK_BOOL		TooLow;		/* Is sensor too low? */ +	SK_U64		CurrTime;	/* Current Time */ +	SK_BOOL		DoTrapSend;	/* We need to send a trap */ +	SK_BOOL		DoErrLog;	/* We need to log the error */ +	SK_BOOL		IsError;	/* We need to log the error */ + +	/* Check Dummy Reads first */ +	if (pAC->I2c.DummyReads > 0) { +		pAC->I2c.DummyReads--; +		return; +	} + +	/* Get the current time */ +	CurrTime = SkOsGetTime(pAC); + +	/* Set para to the most useful setting: The current sensor. */ +	ParaLocal.Para64 = (SK_U64)pAC->I2c.CurrSens; + +	/* Check the Value against the thresholds. First: Error Thresholds */ +	TooHigh = (pSen->SenValue > pSen->SenThreErrHigh); +	TooLow = (pSen->SenValue < pSen->SenThreErrLow); + +	IsError = SK_FALSE; +	if (TooHigh || TooLow) { +		/* Error condition is satisfied */ +		DoTrapSend = SK_TRUE; +		DoErrLog = SK_TRUE; + +		/* Now error condition is satisfied */ +		IsError = SK_TRUE; + +		if (pSen->SenErrFlag == SK_SEN_ERR_ERR) { +			/* This state is the former one */ + +			/* So check first whether we have to send a trap */ +			if (pSen->SenLastErrTrapTS + SK_SEN_ERR_TR_HOLD > +			    CurrTime) { +				/* +				 * Do NOT send the Trap. The hold back time +				 * has to run out first. +				 */ +				DoTrapSend = SK_FALSE; +			} + +			/* Check now whether we have to log an Error */ +			if (pSen->SenLastErrLogTS + SK_SEN_ERR_LOG_HOLD > +			    CurrTime) { +				/* +				 * Do NOT log the error. The hold back time +				 * has to run out first. +				 */ +				DoErrLog = SK_FALSE; +			} +		} +		else { +			/* We came from a different state -> Set Begin Time Stamp */ +			pSen->SenBegErrTS = CurrTime; +			pSen->SenErrFlag = SK_SEN_ERR_ERR; +		} + +		if (DoTrapSend) { +			/* Set current Time */ +			pSen->SenLastErrTrapTS = CurrTime; +			pSen->SenErrCts++; + +			/* Queue PNMI Event */ +			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ? +				SK_PNMI_EVT_SEN_ERR_UPP : +				SK_PNMI_EVT_SEN_ERR_LOW), +				ParaLocal); +		} + +		if (DoErrLog) { +			/* Set current Time */ +			pSen->SenLastErrLogTS = CurrTime; + +			if (pSen->SenType == SK_SEN_TEMP) { +				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011, +					SKERR_I2C_E011MSG); +			} else if (pSen->SenType == SK_SEN_VOLT) { +				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012, +					SKERR_I2C_E012MSG); +			} else +			{ +				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015, +					SKERR_I2C_E015MSG); +			} +		} +	} + +	/* Check the Value against the thresholds */ +	/* 2nd: Warning thresholds */ +	TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh); +	TooLow = (pSen->SenValue < pSen->SenThreWarnLow); + +	if (!IsError && (TooHigh || TooLow)) { +		/* Error condition is satisfied */ +		DoTrapSend = SK_TRUE; +		DoErrLog = SK_TRUE; + +		if (pSen->SenErrFlag == SK_SEN_ERR_WARN) { +			/* This state is the former one */ + +			/* So check first whether we have to send a trap */ +			if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD > +			    CurrTime) { +				/* +				 * Do NOT send the Trap. The hold back time +				 * has to run out first. +				 */ +				DoTrapSend = SK_FALSE; +			} + +			/* Check now whether we have to log an Error */ +			if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD > +			    CurrTime) { +				/* +				 * Do NOT log the error. The hold back time +				 * has to run out first. +				 */ +				DoErrLog = SK_FALSE; +			} +		} +		else { +			/* We came from a different state -> Set Begin Time Stamp */ +			pSen->SenBegWarnTS = CurrTime; +			pSen->SenErrFlag = SK_SEN_ERR_WARN; +		} + +		if (DoTrapSend) { +			/* Set current Time */ +			pSen->SenLastWarnTrapTS = CurrTime; +			pSen->SenWarnCts++; + +			/* Queue PNMI Event */ +			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ? +				SK_PNMI_EVT_SEN_WAR_UPP : +				SK_PNMI_EVT_SEN_WAR_LOW), +				ParaLocal); +		} + +		if (DoErrLog) { +			/* Set current Time */ +			pSen->SenLastWarnLogTS = CurrTime; + +			if (pSen->SenType == SK_SEN_TEMP) { +				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, +					SKERR_I2C_E009MSG); +			} else if (pSen->SenType == SK_SEN_VOLT) { +				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, +					SKERR_I2C_E010MSG); +			} else +			{ +				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, +					SKERR_I2C_E014MSG); +			} +		} +	} + +	/* Check for NO error at all */ +	if (!IsError && !TooHigh && !TooLow) { +		/* Set o.k. Status if no error and no warning condition */ +		pSen->SenErrFlag = SK_SEN_ERR_OK; +	} + +	/* End of check against the thresholds */ + +	/* Bug fix AF: 16.Aug.2001: Correct the init base +	 * of LM80 sensor. +	 */ +	if (pSen->SenInit == SK_SEN_DYN_INIT_PCI_IO) { + +	pSen->SenInit = SK_SEN_DYN_INIT_NONE; + +		if (pSen->SenValue > SK_SEN_PCI_IO_RANGE_LIMITER) { +			/* 5V PCI-IO Voltage */ +			pSen->SenThreWarnLow = SK_SEN_PCI_IO_5V_LOW_WARN; +			pSen->SenThreErrLow = SK_SEN_PCI_IO_5V_LOW_ERR; +		} +		else { +			/* 3.3V PCI-IO Voltage */ +			pSen->SenThreWarnHigh = SK_SEN_PCI_IO_3V3_HIGH_WARN; +			pSen->SenThreErrHigh = SK_SEN_PCI_IO_3V3_HIGH_ERR; +		} +	} + +#if 0 +    /* Dynamic thresholds also for VAUX of LM80 sensor */ +	if (pSen->SenInit == SK_SEN_DYN_INIT_VAUX) { + +	pSen->SenInit = SK_SEN_DYN_INIT_NONE; + +		/* 3.3V VAUX Voltage */ +		if (pSen->SenValue > SK_SEN_VAUX_RANGE_LIMITER) { +			pSen->SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN; +			pSen->SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR; +		} +		/* 0V VAUX Voltage */ +		else { +			pSen->SenThreWarnHigh = SK_SEN_VAUX_0V_WARN_ERR; +			pSen->SenThreErrHigh = SK_SEN_VAUX_0V_WARN_ERR; +		} +	} + +	/* +	 * Check initialization state: +	 * The VIO Thresholds need adaption +	 */ +	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN && +	     pSen->SenValue > SK_SEN_WARNLOW2C && +	     pSen->SenValue < SK_SEN_WARNHIGH2) { +		pSen->SenThreErrLow = SK_SEN_ERRLOW2C; +		pSen->SenThreWarnLow = SK_SEN_WARNLOW2C; +		pSen->SenInit = SK_TRUE; +	} + +	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN && +	     pSen->SenValue > SK_SEN_WARNLOW2 && +	     pSen->SenValue < SK_SEN_WARNHIGH2C) { +		pSen->SenThreErrHigh = SK_SEN_ERRHIGH2C; +		pSen->SenThreWarnHigh = SK_SEN_WARNHIGH2C; +		pSen->SenInit = SK_TRUE; +	} +#endif + +	if (pSen->SenInit != SK_SEN_DYN_INIT_NONE) { +		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG); +	} +}	/* SkI2cCheckSensor*/ + + +/* + * The only Event to be served is the timeout event + * + */ +int	SkI2cEvent( +SK_AC		*pAC,	/* Adapter Context */ +SK_IOC		IoC,	/* I/O Context */ +SK_U32		Event,	/* Module specific Event */ +SK_EVPARA	Para)	/* Event specific Parameter */ +{ +	int			ReadComplete; +	SK_SENSOR	*pSen; +	SK_U32		Time; +	SK_EVPARA	ParaLocal; +	int			i; + +	/* New case: no sensors */ +	if (pAC->I2c.MaxSens == 0) { +		return(0); +	} + +	switch (Event) { +	case SK_I2CEV_IRQ: +		pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; +		ReadComplete = SkI2cReadSensor(pAC, IoC, pSen); + +		if (ReadComplete) { +			/* Check sensor against defined thresholds */ +			SkI2cCheckSensor (pAC, pSen); + +			/* Increment Current sensor and set appropriate Timeout */ +			pAC->I2c.CurrSens++; +			if (pAC->I2c.CurrSens >= pAC->I2c.MaxSens) { +				pAC->I2c.CurrSens = 0; +				Time = SK_I2C_TIM_LONG; +			} +			else { +				Time = SK_I2C_TIM_SHORT; +			} + +			/* Start Timer */ +			ParaLocal.Para64 = (SK_U64)0; + +			pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING; + +			SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time, +				SKGE_I2C, SK_I2CEV_TIM, ParaLocal); +		} +	else { +			/* Start Timer */ +			ParaLocal.Para64 = (SK_U64)0; + +			pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE; + +	    SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, SK_I2C_TIM_WATCH, +				SKGE_I2C, SK_I2CEV_TIM, ParaLocal); +		} +		break; +	case SK_I2CEV_TIM: +		if (pAC->I2c.TimerMode == SK_TIMER_NEW_GAUGING) { + +			ParaLocal.Para64 = (SK_U64)0; +			SkTimerStop(pAC, IoC, &pAC->I2c.SenTimer); + +			pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; +			ReadComplete = SkI2cReadSensor(pAC, IoC, pSen); + +			if (ReadComplete) { +				/* Check sensor against defined thresholds */ +				SkI2cCheckSensor (pAC, pSen); + +				/* Increment Current sensor and set appropriate Timeout */ +				pAC->I2c.CurrSens++; +				if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) { +					pAC->I2c.CurrSens = 0; +					Time = SK_I2C_TIM_LONG; +				} +				else { +					Time = SK_I2C_TIM_SHORT; +				} + +				/* Start Timer */ +				ParaLocal.Para64 = (SK_U64)0; + +				pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING; + +				SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time, +					SKGE_I2C, SK_I2CEV_TIM, ParaLocal); +			} +		} +		else { +			pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; +			pSen->SenErrFlag = SK_SEN_ERR_FAULTY; +			SK_I2C_STOP(IoC); + +			/* Increment Current sensor and set appropriate Timeout */ +			pAC->I2c.CurrSens++; +			if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) { +				pAC->I2c.CurrSens = 0; +				Time = SK_I2C_TIM_LONG; +			} +			else { +				Time = SK_I2C_TIM_SHORT; +			} + +			/* Start Timer */ +			ParaLocal.Para64 = (SK_U64)0; + +			pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING; + +			SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time, +				SKGE_I2C, SK_I2CEV_TIM, ParaLocal); +		} +		break; +	case SK_I2CEV_CLEAR: +		for (i = 0; i < SK_MAX_SENSORS; i++) { +			pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK; +			pAC->I2c.SenTable[i].SenErrCts = 0; +			pAC->I2c.SenTable[i].SenWarnCts = 0; +			pAC->I2c.SenTable[i].SenBegErrTS = 0; +			pAC->I2c.SenTable[i].SenBegWarnTS = 0; +			pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64)0; +			pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64)0; +			pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64)0; +			pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64)0; +		} +		break; +	default: +		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E006, SKERR_I2C_E006MSG); +	} + +	return(0); +}	/* SkI2cEvent*/ + +#endif	/* !SK_DIAG */ + +#endif /* CONFIG_SK98 */ |