cpqfcTSi2c.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:12k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* Copyright(c) 2000, Compaq Computer Corporation 
  2.  * Fibre Channel Host Bus Adapter 
  3.  * 64-bit, 66MHz PCI 
  4.  * Originally developed and tested on:
  5.  * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
  6.  *          SP# P225CXCBFIEL6T, Rev XC
  7.  *          SP# 161290-001, Rev XD
  8.  * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify it
  11.  * under the terms of the GNU General Public License as published by the
  12.  * Free Software Foundation; either version 2, or (at your option) any
  13.  * later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful, but
  16.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18.  * General Public License for more details.
  19.  * Written by Don Zimmerman
  20. */
  21. // These functions control the NVRAM I2C hardware on 
  22. // non-intelligent Fibre Host Adapters.
  23. // The primary purpose is to read the HBA's NVRAM to get adapter's 
  24. // manufactured WWN to copy into Tachyon chip registers
  25. // Orignal source author unknown
  26. #include <linux/types.h>
  27. enum boolean { FALSE, TRUE } ;
  28. #ifndef UCHAR
  29. typedef __u8 UCHAR;
  30. #endif
  31. #ifndef BOOLEAN
  32. typedef __u8 BOOLEAN;
  33. #endif
  34. #ifndef USHORT
  35. typedef __u16 USHORT;
  36. #endif
  37. #ifndef ULONG
  38. typedef __u32 ULONG;
  39. #endif
  40. #include <linux/string.h>
  41. #include <linux/pci.h>
  42. #include <linux/delay.h>
  43. #include <linux/sched.h>
  44. #include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
  45. #include "cpqfcTSchip.h"
  46. static void tl_i2c_tx_byte( void* GPIOout, UCHAR data );
  47. /*static BOOLEAN tl_write_i2c_page_portion( void* GPIOin, void* GPIOout,
  48.   USHORT startOffset,  // e.g. 0x2f for WWN start
  49.   USHORT count,
  50.   UCHAR *buf );
  51. */
  52. //
  53. // Tachlite GPIO2, GPIO3 (I2C) DEFINES
  54. // The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
  55. // GPIO2 drives SDA, and GPIO3 drives SCL
  56. // 
  57. // Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
  58. // and clear writes 1. The input lines (read in TL status) is NOT inverted
  59. // This really helps confuse the code and debugging.
  60. #define SET_DATA_HI  0x0
  61. #define SET_DATA_LO  0x8
  62. #define SET_CLOCK_HI 0x0
  63. #define SET_CLOCK_LO 0x4
  64. #define SENSE_DATA_HI  0x8
  65. #define SENSE_DATA_LO  0x0
  66. #define SENSE_CLOCK_HI 0x4
  67. #define SENSE_CLOCK_LO 0x0
  68. #define SLAVE_READ_ADDRESS    0xA1
  69. #define SLAVE_WRITE_ADDRESS   0xA0
  70.       
  71. static void i2c_delay(ULONG mstime);
  72. static void tl_i2c_clock_pulse( UCHAR , void* GPIOout);
  73. static UCHAR tl_read_i2c_data( void* );
  74. //-----------------------------------------------------------------------------
  75. //
  76. //      Name:   I2C_RX_ACK
  77. //
  78. //      This routine receives an acknowledge over the I2C bus.
  79. //
  80. //-----------------------------------------------------------------------------
  81. static unsigned short tl_i2c_rx_ack( void* GPIOin, void* GPIOout )
  82. {
  83.   unsigned long value;
  84. // do clock pulse, let data line float high
  85.   tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
  86. // slave must drive data low for acknowledge
  87.   value = tl_read_i2c_data( GPIOin);
  88.   if (value & SENSE_DATA_HI )
  89.     return( FALSE );
  90.   return( TRUE );
  91. }
  92. //-----------------------------------------------------------------------------
  93. //
  94. //      Name:   READ_I2C_REG
  95. //
  96. //      This routine reads the I2C control register using the global
  97. //      IO address stored in gpioreg.
  98. //
  99. //-----------------------------------------------------------------------------
  100. static UCHAR tl_read_i2c_data( void* gpioreg )
  101. {
  102.   return( (UCHAR)(readl( gpioreg ) & 0x08L) ); // GPIO3
  103. }
  104. //-----------------------------------------------------------------------------
  105. //
  106. //      Name:   WRITE_I2C_REG
  107. //
  108. //      This routine writes the I2C control register using the global
  109. //      IO address stored in gpioreg.
  110. //      In Tachlite, we don't want to modify other bits in TL Control reg.
  111. //
  112. //-----------------------------------------------------------------------------
  113. static void tl_write_i2c_reg( void* gpioregOUT, UCHAR value )
  114. {
  115.   ULONG  temp;
  116. // First read the register and clear out the old bits
  117.   temp = readl( gpioregOUT ) & 0xfffffff3L;
  118. // Now or in the new data and send it back out
  119.   writel( temp | value, gpioregOUT);
  120. }
  121. //-----------------------------------------------------------------------------
  122. //
  123. //      Name:   I2C_TX_START
  124. //
  125. //      This routine transmits a start condition over the I2C bus.
  126. //      1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH,
  127. //      wait 5us to stabilize.
  128. //      2. With SCL still HIGH, drive SDA low.  The low transition marks
  129. //         the start condition to NM24Cxx (the chip)
  130. //      NOTE! In TL control reg., output 1 means chip sees LOW
  131. //
  132. //-----------------------------------------------------------------------------
  133. static unsigned short tl_i2c_tx_start( void* GPIOin, void* GPIOout )
  134. {
  135.   unsigned short i;
  136.   ULONG value;
  137.   if ( !(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI))
  138.   {
  139.     // start with clock high, let data float high
  140.     tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
  141.     // keep sending clock pulses if slave is driving data line
  142.     for (i = 0; i < 10; i++)
  143.     {
  144.       tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
  145.       if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
  146. break;
  147.     }
  148. // if he's still driving data low after 10 clocks, abort
  149.     value = tl_read_i2c_data( GPIOin ); // read status
  150.     if (!(value & 0x08) )
  151.       return( FALSE );
  152.   }
  153. // To START, bring data low while clock high
  154.   tl_write_i2c_reg(  GPIOout, SET_CLOCK_HI | SET_DATA_LO );
  155.   i2c_delay(0);
  156.   return( TRUE );                           // TX start successful
  157. }
  158. //-----------------------------------------------------------------------------
  159. //
  160. //      Name:   I2C_TX_STOP
  161. //
  162. //      This routine transmits a stop condition over the I2C bus.
  163. //
  164. //-----------------------------------------------------------------------------
  165. static unsigned short tl_i2c_tx_stop( void* GPIOin, void* GPIOout )
  166. {
  167.   int i;
  168.   for (i = 0; i < 10; i++) 
  169.   {
  170.   // Send clock pulse, drive data line low
  171.     tl_i2c_clock_pulse( SET_DATA_LO, GPIOout );
  172.   // To STOP, bring data high while clock high
  173.     tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
  174.   // Give the data line time to float high
  175.     i2c_delay(0);
  176.   // If slave is driving data line low, there's a problem; retry
  177.     if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
  178.       return( TRUE );  // TX STOP successful!
  179.   }
  180.   return( FALSE );                      // error
  181. }
  182. //-----------------------------------------------------------------------------
  183. //
  184. //      Name:   I2C_TX_uchar
  185. //
  186. //      This routine transmits a byte across the I2C bus.
  187. //
  188. //-----------------------------------------------------------------------------
  189. static void tl_i2c_tx_byte( void* GPIOout, UCHAR data )
  190. {
  191.   UCHAR bit;
  192.   for (bit = 0x80; bit; bit >>= 1)
  193.   {
  194.     if( data & bit )
  195.       tl_i2c_clock_pulse( (UCHAR)SET_DATA_HI, GPIOout);
  196.     else
  197.       tl_i2c_clock_pulse( (UCHAR)SET_DATA_LO, GPIOout);
  198.   }  
  199. }
  200. //-----------------------------------------------------------------------------
  201. //
  202. //      Name:   I2C_RX_uchar
  203. //
  204. //      This routine receives a byte across the I2C bus.
  205. //
  206. //-----------------------------------------------------------------------------
  207. static UCHAR tl_i2c_rx_byte( void* GPIOin, void* GPIOout )
  208. {
  209.   UCHAR bit;
  210.   UCHAR data = 0;
  211.   for (bit = 0x80; bit; bit >>= 1) {
  212.     // do clock pulse, let data line float high
  213.     tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
  214.     // read data line
  215.     if ( tl_read_i2c_data( GPIOin) & 0x08 )
  216.       data |= bit;
  217.   }
  218.   return (data);
  219. }
  220. //*****************************************************************************
  221. //*****************************************************************************
  222. // Function:   read_i2c_nvram
  223. // Arguments:  UCHAR count     number of bytes to read
  224. //             UCHAR *buf      area to store the bytes read
  225. // Returns:    0 - failed
  226. //             1 - success
  227. //*****************************************************************************
  228. //*****************************************************************************
  229. unsigned long cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
  230. UCHAR *buf )
  231. {
  232.   unsigned short i;
  233.   if( !( tl_i2c_tx_start(GPIOin, GPIOout) ))
  234.     return FALSE;
  235.   // Select the NVRAM for "dummy" write, to set the address
  236.   tl_i2c_tx_byte( GPIOout , SLAVE_WRITE_ADDRESS );
  237.   if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
  238.     return( FALSE );
  239.   // Now send the address where we want to start reading  
  240.   tl_i2c_tx_byte( GPIOout , 0 );
  241.   if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
  242.     return( FALSE );
  243.   // Send a repeated start condition and select the
  244.   //  slave for reading now.
  245.   if( tl_i2c_tx_start(GPIOin, GPIOout) )
  246.     tl_i2c_tx_byte( GPIOout, SLAVE_READ_ADDRESS );
  247.   if ( !tl_i2c_rx_ack(GPIOin, GPIOout) )
  248.     return( FALSE );
  249.   // this loop will now read out the data and store it
  250.   //  in the buffer pointed to by buf
  251.   for ( i=0; i<count; i++) 
  252.   {
  253.     *buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
  254.     // Send ACK by holding data line low for 1 clock
  255.     if ( i < (count-1) )
  256.       tl_i2c_clock_pulse( 0x08, GPIOout );
  257.     else {
  258. // Don't send ack for final byte
  259.       tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
  260.     }
  261.   }
  262.   tl_i2c_tx_stop(GPIOin, GPIOout);
  263.   return( TRUE );
  264. }
  265. //****************************************************************
  266. //
  267. //
  268. //
  269. // routines to set and clear the data and clock bits
  270. //
  271. //
  272. //
  273. //****************************************************************
  274. static void tl_set_clock(void* gpioreg)
  275. {
  276.   ULONG ret_val;
  277.   ret_val = readl( gpioreg );
  278.   ret_val &= 0xffffffFBL;  // clear GPIO2 (SCL)
  279.   writel( ret_val, gpioreg);
  280. }
  281. static void tl_clr_clock(void* gpioreg)
  282. {
  283.   ULONG ret_val;
  284.   ret_val = readl( gpioreg );
  285.   ret_val |= SET_CLOCK_LO;
  286.   writel( ret_val, gpioreg);
  287. }
  288. //*****************************************************************
  289. //
  290. //
  291. // This routine will advance the clock by one period
  292. //
  293. //
  294. //*****************************************************************
  295. static void tl_i2c_clock_pulse( UCHAR value, void* GPIOout  )
  296. {
  297.   ULONG ret_val;
  298.   // clear the clock bit
  299.   tl_clr_clock( GPIOout );
  300.   i2c_delay(0);
  301.   // read the port to preserve non-I2C bits
  302.   ret_val = readl( GPIOout );
  303.   // clear the data & clock bits
  304.   ret_val &= 0xFFFFFFf3;
  305.   // write the value passed in...
  306.   // data can only change while clock is LOW!
  307.   ret_val |= value;           // the data
  308.   ret_val |= SET_CLOCK_LO;    // the clock
  309.   writel( ret_val, GPIOout );
  310.   i2c_delay(0);
  311.   //set clock bit
  312.   tl_set_clock( GPIOout);
  313. }
  314. //*****************************************************************
  315. //
  316. //
  317. // This routine returns the 64-bit WWN
  318. //
  319. //
  320. //*****************************************************************
  321. int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf )
  322. {
  323.   ULONG len;
  324.   ULONG sub_len;
  325.   ULONG ptr_inc;
  326.   ULONG i;
  327.   ULONG j;
  328.   UCHAR *data_ptr;
  329.   UCHAR  z;
  330.   UCHAR  name;
  331.   UCHAR  sub_name;
  332.   UCHAR  done;
  333.   int iReturn=0;  // def. 0 offset is failure to find WWN field
  334.   
  335.   
  336.   data_ptr = (UCHAR *)buf;
  337.   done = FALSE;
  338.   i = 0;
  339.   while ( (i < 128) && (!done) ) 
  340.   {
  341.     z = data_ptr[i];
  342.     if ( !(z & 0x80) )  
  343.     {
  344.       len  = 1 + (z & 0x07);
  345.       name = (z & 0x78) >> 3;
  346.       if (name == 0x0F)
  347.         done = TRUE;
  348.     }
  349.     else 
  350.     {
  351.       name = z & 0x7F;
  352.       len  = 3 + data_ptr[i+1] + (data_ptr[i+2] << 8);
  353.            
  354.       switch (name) 
  355.       {
  356.       case 0x0D:
  357. //
  358.   j = i + 3;
  359.   //
  360.   if ( data_ptr[j] == 0x3b ) {
  361.     len = 6;
  362.     break;
  363.   }
  364.   while ( j<(i+len) ) {
  365.     sub_name = (data_ptr[j] & 0x3f);
  366.     sub_len  = data_ptr[j+1] + 
  367.                (data_ptr[j+2] << 8);
  368.             ptr_inc  = sub_len + 3; 
  369.     switch (sub_name) 
  370.     {
  371.     case 0x3C:
  372.               memcpy( wwnbuf, &data_ptr[j+3], 8);
  373.               iReturn = j+3;
  374.               break;
  375.             default:
  376.               break;
  377.     }
  378.     j += ptr_inc;
  379.           }
  380.   break;
  381.         default:
  382.   break;
  383.       }  
  384.     }  
  385.   //
  386.     i += len;
  387.   }  // end while 
  388.   return iReturn;
  389. }
  390. // define a short 5 micro sec delay, and longer (ms) delay
  391. static void i2c_delay(ULONG mstime)
  392. {
  393.   ULONG i;
  394.   
  395. // NOTE: we only expect to use these delays when reading
  396. // our adapter's NVRAM, which happens only during adapter reset.
  397. // Delay technique from "Linux Device Drivers", A. Rubini 
  398. // (1st Ed.) pg 137.
  399. //  printk(" delay %lx  ", mstime);
  400.   if( mstime ) // ms delay?
  401.   {
  402.     // delay technique
  403.     for( i=0; i < mstime; i++)
  404.       udelay(1000); // 1ms per loop
  405.   }
  406.   else  // 5 micro sec delay
  407.   
  408.     udelay( 5 ); // micro secs
  409.   
  410. //  printk("donen");
  411. }