181dee67eSSudip Mukherjee /*******************************************************************
281dee67eSSudip Mukherjee *
381dee67eSSudip Mukherjee *         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
481dee67eSSudip Mukherjee *
581dee67eSSudip Mukherjee *  All rights are reserved. Reproduction or in part is prohibited
681dee67eSSudip Mukherjee *  without the written consent of the copyright owner.
781dee67eSSudip Mukherjee *
881dee67eSSudip Mukherjee *  swi2c.c --- SM750/SM718 DDK
981dee67eSSudip Mukherjee *  This file contains the source code for I2C using software
1081dee67eSSudip Mukherjee *  implementation.
1181dee67eSSudip Mukherjee *
1281dee67eSSudip Mukherjee *******************************************************************/
1381dee67eSSudip Mukherjee #include "ddk750_help.h"
1481dee67eSSudip Mukherjee #include "ddk750_reg.h"
1581dee67eSSudip Mukherjee #include "ddk750_swi2c.h"
1681dee67eSSudip Mukherjee #include "ddk750_power.h"
1781dee67eSSudip Mukherjee 
1881dee67eSSudip Mukherjee 
1981dee67eSSudip Mukherjee /*******************************************************************
2081dee67eSSudip Mukherjee  * I2C Software Master Driver:
2181dee67eSSudip Mukherjee  * ===========================
2281dee67eSSudip Mukherjee  * Each i2c cycle is split into 4 sections. Each of these section marks
2381dee67eSSudip Mukherjee  * a point in time where the SCL or SDA may be changed.
2481dee67eSSudip Mukherjee  *
2581dee67eSSudip Mukherjee  * 1 Cycle == |  Section I. |  Section 2. |  Section 3. |  Section 4. |
2681dee67eSSudip Mukherjee  *            +-------------+-------------+-------------+-------------+
2781dee67eSSudip Mukherjee  *            | SCL set LOW |SCL no change| SCL set HIGH|SCL no change|
2881dee67eSSudip Mukherjee  *
2981dee67eSSudip Mukherjee  *                                          ____________ _____________
3081dee67eSSudip Mukherjee  * SCL == XXXX _____________ ____________ /
3181dee67eSSudip Mukherjee  *
3281dee67eSSudip Mukherjee  * I.e. the SCL may only be changed in section 1. and section 3. while
3381dee67eSSudip Mukherjee  * the SDA may only be changed in section 2. and section 4. The table
3481dee67eSSudip Mukherjee  * below gives the changes for these 2 lines in the varios sections.
3581dee67eSSudip Mukherjee  *
3681dee67eSSudip Mukherjee  * Section changes Table:
3781dee67eSSudip Mukherjee  * ======================
3881dee67eSSudip Mukherjee  * blank = no change, L = set bit LOW, H = set bit HIGH
3981dee67eSSudip Mukherjee  *
4081dee67eSSudip Mukherjee  *                                | 1.| 2.| 3.| 4.|
4181dee67eSSudip Mukherjee  *                 ---------------+---+---+---+---+
4281dee67eSSudip Mukherjee  *                 Tx Start   SDA |   | H |   | L |
4381dee67eSSudip Mukherjee  *                            SCL | L |   | H |   |
4481dee67eSSudip Mukherjee  *                 ---------------+---+---+---+---+
4581dee67eSSudip Mukherjee  *                 Tx Stop    SDA |   | L |   | H |
4681dee67eSSudip Mukherjee  *                            SCL | L |   | H |   |
4781dee67eSSudip Mukherjee  *                 ---------------+---+---+---+---+
4881dee67eSSudip Mukherjee  *                 Tx bit H   SDA |   | H |   |   |
4981dee67eSSudip Mukherjee  *                            SCL | L |   | H |   |
5081dee67eSSudip Mukherjee  *                 ---------------+---+---+---+---+
5181dee67eSSudip Mukherjee  *                 Tx bit L   SDA |   | L |   |   |
5281dee67eSSudip Mukherjee  *                            SCL | L |   | H |   |
5381dee67eSSudip Mukherjee  *                 ---------------+---+---+---+---+
5481dee67eSSudip Mukherjee  *
5581dee67eSSudip Mukherjee  ******************************************************************/
5681dee67eSSudip Mukherjee 
5781dee67eSSudip Mukherjee /* GPIO pins used for this I2C. It ranges from 0 to 63. */
5881dee67eSSudip Mukherjee static unsigned char g_i2cClockGPIO = DEFAULT_I2C_SCL;
5981dee67eSSudip Mukherjee static unsigned char g_i2cDataGPIO = DEFAULT_I2C_SDA;
6081dee67eSSudip Mukherjee 
6181dee67eSSudip Mukherjee /*
6281dee67eSSudip Mukherjee  *  Below is the variable declaration for the GPIO pin register usage
6381dee67eSSudip Mukherjee  *  for the i2c Clock and i2c Data.
6481dee67eSSudip Mukherjee  *
6581dee67eSSudip Mukherjee  *  Note:
6681dee67eSSudip Mukherjee  *      Notice that the GPIO usage for the i2c clock and i2c Data are
6781dee67eSSudip Mukherjee  *      separated. This is to make this code flexible enough when
6881dee67eSSudip Mukherjee  *      two separate GPIO pins for the clock and data are located
6981dee67eSSudip Mukherjee  *      in two different GPIO register set (worst case).
7081dee67eSSudip Mukherjee  */
7181dee67eSSudip Mukherjee 
7281dee67eSSudip Mukherjee /* i2c Clock GPIO Register usage */
7381dee67eSSudip Mukherjee static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX;
7481dee67eSSudip Mukherjee static unsigned long g_i2cClkGPIODataReg = GPIO_DATA;
7581dee67eSSudip Mukherjee static unsigned long g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
7681dee67eSSudip Mukherjee 
7781dee67eSSudip Mukherjee /* i2c Data GPIO Register usage */
7881dee67eSSudip Mukherjee static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX;
7981dee67eSSudip Mukherjee static unsigned long g_i2cDataGPIODataReg = GPIO_DATA;
8081dee67eSSudip Mukherjee static unsigned long g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
8181dee67eSSudip Mukherjee 
8281dee67eSSudip Mukherjee static unsigned char peekIO(unsigned short port,unsigned short index)
8381dee67eSSudip Mukherjee {
8481dee67eSSudip Mukherjee #if defined(__i386__) || defined( __x86_64__)
8581dee67eSSudip Mukherjee 		outb_p(index,port);
8681dee67eSSudip Mukherjee 		return inb_p(port+1);
8781dee67eSSudip Mukherjee #endif
8881dee67eSSudip Mukherjee }
8981dee67eSSudip Mukherjee 
9081dee67eSSudip Mukherjee /*
9181dee67eSSudip Mukherjee  *  This function puts a delay between command
9281dee67eSSudip Mukherjee  */
9381dee67eSSudip Mukherjee static void swI2CWait(void)
9481dee67eSSudip Mukherjee {
9581dee67eSSudip Mukherjee 	/* find a bug:
9681dee67eSSudip Mukherjee 	 * peekIO method works well before suspend/resume
9781dee67eSSudip Mukherjee 	 * but after suspend, peekIO(0x3ce,0x61) & 0x10
9881dee67eSSudip Mukherjee 	 * always be non-zero,which makes the while loop
9981dee67eSSudip Mukherjee 	 * never finish.
10081dee67eSSudip Mukherjee 	 * use non-ultimate for loop below is safe
10181dee67eSSudip Mukherjee 	 * */
10281dee67eSSudip Mukherjee #if 0
10381dee67eSSudip Mukherjee     /* Change wait algorithm to use PCI bus clock,
10481dee67eSSudip Mukherjee        it's more reliable than counter loop ..
10581dee67eSSudip Mukherjee        write 0x61 to 0x3ce and read from 0x3cf
10681dee67eSSudip Mukherjee        */
10781dee67eSSudip Mukherjee 	while(peekIO(0x3ce,0x61) & 0x10);
10881dee67eSSudip Mukherjee #else
10981dee67eSSudip Mukherjee     int i, Temp;
11081dee67eSSudip Mukherjee 
11181dee67eSSudip Mukherjee     for(i=0; i<600; i++)
11281dee67eSSudip Mukherjee     {
11381dee67eSSudip Mukherjee         Temp = i;
11481dee67eSSudip Mukherjee         Temp += i;
11581dee67eSSudip Mukherjee     }
11681dee67eSSudip Mukherjee #endif
11781dee67eSSudip Mukherjee }
11881dee67eSSudip Mukherjee 
11981dee67eSSudip Mukherjee /*
12081dee67eSSudip Mukherjee  *  This function set/reset the SCL GPIO pin
12181dee67eSSudip Mukherjee  *
12281dee67eSSudip Mukherjee  *  Parameters:
12381dee67eSSudip Mukherjee  *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
12481dee67eSSudip Mukherjee  *
12581dee67eSSudip Mukherjee  *  Notes:
12681dee67eSSudip Mukherjee  *      When setting SCL to high, just set the GPIO as input where the pull up
12781dee67eSSudip Mukherjee  *      resistor will pull the signal up. Do not use software to pull up the
12881dee67eSSudip Mukherjee  *      signal because the i2c will fail when other device try to drive the
12981dee67eSSudip Mukherjee  *      signal due to SM50x will drive the signal to always high.
13081dee67eSSudip Mukherjee  */
13181dee67eSSudip Mukherjee void swI2CSCL(unsigned char value)
13281dee67eSSudip Mukherjee {
13381dee67eSSudip Mukherjee     unsigned long ulGPIOData;
13481dee67eSSudip Mukherjee     unsigned long ulGPIODirection;
13581dee67eSSudip Mukherjee 
13681dee67eSSudip Mukherjee     ulGPIODirection = PEEK32(g_i2cClkGPIODataDirReg);
13781dee67eSSudip Mukherjee     if (value)      /* High */
13881dee67eSSudip Mukherjee     {
13981dee67eSSudip Mukherjee         /* Set direction as input. This will automatically pull the signal up. */
14081dee67eSSudip Mukherjee         ulGPIODirection &= ~(1 << g_i2cClockGPIO);
14181dee67eSSudip Mukherjee         POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection);
14281dee67eSSudip Mukherjee     }
14381dee67eSSudip Mukherjee     else            /* Low */
14481dee67eSSudip Mukherjee     {
14581dee67eSSudip Mukherjee         /* Set the signal down */
14681dee67eSSudip Mukherjee         ulGPIOData = PEEK32(g_i2cClkGPIODataReg);
14781dee67eSSudip Mukherjee         ulGPIOData &= ~(1 << g_i2cClockGPIO);
14881dee67eSSudip Mukherjee         POKE32(g_i2cClkGPIODataReg, ulGPIOData);
14981dee67eSSudip Mukherjee 
15081dee67eSSudip Mukherjee         /* Set direction as output */
15181dee67eSSudip Mukherjee         ulGPIODirection |= (1 << g_i2cClockGPIO);
15281dee67eSSudip Mukherjee         POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection);
15381dee67eSSudip Mukherjee     }
15481dee67eSSudip Mukherjee }
15581dee67eSSudip Mukherjee 
15681dee67eSSudip Mukherjee /*
15781dee67eSSudip Mukherjee  *  This function set/reset the SDA GPIO pin
15881dee67eSSudip Mukherjee  *
15981dee67eSSudip Mukherjee  *  Parameters:
16081dee67eSSudip Mukherjee  *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
16181dee67eSSudip Mukherjee  *
16281dee67eSSudip Mukherjee  *  Notes:
16381dee67eSSudip Mukherjee  *      When setting SCL to high, just set the GPIO as input where the pull up
16481dee67eSSudip Mukherjee  *      resistor will pull the signal up. Do not use software to pull up the
16581dee67eSSudip Mukherjee  *      signal because the i2c will fail when other device try to drive the
16681dee67eSSudip Mukherjee  *      signal due to SM50x will drive the signal to always high.
16781dee67eSSudip Mukherjee  */
16881dee67eSSudip Mukherjee void swI2CSDA(unsigned char value)
16981dee67eSSudip Mukherjee {
17081dee67eSSudip Mukherjee     unsigned long ulGPIOData;
17181dee67eSSudip Mukherjee     unsigned long ulGPIODirection;
17281dee67eSSudip Mukherjee 
17381dee67eSSudip Mukherjee     ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg);
17481dee67eSSudip Mukherjee     if (value)      /* High */
17581dee67eSSudip Mukherjee     {
17681dee67eSSudip Mukherjee         /* Set direction as input. This will automatically pull the signal up. */
17781dee67eSSudip Mukherjee         ulGPIODirection &= ~(1 << g_i2cDataGPIO);
17881dee67eSSudip Mukherjee         POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
17981dee67eSSudip Mukherjee     }
18081dee67eSSudip Mukherjee     else            /* Low */
18181dee67eSSudip Mukherjee     {
18281dee67eSSudip Mukherjee         /* Set the signal down */
18381dee67eSSudip Mukherjee         ulGPIOData = PEEK32(g_i2cDataGPIODataReg);
18481dee67eSSudip Mukherjee         ulGPIOData &= ~(1 << g_i2cDataGPIO);
18581dee67eSSudip Mukherjee         POKE32(g_i2cDataGPIODataReg, ulGPIOData);
18681dee67eSSudip Mukherjee 
18781dee67eSSudip Mukherjee         /* Set direction as output */
18881dee67eSSudip Mukherjee         ulGPIODirection |= (1 << g_i2cDataGPIO);
18981dee67eSSudip Mukherjee         POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
19081dee67eSSudip Mukherjee     }
19181dee67eSSudip Mukherjee }
19281dee67eSSudip Mukherjee 
19381dee67eSSudip Mukherjee /*
19481dee67eSSudip Mukherjee  *  This function read the data from the SDA GPIO pin
19581dee67eSSudip Mukherjee  *
19681dee67eSSudip Mukherjee  *  Return Value:
19781dee67eSSudip Mukherjee  *      The SDA data bit sent by the Slave
19881dee67eSSudip Mukherjee  */
19981dee67eSSudip Mukherjee static unsigned char swI2CReadSDA(void)
20081dee67eSSudip Mukherjee {
20181dee67eSSudip Mukherjee     unsigned long ulGPIODirection;
20281dee67eSSudip Mukherjee     unsigned long ulGPIOData;
20381dee67eSSudip Mukherjee 
20481dee67eSSudip Mukherjee     /* Make sure that the direction is input (High) */
20581dee67eSSudip Mukherjee     ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg);
20681dee67eSSudip Mukherjee     if ((ulGPIODirection & (1 << g_i2cDataGPIO)) != (~(1 << g_i2cDataGPIO)))
20781dee67eSSudip Mukherjee     {
20881dee67eSSudip Mukherjee         ulGPIODirection &= ~(1 << g_i2cDataGPIO);
20981dee67eSSudip Mukherjee         POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
21081dee67eSSudip Mukherjee     }
21181dee67eSSudip Mukherjee 
21281dee67eSSudip Mukherjee     /* Now read the SDA line */
21381dee67eSSudip Mukherjee     ulGPIOData = PEEK32(g_i2cDataGPIODataReg);
21481dee67eSSudip Mukherjee     if (ulGPIOData & (1 << g_i2cDataGPIO))
21581dee67eSSudip Mukherjee         return 1;
21681dee67eSSudip Mukherjee     else
21781dee67eSSudip Mukherjee         return 0;
21881dee67eSSudip Mukherjee }
21981dee67eSSudip Mukherjee 
22081dee67eSSudip Mukherjee #pragma optimize( "", off )
22181dee67eSSudip Mukherjee 
22281dee67eSSudip Mukherjee /*
22381dee67eSSudip Mukherjee  *  This function sends ACK signal
22481dee67eSSudip Mukherjee  */
22581dee67eSSudip Mukherjee static void swI2CAck(void)
22681dee67eSSudip Mukherjee {
22781dee67eSSudip Mukherjee     return;  /* Single byte read is ok without it. */
22881dee67eSSudip Mukherjee }
22981dee67eSSudip Mukherjee 
23081dee67eSSudip Mukherjee /*
23181dee67eSSudip Mukherjee  *  This function sends the start command to the slave device
23281dee67eSSudip Mukherjee  */
23381dee67eSSudip Mukherjee void swI2CStart(void)
23481dee67eSSudip Mukherjee {
23581dee67eSSudip Mukherjee     /* Start I2C */
23681dee67eSSudip Mukherjee     swI2CSDA(1);
23781dee67eSSudip Mukherjee     swI2CSCL(1);
23881dee67eSSudip Mukherjee     swI2CSDA(0);
23981dee67eSSudip Mukherjee }
24081dee67eSSudip Mukherjee 
24181dee67eSSudip Mukherjee /*
24281dee67eSSudip Mukherjee  *  This function sends the stop command to the slave device
24381dee67eSSudip Mukherjee  */
24481dee67eSSudip Mukherjee void swI2CStop(void)
24581dee67eSSudip Mukherjee {
24681dee67eSSudip Mukherjee     /* Stop the I2C */
24781dee67eSSudip Mukherjee     swI2CSCL(1);
24881dee67eSSudip Mukherjee     swI2CSDA(0);
24981dee67eSSudip Mukherjee     swI2CSDA(1);
25081dee67eSSudip Mukherjee }
25181dee67eSSudip Mukherjee 
25281dee67eSSudip Mukherjee /*
25381dee67eSSudip Mukherjee  *  This function writes one byte to the slave device
25481dee67eSSudip Mukherjee  *
25581dee67eSSudip Mukherjee  *  Parameters:
25681dee67eSSudip Mukherjee  *      data    - Data to be write to the slave device
25781dee67eSSudip Mukherjee  *
25881dee67eSSudip Mukherjee  *  Return Value:
25981dee67eSSudip Mukherjee  *       0   - Success
26081dee67eSSudip Mukherjee  *      -1   - Fail to write byte
26181dee67eSSudip Mukherjee  */
26281dee67eSSudip Mukherjee long swI2CWriteByte(unsigned char data)
26381dee67eSSudip Mukherjee {
26481dee67eSSudip Mukherjee     unsigned char value = data;
26581dee67eSSudip Mukherjee     int i;
26681dee67eSSudip Mukherjee 
26781dee67eSSudip Mukherjee     /* Sending the data bit by bit */
26881dee67eSSudip Mukherjee     for (i=0; i<8; i++)
26981dee67eSSudip Mukherjee     {
27081dee67eSSudip Mukherjee         /* Set SCL to low */
27181dee67eSSudip Mukherjee         swI2CSCL(0);
27281dee67eSSudip Mukherjee 
27381dee67eSSudip Mukherjee         /* Send data bit */
27481dee67eSSudip Mukherjee         if ((value & 0x80) != 0)
27581dee67eSSudip Mukherjee             swI2CSDA(1);
27681dee67eSSudip Mukherjee         else
27781dee67eSSudip Mukherjee             swI2CSDA(0);
27881dee67eSSudip Mukherjee 
27981dee67eSSudip Mukherjee         swI2CWait();
28081dee67eSSudip Mukherjee 
28181dee67eSSudip Mukherjee         /* Toggle clk line to one */
28281dee67eSSudip Mukherjee         swI2CSCL(1);
28381dee67eSSudip Mukherjee         swI2CWait();
28481dee67eSSudip Mukherjee 
28581dee67eSSudip Mukherjee         /* Shift byte to be sent */
28681dee67eSSudip Mukherjee         value = value << 1;
28781dee67eSSudip Mukherjee     }
28881dee67eSSudip Mukherjee 
28981dee67eSSudip Mukherjee     /* Set the SCL Low and SDA High (prepare to get input) */
29081dee67eSSudip Mukherjee     swI2CSCL(0);
29181dee67eSSudip Mukherjee     swI2CSDA(1);
29281dee67eSSudip Mukherjee 
29381dee67eSSudip Mukherjee     /* Set the SCL High for ack */
29481dee67eSSudip Mukherjee     swI2CWait();
29581dee67eSSudip Mukherjee     swI2CSCL(1);
29681dee67eSSudip Mukherjee     swI2CWait();
29781dee67eSSudip Mukherjee 
29881dee67eSSudip Mukherjee     /* Read SDA, until SDA==0 */
29981dee67eSSudip Mukherjee     for(i=0; i<0xff; i++)
30081dee67eSSudip Mukherjee     {
30181dee67eSSudip Mukherjee         if (!swI2CReadSDA())
30281dee67eSSudip Mukherjee             break;
30381dee67eSSudip Mukherjee 
30481dee67eSSudip Mukherjee         swI2CSCL(0);
30581dee67eSSudip Mukherjee         swI2CWait();
30681dee67eSSudip Mukherjee         swI2CSCL(1);
30781dee67eSSudip Mukherjee         swI2CWait();
30881dee67eSSudip Mukherjee     }
30981dee67eSSudip Mukherjee 
31081dee67eSSudip Mukherjee     /* Set the SCL Low and SDA High */
31181dee67eSSudip Mukherjee     swI2CSCL(0);
31281dee67eSSudip Mukherjee     swI2CSDA(1);
31381dee67eSSudip Mukherjee 
31481dee67eSSudip Mukherjee     if (i<0xff)
31581dee67eSSudip Mukherjee         return 0;
31681dee67eSSudip Mukherjee     else
31781dee67eSSudip Mukherjee         return (-1);
31881dee67eSSudip Mukherjee }
31981dee67eSSudip Mukherjee 
32081dee67eSSudip Mukherjee /*
32181dee67eSSudip Mukherjee  *  This function reads one byte from the slave device
32281dee67eSSudip Mukherjee  *
32381dee67eSSudip Mukherjee  *  Parameters:
32481dee67eSSudip Mukherjee  *      ack    - Flag to indicate either to send the acknowledge
32581dee67eSSudip Mukherjee  *            message to the slave device or not
32681dee67eSSudip Mukherjee  *
32781dee67eSSudip Mukherjee  *  Return Value:
32881dee67eSSudip Mukherjee  *      One byte data read from the Slave device
32981dee67eSSudip Mukherjee  */
33081dee67eSSudip Mukherjee unsigned char swI2CReadByte(unsigned char ack)
33181dee67eSSudip Mukherjee {
33281dee67eSSudip Mukherjee     int i;
33381dee67eSSudip Mukherjee     unsigned char data = 0;
33481dee67eSSudip Mukherjee 
33581dee67eSSudip Mukherjee     for(i=7; i>=0; i--)
33681dee67eSSudip Mukherjee     {
33781dee67eSSudip Mukherjee         /* Set the SCL to Low and SDA to High (Input) */
33881dee67eSSudip Mukherjee         swI2CSCL(0);
33981dee67eSSudip Mukherjee         swI2CSDA(1);
34081dee67eSSudip Mukherjee         swI2CWait();
34181dee67eSSudip Mukherjee 
34281dee67eSSudip Mukherjee         /* Set the SCL High */
34381dee67eSSudip Mukherjee         swI2CSCL(1);
34481dee67eSSudip Mukherjee         swI2CWait();
34581dee67eSSudip Mukherjee 
34681dee67eSSudip Mukherjee         /* Read data bits from SDA */
34781dee67eSSudip Mukherjee         data |= (swI2CReadSDA() << i);
34881dee67eSSudip Mukherjee     }
34981dee67eSSudip Mukherjee 
35081dee67eSSudip Mukherjee     if (ack)
35181dee67eSSudip Mukherjee         swI2CAck();
35281dee67eSSudip Mukherjee 
35381dee67eSSudip Mukherjee     /* Set the SCL Low and SDA High */
35481dee67eSSudip Mukherjee     swI2CSCL(0);
35581dee67eSSudip Mukherjee     swI2CSDA(1);
35681dee67eSSudip Mukherjee 
35781dee67eSSudip Mukherjee     return data;
35881dee67eSSudip Mukherjee }
35981dee67eSSudip Mukherjee #pragma optimize( "", on )
36081dee67eSSudip Mukherjee 
36181dee67eSSudip Mukherjee /*
36281dee67eSSudip Mukherjee  * This function initializes GPIO port for SW I2C communication.
36381dee67eSSudip Mukherjee  *
36481dee67eSSudip Mukherjee  * Parameters:
36581dee67eSSudip Mukherjee  *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
36681dee67eSSudip Mukherjee  *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
36781dee67eSSudip Mukherjee  *
36881dee67eSSudip Mukherjee  * Return Value:
36981dee67eSSudip Mukherjee  *      -1   - Fail to initialize the i2c
37081dee67eSSudip Mukherjee  *       0   - Success
37181dee67eSSudip Mukherjee  */
37281dee67eSSudip Mukherjee long swI2CInit_SM750LE(
37381dee67eSSudip Mukherjee     unsigned char i2cClkGPIO,
37481dee67eSSudip Mukherjee     unsigned char i2cDataGPIO
37581dee67eSSudip Mukherjee )
37681dee67eSSudip Mukherjee {
37781dee67eSSudip Mukherjee     int i;
37881dee67eSSudip Mukherjee 
37981dee67eSSudip Mukherjee     /* Initialize the GPIO pin for the i2c Clock Register */
38081dee67eSSudip Mukherjee     g_i2cClkGPIODataReg = GPIO_DATA_SM750LE;
38181dee67eSSudip Mukherjee     g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
38281dee67eSSudip Mukherjee 
38381dee67eSSudip Mukherjee     /* Initialize the Clock GPIO Offset */
38481dee67eSSudip Mukherjee     g_i2cClockGPIO = i2cClkGPIO;
38581dee67eSSudip Mukherjee 
38681dee67eSSudip Mukherjee     /* Initialize the GPIO pin for the i2c Data Register */
38781dee67eSSudip Mukherjee     g_i2cDataGPIODataReg = GPIO_DATA_SM750LE;
38881dee67eSSudip Mukherjee     g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
38981dee67eSSudip Mukherjee 
39081dee67eSSudip Mukherjee     /* Initialize the Data GPIO Offset */
39181dee67eSSudip Mukherjee     g_i2cDataGPIO = i2cDataGPIO;
39281dee67eSSudip Mukherjee 
39381dee67eSSudip Mukherjee     /* Note that SM750LE don't have GPIO MUX and power is always on */
39481dee67eSSudip Mukherjee 
39581dee67eSSudip Mukherjee     /* Clear the i2c lines. */
39681dee67eSSudip Mukherjee     for(i=0; i<9; i++)
39781dee67eSSudip Mukherjee         swI2CStop();
39881dee67eSSudip Mukherjee 
39981dee67eSSudip Mukherjee     return 0;
40081dee67eSSudip Mukherjee }
40181dee67eSSudip Mukherjee 
40281dee67eSSudip Mukherjee /*
40381dee67eSSudip Mukherjee  * This function initializes the i2c attributes and bus
40481dee67eSSudip Mukherjee  *
40581dee67eSSudip Mukherjee  * Parameters:
40681dee67eSSudip Mukherjee  *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
40781dee67eSSudip Mukherjee  *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
40881dee67eSSudip Mukherjee  *
40981dee67eSSudip Mukherjee  * Return Value:
41081dee67eSSudip Mukherjee  *      -1   - Fail to initialize the i2c
41181dee67eSSudip Mukherjee  *       0   - Success
41281dee67eSSudip Mukherjee  */
41381dee67eSSudip Mukherjee long swI2CInit(
41481dee67eSSudip Mukherjee     unsigned char i2cClkGPIO,
41581dee67eSSudip Mukherjee     unsigned char i2cDataGPIO
41681dee67eSSudip Mukherjee )
41781dee67eSSudip Mukherjee {
41881dee67eSSudip Mukherjee     int i;
41981dee67eSSudip Mukherjee 
42081dee67eSSudip Mukherjee     /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */
42181dee67eSSudip Mukherjee     if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31))
42281dee67eSSudip Mukherjee         return (-1);
42381dee67eSSudip Mukherjee 
42481dee67eSSudip Mukherjee     if (getChipType() == SM750LE)
42581dee67eSSudip Mukherjee         return( swI2CInit_SM750LE(i2cClkGPIO, i2cDataGPIO) );
42681dee67eSSudip Mukherjee 
42781dee67eSSudip Mukherjee     /* Initialize the GPIO pin for the i2c Clock Register */
42881dee67eSSudip Mukherjee     g_i2cClkGPIOMuxReg = GPIO_MUX;
42981dee67eSSudip Mukherjee     g_i2cClkGPIODataReg = GPIO_DATA;
43081dee67eSSudip Mukherjee     g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
43181dee67eSSudip Mukherjee 
43281dee67eSSudip Mukherjee     /* Initialize the Clock GPIO Offset */
43381dee67eSSudip Mukherjee     g_i2cClockGPIO = i2cClkGPIO;
43481dee67eSSudip Mukherjee 
43581dee67eSSudip Mukherjee     /* Initialize the GPIO pin for the i2c Data Register */
43681dee67eSSudip Mukherjee     g_i2cDataGPIOMuxReg = GPIO_MUX;
43781dee67eSSudip Mukherjee     g_i2cDataGPIODataReg = GPIO_DATA;
43881dee67eSSudip Mukherjee     g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
43981dee67eSSudip Mukherjee 
44081dee67eSSudip Mukherjee     /* Initialize the Data GPIO Offset */
44181dee67eSSudip Mukherjee     g_i2cDataGPIO = i2cDataGPIO;
44281dee67eSSudip Mukherjee 
44381dee67eSSudip Mukherjee     /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
44481dee67eSSudip Mukherjee     POKE32(g_i2cClkGPIOMuxReg,
44581dee67eSSudip Mukherjee                       PEEK32(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO));
44681dee67eSSudip Mukherjee     POKE32(g_i2cDataGPIOMuxReg,
44781dee67eSSudip Mukherjee                       PEEK32(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO));
44881dee67eSSudip Mukherjee 
44981dee67eSSudip Mukherjee     /* Enable GPIO power */
45081dee67eSSudip Mukherjee     enableGPIO(1);
45181dee67eSSudip Mukherjee 
45281dee67eSSudip Mukherjee     /* Clear the i2c lines. */
45381dee67eSSudip Mukherjee     for(i=0; i<9; i++)
45481dee67eSSudip Mukherjee         swI2CStop();
45581dee67eSSudip Mukherjee 
45681dee67eSSudip Mukherjee     return 0;
45781dee67eSSudip Mukherjee }
45881dee67eSSudip Mukherjee 
45981dee67eSSudip Mukherjee /*
46081dee67eSSudip Mukherjee  *  This function reads the slave device's register
46181dee67eSSudip Mukherjee  *
46281dee67eSSudip Mukherjee  *  Parameters:
46381dee67eSSudip Mukherjee  *      deviceAddress   - i2c Slave device address which register
46481dee67eSSudip Mukherjee  *                        to be read from
46581dee67eSSudip Mukherjee  *      registerIndex   - Slave device's register to be read
46681dee67eSSudip Mukherjee  *
46781dee67eSSudip Mukherjee  *  Return Value:
46881dee67eSSudip Mukherjee  *      Register value
46981dee67eSSudip Mukherjee  */
47081dee67eSSudip Mukherjee unsigned char swI2CReadReg(
47181dee67eSSudip Mukherjee     unsigned char deviceAddress,
47281dee67eSSudip Mukherjee     unsigned char registerIndex
47381dee67eSSudip Mukherjee )
47481dee67eSSudip Mukherjee {
47581dee67eSSudip Mukherjee     unsigned char data;
47681dee67eSSudip Mukherjee 
47781dee67eSSudip Mukherjee     /* Send the Start signal */
47881dee67eSSudip Mukherjee     swI2CStart();
47981dee67eSSudip Mukherjee 
48081dee67eSSudip Mukherjee     /* Send the device address */
48181dee67eSSudip Mukherjee     swI2CWriteByte(deviceAddress);
48281dee67eSSudip Mukherjee 
48381dee67eSSudip Mukherjee     /* Send the register index */
48481dee67eSSudip Mukherjee     swI2CWriteByte(registerIndex);
48581dee67eSSudip Mukherjee 
48681dee67eSSudip Mukherjee     /* Get the bus again and get the data from the device read address */
48781dee67eSSudip Mukherjee     swI2CStart();
48881dee67eSSudip Mukherjee     swI2CWriteByte(deviceAddress + 1);
48981dee67eSSudip Mukherjee     data = swI2CReadByte(1);
49081dee67eSSudip Mukherjee 
49181dee67eSSudip Mukherjee     /* Stop swI2C and release the bus */
49281dee67eSSudip Mukherjee     swI2CStop();
49381dee67eSSudip Mukherjee 
49481dee67eSSudip Mukherjee     return data;
49581dee67eSSudip Mukherjee }
49681dee67eSSudip Mukherjee 
49781dee67eSSudip Mukherjee /*
49881dee67eSSudip Mukherjee  *  This function writes a value to the slave device's register
49981dee67eSSudip Mukherjee  *
50081dee67eSSudip Mukherjee  *  Parameters:
50181dee67eSSudip Mukherjee  *      deviceAddress   - i2c Slave device address which register
50281dee67eSSudip Mukherjee  *                        to be written
50381dee67eSSudip Mukherjee  *      registerIndex   - Slave device's register to be written
50481dee67eSSudip Mukherjee  *      data            - Data to be written to the register
50581dee67eSSudip Mukherjee  *
50681dee67eSSudip Mukherjee  *  Result:
50781dee67eSSudip Mukherjee  *          0   - Success
50881dee67eSSudip Mukherjee  *         -1   - Fail
50981dee67eSSudip Mukherjee  */
51081dee67eSSudip Mukherjee long swI2CWriteReg(
51181dee67eSSudip Mukherjee     unsigned char deviceAddress,
51281dee67eSSudip Mukherjee     unsigned char registerIndex,
51381dee67eSSudip Mukherjee     unsigned char data
51481dee67eSSudip Mukherjee )
51581dee67eSSudip Mukherjee {
51681dee67eSSudip Mukherjee     long returnValue = 0;
51781dee67eSSudip Mukherjee 
51881dee67eSSudip Mukherjee     /* Send the Start signal */
51981dee67eSSudip Mukherjee     swI2CStart();
52081dee67eSSudip Mukherjee 
52181dee67eSSudip Mukherjee     /* Send the device address and read the data. All should return success
52281dee67eSSudip Mukherjee        in order for the writing processed to be successful
52381dee67eSSudip Mukherjee      */
52481dee67eSSudip Mukherjee     if ((swI2CWriteByte(deviceAddress) != 0) ||
52581dee67eSSudip Mukherjee         (swI2CWriteByte(registerIndex) != 0) ||
52681dee67eSSudip Mukherjee         (swI2CWriteByte(data) != 0))
52781dee67eSSudip Mukherjee     {
52881dee67eSSudip Mukherjee         returnValue = -1;
52981dee67eSSudip Mukherjee     }
53081dee67eSSudip Mukherjee 
53181dee67eSSudip Mukherjee     /* Stop i2c and release the bus */
53281dee67eSSudip Mukherjee     swI2CStop();
53381dee67eSSudip Mukherjee 
53481dee67eSSudip Mukherjee     return returnValue;
53581dee67eSSudip Mukherjee }
536