* Add support for SK98xx driver
[pandora-u-boot.git] / drivers / sk98lin / ski2c.c
diff --git a/drivers/sk98lin/ski2c.c b/drivers/sk98lin/ski2c.c
new file mode 100644 (file)
index 0000000..671f76e
--- /dev/null
@@ -0,0 +1,1499 @@
+/******************************************************************************
+ *
+ * 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.
+ *
+ *
+ ******************************************************************************/
+
+
+/*
+ *     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 */