summaryrefslogtreecommitdiff
path: root/drivers/net/sk98lin/ski2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sk98lin/ski2c.c')
-rw-r--r--drivers/net/sk98lin/ski2c.c1505
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 0000000..2ab635a
--- /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 */