/******************************************************************************* NAME $RCSfile: max6657Diag.c,v $ SUMMARY Max6657 temperature sensor diagnostics VERSION $Revision: 1.5 $ UPDATE DATE $Date: 2009/10/08 06:39:54 $ PROGRAMMER $Author: cloud $ Copyright 2009 LSI Corporation. All Rights Reserved. DESCRIPTION: REFERENCE: *******************************************************************************/ #include #include #include #include #include #include #include #include #include #ifdef MAX6657_DEBUG #define DPRINTK(fmt...) printk("[MAX6657_DIAG] " fmt) #else #define DPRINTK(fmt...) do { } while(0) #endif /* Max Temperature difference between two controller */ #define MAX_TEMP_DIFFERENCE 10 //extern INT32 fpgaControllerOverTempInt(VOID); static uint16_t peerPCB; static uint16_t peerCPU; static int max6657Notified; #if 0 extern int adm1032GetTemp(uint16_t *pcb, uint16_t *cpu); extern int adm1032SensorTest(void); extern int adm1032AlertTest(void); #endif /* Register Definition */ #define MAX6657_REG_RLTS 0x00 /* Read Internal Temperature */ #define MAX6657_REG_RRTE 0x01 /* Read External Temperature */ #define MAX6657_REG_RSL 0x02 /* Read Status Register */ #define MAX6657_REG_RCL 0x03 /* Read Configuration Byte */ #define MAX6657_REG_RCRA 0x04 /* Read Conversion Rete Byte */ #define MAX6657_REG_RLHN 0x05 /* Read Internal High Limit */ #define MAX6657_REG_RLLI 0x06 /* Read Internal Low Limit */ #define MAX6657_REG_RRHI 0x07 /* Read External High Limit */ #define MAX6657_REG_RRLS 0x08 /* Read External Low Limit */ #define MAX6657_REG_WCA 0x09 /* Write Configuration Byte */ #define MAX6657_REG_WCRW 0x0a /* Write Conversion Rate Byte */ #define MAX6657_REG_WLHO 0x0b /* Write Internal High Limit */ #define MAX6657_REG_WLLM 0x0c /* Write Internal Low Limit */ #define MAX6657_REG_WRHA 0x0d /* Write External High Limit */ #define MAX6657_REG_WRLN 0x0e /* Write External Low Limit */ #define MAX6657_REG_OSHT 0x0f /* One Shot */ #define MAX6657_REG_REET 0x10 /* Read External Extended Temperature */ #define MAX6657_REG_RIET 0x11 /* Read Internal Extended Temperature*/ #define MAX6657_REG_RWO2E 0x16 /* Read/Write External OVERT2 Limit (6659 only) */ #define MAX6657_REG_RWO2I 0x17 /* Read/Write Internal OVERT2 Limit (6659 only) */ #define MAX6657_REG_RWOE 0x19 /* Read/Write External OVERT1 Limit*/ #define MAX6657_REG_RWOI 0x20 /* Read/Write Internal OVERT1 Limit*/ #define MAX6657_REG_HYST 0x21 /* Overtemperature Hysteresis */ #define MAX6657_REG_RMID 0xfe /* Read Manufacture ID */ #define MAX6657_I2C_ADDR (0x98 >> 1) #define SMBUS_ALERT_RSP_ADDR (0x18 >> 1) #define SENSOR_ID_ADM1032 0x41 #define SENSOR_ID_G786 0x47 #define SENSOR_ID_MAX6657 0x4d static int max6657RegRead( struct i2c_client *client, uint8_t reg, uint8_t *value ) { *value = i2c_smbus_read_byte_data( client, reg ); if( *value < 0 ) return 1; return 0; } static void max6657RegWrite( struct i2c_client *client, uint8_t reg, uint8_t value ) { i2c_smbus_write_byte_data( client, reg, value ); } static int max6657RunDevice( struct i2c_client *client ) { uint8_t cfg; int ret; ret = max6657RegRead( client, MAX6657_REG_RCL, &cfg ); if( ret < 0 ) { DPRINTK("%s failed to read register\n", __func__); return (ret); } DPRINTK("%s configuration value [%x]\n", __func__, cfg); /* at Run or Standby mode ? */ if (cfg & 0x40) max6657RegWrite( client, MAX6657_REG_WCA, cfg & 0xbf); /* set run */ return (0); } static int max6657EnableAlert( struct i2c_client *client ) { int ret; ret = i2c_smbus_read_byte_data( client, MAX6657_REG_RCL ); if( ret < 0 ) { DPRINTK("%s failed to read register\n", __func__); return (ret); } DPRINTK("%s configuration value [%x]\n", __func__, cfg); /* Alert masked ? */ if( ret & 0x80 ) i2c_smbus_write_byte_data( client, MAX6657_REG_WCA, ret & 0x7f ); /* enable alert */ return (0); } int max6657ReadManuID( struct i2c_client *client, uint8_t *id ) { return (max6657RegRead( client, MAX6657_REG_RMID, id)); } int max6657AlertResp( struct i2c_client *client ) { union i2c_smbus_data data; return (i2c_smbus_xfer( client->adapter, SMBUS_ALERT_RSP_ADDR , 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data)); } /******************************************************************************* * PROCEDURE * * NAME: max6657GetTemperature * SUMMARY: Get temperature on this controller * * SCOPE: Public * * DESCRIPTION: * Max6657 has an internal and an external sensor, * internal sensor represents the PCB board temperature * external sensor represents the CPU die temperature * RETURNS: * * NOTES: * input: pcb@ composed of internal temp. (high byte) & extended temp (low byte). * input: cpu@ composed of external temp. (high byte) & extended temp (low byte). */ int max6657GetTemperature(uint16_t *pcb, uint16_t *cpu) { uint8_t pcbTemp, pcbExt; uint8_t cpuTemp, cpuExt; uint8_t status; int ret; struct i2c_client *client; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return -ENODEV; } /* Check and clear status */ max6657RegRead(client, MAX6657_REG_RSL, &status); DPRINTK("%s status %02x\n", __func__, status); if (status & 0x78) max6657AlertResp( client ); /* Get internal temperature */ if ((ret = max6657RegRead(client, MAX6657_REG_RLTS, &pcbTemp))) return (ret); if ((ret = max6657RegRead(client, MAX6657_REG_RIET, &pcbExt))) return (ret); /* Get external temperature */ if ((ret = max6657RegRead(client, MAX6657_REG_RRTE, &cpuTemp))) return (ret); if ((ret = max6657RegRead(client, MAX6657_REG_REET, &cpuExt))) return (ret); DPRINTK("%s PCB [%d.%d] degree, CPU [%d.%d] degree\n", __func__, pcbTemp, (pcbExt >> 5) * 125, cpuTemp, (cpuExt >> 5) * 125); *pcb = (((uint16_t) pcbTemp) << 8) + pcbExt; *cpu = (((uint16_t) cpuTemp) << 8) + cpuExt; return (0); } static void max6657GetTempNotify(EIPC_MSG *msg) { if (msg->hdr.cookie) { max6657Notified = -EIO; } else { max6657Notified = 1; memcpy(&peerPCB, &msg->body[0], sizeof(uint16_t)); memcpy(&peerCPU, &msg->body[sizeof(uint16_t)], sizeof(uint16_t)); } } #if 0 /******************************************************************************* * PROCEDURE * * NAME: max6657GetPeerTemperature * SUMMARY: Get temperature on peer controller * * SCOPE: Public * * DESCRIPTION: * Max6657 has an internal and an external sensor, * internal sensor represents the PCB board temperature * external sensor represents the CPU die temperature * RETURNS: * * NOTES: * input: pcb@ composed of internal temp. (high byte) & extended temp (low byte). * input: cpu@ composed of external temp. (high byte) & extended temp (low byte). */ int max6657GetPeerTemperature(uint16_t *pcb, uint16_t *cpu) { IPC_MSG msg; int ret = 0; int TIMEOUT = 3*HZ; /* 3 seconds */ unsigned long expire; /* reset vaule */ peerPCB = 0; peerCPU = 0; ipcEthernetRegister(IPC_APP_GET_TEMP, max6657GetTempNotify); max6657Notified = 0; /* send request */ msg.hdr.app = IPC_APP_GET_TEMP; msg.hdr.flag = IPC_APP_REQUEST; msg.hdr.len = 0; ipcEthernetSend((EIPC_MSG*) &msg); /* wait for completion */ expire = jiffies + TIMEOUT; while (time_before(jiffies, expire)) { if (max6657Notified) break; msleep(1); } if (!max6657Notified) ret = -ETIMEDOUT; else if (max6657Notified < 0) { printk("[MAX6657] failed to get peer controller temperature\n"); ret = -EIO; } else { *pcb = peerPCB; *cpu = peerCPU; } ipcEthernetDeregister(IPC_APP_GET_TEMP); return (ret); } #endif /******************************************************************************* * PROCEDURE * * NAME: max6657AlertTest * SUMMARY: Test Alert line functionality * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int max6657AlertTest(void) { struct i2c_client *client; uint16_t pcb, cpu; uint8_t limit, status; int ret; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return -ENODEV; } /* Run device if not */ ret = max6657RunDevice( client ); if (ret) { DPRINTK("%s: failed to initialize device\n", __func__); commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_ALERT, TEMP_SENSOR_CODE_ALERT, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return (ret); } ret = max6657GetTemperature( &pcb, &cpu ); if (ret) { DPRINTK("%s: failed to get temperature\n", __func__); commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_ALERT, TEMP_SENSOR_CODE_ALERT, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return (ret); } /* * Test ALERT */ /* Enable ALERT if not */ max6657EnableAlert( client ); max6657RegRead(client, MAX6657_REG_RLHN, &limit); DPRINTK("%s internal high limit [%d]\n", __func__, limit); /* Set internal high limit 10 degree lower to measured temp. */ max6657RegWrite(client, MAX6657_REG_WLHO, (uint8_t) (pcb >> 8) - 10); /* Wait for conversion * default conversion rate 16 Hz */ msleep(500); #if 0 /* FPGA read ALERT */ if (!fpgaControllerOverTempInt()) commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_ALERT, TEMP_SENSOR_CODE_ALERT, TEMP_SENSOR_MSG_EALERT_ASSERT, 0, 0, 0, DG_FORMAT_NONE); #endif /* Restore limit & clear ALERT */ max6657RegWrite(client, MAX6657_REG_WLHO, limit); max6657AlertResp( client ); max6657RegRead(client, MAX6657_REG_RSL, &status); DPRINTK("%s status %02x\n", __func__, status); msleep(500); #if 0 /* FPGA read ALERT */ if (fpgaControllerOverTempInt()) commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_ALERT, TEMP_SENSOR_CODE_ALERT, TEMP_SENSOR_MSG_EALERT_DEASSERT, 0, 0, 0, DG_FORMAT_NONE); #endif return (0); } /******************************************************************************* * PROCEDURE * * NAME: max6657OvertTest * SUMMARY: Test OVERT line functionality * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int max6657OvertTest(void) { struct i2c_client *client; uint16_t pcb, cpu; uint8_t limit, status; int ret; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return -ENODEV; } /* Run device if not */ ret = max6657RunDevice( client ); if (ret) { DPRINTK("%s: failed to initialize device\n", __func__); commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_OVERT, TEMP_SENSOR_CODE_OVERT, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return (ret); } ret = max6657GetTemperature(&pcb, &cpu); if (ret) { DPRINTK("%s: failed to get temperature\n", __func__); commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_OVERT, TEMP_SENSOR_CODE_OVERT, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return (ret); } /* * Test OVERT */ max6657RegRead(client, MAX6657_REG_RWOI, &limit); DPRINTK("%s internal OVERT limit [%d]\n", __func__, limit); /* Set internal OVERT limit 10 degree lower to measured temp. */ max6657RegWrite(client, MAX6657_REG_RWOI, (uint8_t) (pcb >> 8) - 10); /* Wait for conversion * default conversion rate 16 Hz */ msleep(500); /* TODO: FPGA read OVERT (HW not supports now) */ /* Restore limit & clear ALERT */ max6657RegWrite(client, MAX6657_REG_RWOI, limit); max6657RegRead(client, MAX6657_REG_RSL, &status); msleep(500); /* TODO: FPGA read ALERT (HW not supports now) */ return (0); } /******************************************************************************* * PROCEDURE * * NAME: max6657SensorTest * SUMMARY: Test internal/external sensor * * SCOPE: Public * * DESCRIPTION: * The internal/external temperature value shall compare to values of * peer fixture controller, if peer exist. * RETURNS: * * NOTES: * */ int max6657SensorTest(void) { struct i2c_client *client; uint16_t pcb, cpu; uint16_t pPcb, pCpu, diffPcb; int ret; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return -ENODEV; } /* Run device if not */ ret = max6657RunDevice( client ); if (ret) { DPRINTK("%s: failed to initialize device\n", __func__); commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_SENSOR, TEMP_SENSOR_CODE_SENSOR, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return (ret); } ret = max6657GetTemperature(&pcb, &cpu); if (ret) { DPRINTK("%s: failed to get temperature\n", __func__); commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_SENSOR, TEMP_SENSOR_CODE_SENSOR, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return (ret); } /* FIXME: may fail to get peer controller temperature * do not report error */ /* Remove the procedure to get peer temperature , modify for all single controller, set ret > 0*/ /* ret = max6657GetPeerTemperature(&pPcb, &pCpu); if (ret) printk("%s failed to get peer controller temperature\n", __func__); */ /* No need to perform dual controller */ // if (sysDualCtrl && !ret) if(0) { if (pcb >= pPcb) diffPcb = pcb - pPcb; else diffPcb = pPcb - pcb; diffPcb = diffPcb >> 8; if (diffPcb > MAX_TEMP_DIFFERENCE) { commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_SENSOR, TEMP_SENSOR_CODE_SENSOR, TEMP_SENSOR_MSG_EVALUE, 0, 0, 0, DG_FORMAT_NONE); } /* external sensor is not connected */ if (cpu == 0x8000) { printk("[Temperature Sensor]\n" " UUT CTL PCB [%d.%d] degree\n" "Fixture CTL PCB [%d.%d] degree\n", pcb >> 8, (((uint8_t) pcb) >> 5) * 125, pPcb >> 8, (((uint8_t) pPcb) >> 5) * 125); } else { printk("[Temperature Sensor]\n" " UUT CTL PCB [%d.%d] degree, CPU [%d.%d] degree\n" "Fixture CTL PCB [%d.%d] degree, CPU [%d.%d] degree\n", pcb >> 8, (((uint8_t) pcb) >> 5) * 125, cpu >> 8, (((uint8_t) cpu) >> 5) * 125, pPcb >> 8, (((uint8_t) pPcb) >> 5) * 125, pCpu >> 8, (((uint8_t) pCpu) >> 5) * 125); } } /* single controller */ else { /* external sensor is not connected */ if (cpu == 0x8000) { printk("[MAX6657] PCB [%d.%d] degree\n", pcb >> 8, (((uint8_t) pcb) >> 5) * 125); } else { printk("[MAX6657] PCB [%d.%d] degree, CPU [%d.%d] degree\n", pcb >> 8, (((uint8_t) pcb) >> 5) * 125, cpu >> 8, (((uint8_t) cpu) >> 5) * 125); } } return (0); } void max6657SetConversionRate(uint8_t rate) { struct i2c_client *client; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return; } max6657RegWrite(client, MAX6657_REG_WCRW, rate); } void max6657SetInternalLowLimit(uint8_t limit) { struct i2c_client *client; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return; } max6657RegWrite(client, MAX6657_REG_WLLM, limit); } void max6657SetInternalHihgLimit(uint8_t limit) { struct i2c_client *client; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return; } max6657RegWrite(client, MAX6657_REG_WLHO, limit); } void max6657WriteRegister(uint16_t reg, uint8_t value) { struct i2c_client *client; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return; } max6657RegWrite(client, reg, value); } void max6657DumpReg(void) { uint8_t reg, value; struct i2c_client *client; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return; } reg = 0x00; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x01; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x02; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x03; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x04; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x05; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x06; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x07; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x08; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x10; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x11; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x16; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x17; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x19; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0x20; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); reg = 0xfe; max6657RegRead(client, reg, &value); printk("register %02x value %02x\n", reg, value); } static int sensorGetId( void ) { struct i2c_client *client; int id; /* MAX6657 */ client = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get max6657 device\n", __func__ ); return -ENODEV; } /* max6657 & adm1032 has same adderss for manufacturer id */ // Read manufacturing ID id = i2c_smbus_read_byte_data( client, 0xFE ); if( id < 0 ) { commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_SENSOR, TEMP_SENSOR_CODE_SENSOR, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return -ENODEV; } return id; } int soyuzSensorGetTemperature(uint16_t *pcb, uint16_t *cpu) { int ret; int id; int (*funcPtr) (uint16_t *, uint16_t *); // Get Sensor ID /* id = sensorGetId(); switch ( id ) { #if 1 case SENSOR_ID_ADM1032: case SENSOR_ID_G786: #endif case SENSOR_ID_MAX6657: funcPtr = max6657GetTemperature; break; default: printk("WARNING: unsupported sensor manufacturer ID (%02x)\n", id); commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_SENSOR, TEMP_SENSOR_CODE_SENSOR, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return (0); } */ funcPtr = max6657GetTemperature; ret = (funcPtr(pcb, cpu)); return ret; } /******************************************************************************* * PROCEDURE * * NAME: SensorTest * SUMMARY: Test internal/external sensor * * SCOPE: Public * * DESCRIPTION: * The internal/external temperature value shall compare to values of * peer fixture controller, if peer exist. * RETURNS: * * NOTES: * */ int sensorTest(void) { int ret, id; int (*testFunction) (void); // Get Sensor ID /* id = sensorGetId(); switch (id) { #if 1 case SENSOR_ID_ADM1032: case SENSOR_ID_G786: #endif case SENSOR_ID_MAX6657: testFunction = max6657SensorTest; break; default: printk("WARNING: unsupported sensor manufacturer ID (%02x)\n", id); commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_SENSOR, TEMP_SENSOR_CODE_SENSOR, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return (0); } */ testFunction = max6657SensorTest; ret = (testFunction()); return ret; } /******************************************************************************* * PROCEDURE * * NAME: sensorAlertTest * SUMMARY: Test sensor Alert line functionality * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int sensorAlertTest(void) { int ret, id; int (*testFunction) (void); // Get Sensor ID /* id = sensorGetId(); switch (id) { #if 1 case SENSOR_ID_ADM1032: case SENSOR_ID_G786: #endif case SENSOR_ID_MAX6657: testFunction = max6657AlertTest; break; default: printk("WARNING: unsupported sensor manufacturer ID (%02x)\n", id); commReportError(MEC_TEMP_SENSOR, TEMP_SENSOR_ITEM_SENSOR, TEMP_SENSOR_CODE_SENSOR, TEMP_SENSOR_MSG_EIO, 0, 0, 0, DG_FORMAT_NONE); return (0); } */ testFunction = max6657AlertTest; ret = (testFunction()); return ret; } MODULE_AUTHOR( "will.lee@netapp.com" ); MODULE_DESCRIPTION( "NetApp Temperature Sensor Diag Code" ); MODULE_LICENSE( "GPL" ); MODULE_VERSION( "0.1" );