1 /*******************************************************************
2 *
3 *         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
4 *
5 *  All rights are reserved. Reproduction or in part is prohibited
6 *  without the written consent of the copyright owner.
7 *
8 *  swi2c.c --- SM750/SM718 DDK
9 *  This file contains the source code for I2C using software
10 *  implementation.
11 *
12 *******************************************************************/
13 #include "ddk750_help.h"
14 #include "ddk750_reg.h"
15 #include "ddk750_swi2c.h"
16 #include "ddk750_power.h"
17 
18 
19 /*******************************************************************
20  * I2C Software Master Driver:
21  * ===========================
22  * Each i2c cycle is split into 4 sections. Each of these section marks
23  * a point in time where the SCL or SDA may be changed.
24  *
25  * 1 Cycle == |  Section I. |  Section 2. |  Section 3. |  Section 4. |
26  *            +-------------+-------------+-------------+-------------+
27  *            | SCL set LOW |SCL no change| SCL set HIGH|SCL no change|
28  *
29  *                                          ____________ _____________
30  * SCL == XXXX _____________ ____________ /
31  *
32  * I.e. the SCL may only be changed in section 1. and section 3. while
33  * the SDA may only be changed in section 2. and section 4. The table
34  * below gives the changes for these 2 lines in the varios sections.
35  *
36  * Section changes Table:
37  * ======================
38  * blank = no change, L = set bit LOW, H = set bit HIGH
39  *
40  *                                | 1.| 2.| 3.| 4.|
41  *                 ---------------+---+---+---+---+
42  *                 Tx Start   SDA |   | H |   | L |
43  *                            SCL | L |   | H |   |
44  *                 ---------------+---+---+---+---+
45  *                 Tx Stop    SDA |   | L |   | H |
46  *                            SCL | L |   | H |   |
47  *                 ---------------+---+---+---+---+
48  *                 Tx bit H   SDA |   | H |   |   |
49  *                            SCL | L |   | H |   |
50  *                 ---------------+---+---+---+---+
51  *                 Tx bit L   SDA |   | L |   |   |
52  *                            SCL | L |   | H |   |
53  *                 ---------------+---+---+---+---+
54  *
55  ******************************************************************/
56 
57 /* GPIO pins used for this I2C. It ranges from 0 to 63. */
58 static unsigned char g_i2cClockGPIO = DEFAULT_I2C_SCL;
59 static unsigned char g_i2cDataGPIO = DEFAULT_I2C_SDA;
60 
61 /*
62  *  Below is the variable declaration for the GPIO pin register usage
63  *  for the i2c Clock and i2c Data.
64  *
65  *  Note:
66  *      Notice that the GPIO usage for the i2c clock and i2c Data are
67  *      separated. This is to make this code flexible enough when
68  *      two separate GPIO pins for the clock and data are located
69  *      in two different GPIO register set (worst case).
70  */
71 
72 /* i2c Clock GPIO Register usage */
73 static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX;
74 static unsigned long g_i2cClkGPIODataReg = GPIO_DATA;
75 static unsigned long g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
76 
77 /* i2c Data GPIO Register usage */
78 static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX;
79 static unsigned long g_i2cDataGPIODataReg = GPIO_DATA;
80 static unsigned long g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
81 
82 static unsigned char peekIO(unsigned short port,unsigned short index)
83 {
84 #if defined(__i386__) || defined( __x86_64__)
85 		outb_p(index,port);
86 		return inb_p(port+1);
87 #endif
88 }
89 
90 /*
91  *  This function puts a delay between command
92  */
93 static void swI2CWait(void)
94 {
95 	/* find a bug:
96 	 * peekIO method works well before suspend/resume
97 	 * but after suspend, peekIO(0x3ce,0x61) & 0x10
98 	 * always be non-zero,which makes the while loop
99 	 * never finish.
100 	 * use non-ultimate for loop below is safe
101 	 * */
102 #if 0
103     /* Change wait algorithm to use PCI bus clock,
104        it's more reliable than counter loop ..
105        write 0x61 to 0x3ce and read from 0x3cf
106        */
107 	while(peekIO(0x3ce,0x61) & 0x10);
108 #else
109     int i, Temp;
110 
111     for(i=0; i<600; i++)
112     {
113         Temp = i;
114         Temp += i;
115     }
116 #endif
117 }
118 
119 /*
120  *  This function set/reset the SCL GPIO pin
121  *
122  *  Parameters:
123  *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
124  *
125  *  Notes:
126  *      When setting SCL to high, just set the GPIO as input where the pull up
127  *      resistor will pull the signal up. Do not use software to pull up the
128  *      signal because the i2c will fail when other device try to drive the
129  *      signal due to SM50x will drive the signal to always high.
130  */
131 void swI2CSCL(unsigned char value)
132 {
133     unsigned long ulGPIOData;
134     unsigned long ulGPIODirection;
135 
136     ulGPIODirection = PEEK32(g_i2cClkGPIODataDirReg);
137     if (value)      /* High */
138     {
139         /* Set direction as input. This will automatically pull the signal up. */
140         ulGPIODirection &= ~(1 << g_i2cClockGPIO);
141         POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection);
142     }
143     else            /* Low */
144     {
145         /* Set the signal down */
146         ulGPIOData = PEEK32(g_i2cClkGPIODataReg);
147         ulGPIOData &= ~(1 << g_i2cClockGPIO);
148         POKE32(g_i2cClkGPIODataReg, ulGPIOData);
149 
150         /* Set direction as output */
151         ulGPIODirection |= (1 << g_i2cClockGPIO);
152         POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection);
153     }
154 }
155 
156 /*
157  *  This function set/reset the SDA GPIO pin
158  *
159  *  Parameters:
160  *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
161  *
162  *  Notes:
163  *      When setting SCL to high, just set the GPIO as input where the pull up
164  *      resistor will pull the signal up. Do not use software to pull up the
165  *      signal because the i2c will fail when other device try to drive the
166  *      signal due to SM50x will drive the signal to always high.
167  */
168 void swI2CSDA(unsigned char value)
169 {
170     unsigned long ulGPIOData;
171     unsigned long ulGPIODirection;
172 
173     ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg);
174     if (value)      /* High */
175     {
176         /* Set direction as input. This will automatically pull the signal up. */
177         ulGPIODirection &= ~(1 << g_i2cDataGPIO);
178         POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
179     }
180     else            /* Low */
181     {
182         /* Set the signal down */
183         ulGPIOData = PEEK32(g_i2cDataGPIODataReg);
184         ulGPIOData &= ~(1 << g_i2cDataGPIO);
185         POKE32(g_i2cDataGPIODataReg, ulGPIOData);
186 
187         /* Set direction as output */
188         ulGPIODirection |= (1 << g_i2cDataGPIO);
189         POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
190     }
191 }
192 
193 /*
194  *  This function read the data from the SDA GPIO pin
195  *
196  *  Return Value:
197  *      The SDA data bit sent by the Slave
198  */
199 static unsigned char swI2CReadSDA(void)
200 {
201     unsigned long ulGPIODirection;
202     unsigned long ulGPIOData;
203 
204     /* Make sure that the direction is input (High) */
205     ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg);
206     if ((ulGPIODirection & (1 << g_i2cDataGPIO)) != (~(1 << g_i2cDataGPIO)))
207     {
208         ulGPIODirection &= ~(1 << g_i2cDataGPIO);
209         POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
210     }
211 
212     /* Now read the SDA line */
213     ulGPIOData = PEEK32(g_i2cDataGPIODataReg);
214     if (ulGPIOData & (1 << g_i2cDataGPIO))
215         return 1;
216     else
217         return 0;
218 }
219 
220 /*
221  *  This function sends ACK signal
222  */
223 static void swI2CAck(void)
224 {
225     return;  /* Single byte read is ok without it. */
226 }
227 
228 /*
229  *  This function sends the start command to the slave device
230  */
231 void swI2CStart(void)
232 {
233     /* Start I2C */
234     swI2CSDA(1);
235     swI2CSCL(1);
236     swI2CSDA(0);
237 }
238 
239 /*
240  *  This function sends the stop command to the slave device
241  */
242 void swI2CStop(void)
243 {
244     /* Stop the I2C */
245     swI2CSCL(1);
246     swI2CSDA(0);
247     swI2CSDA(1);
248 }
249 
250 /*
251  *  This function writes one byte to the slave device
252  *
253  *  Parameters:
254  *      data    - Data to be write to the slave device
255  *
256  *  Return Value:
257  *       0   - Success
258  *      -1   - Fail to write byte
259  */
260 long swI2CWriteByte(unsigned char data)
261 {
262     unsigned char value = data;
263     int i;
264 
265     /* Sending the data bit by bit */
266     for (i=0; i<8; i++)
267     {
268         /* Set SCL to low */
269         swI2CSCL(0);
270 
271         /* Send data bit */
272         if ((value & 0x80) != 0)
273             swI2CSDA(1);
274         else
275             swI2CSDA(0);
276 
277         swI2CWait();
278 
279         /* Toggle clk line to one */
280         swI2CSCL(1);
281         swI2CWait();
282 
283         /* Shift byte to be sent */
284         value = value << 1;
285     }
286 
287     /* Set the SCL Low and SDA High (prepare to get input) */
288     swI2CSCL(0);
289     swI2CSDA(1);
290 
291     /* Set the SCL High for ack */
292     swI2CWait();
293     swI2CSCL(1);
294     swI2CWait();
295 
296     /* Read SDA, until SDA==0 */
297     for(i=0; i<0xff; i++)
298     {
299         if (!swI2CReadSDA())
300             break;
301 
302         swI2CSCL(0);
303         swI2CWait();
304         swI2CSCL(1);
305         swI2CWait();
306     }
307 
308     /* Set the SCL Low and SDA High */
309     swI2CSCL(0);
310     swI2CSDA(1);
311 
312     if (i<0xff)
313         return 0;
314     else
315         return (-1);
316 }
317 
318 /*
319  *  This function reads one byte from the slave device
320  *
321  *  Parameters:
322  *      ack    - Flag to indicate either to send the acknowledge
323  *            message to the slave device or not
324  *
325  *  Return Value:
326  *      One byte data read from the Slave device
327  */
328 unsigned char swI2CReadByte(unsigned char ack)
329 {
330     int i;
331     unsigned char data = 0;
332 
333     for(i=7; i>=0; i--)
334     {
335         /* Set the SCL to Low and SDA to High (Input) */
336         swI2CSCL(0);
337         swI2CSDA(1);
338         swI2CWait();
339 
340         /* Set the SCL High */
341         swI2CSCL(1);
342         swI2CWait();
343 
344         /* Read data bits from SDA */
345         data |= (swI2CReadSDA() << i);
346     }
347 
348     if (ack)
349         swI2CAck();
350 
351     /* Set the SCL Low and SDA High */
352     swI2CSCL(0);
353     swI2CSDA(1);
354 
355     return data;
356 }
357 
358 /*
359  * This function initializes GPIO port for SW I2C communication.
360  *
361  * Parameters:
362  *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
363  *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
364  *
365  * Return Value:
366  *      -1   - Fail to initialize the i2c
367  *       0   - Success
368  */
369 long swI2CInit_SM750LE(
370     unsigned char i2cClkGPIO,
371     unsigned char i2cDataGPIO
372 )
373 {
374     int i;
375 
376     /* Initialize the GPIO pin for the i2c Clock Register */
377     g_i2cClkGPIODataReg = GPIO_DATA_SM750LE;
378     g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
379 
380     /* Initialize the Clock GPIO Offset */
381     g_i2cClockGPIO = i2cClkGPIO;
382 
383     /* Initialize the GPIO pin for the i2c Data Register */
384     g_i2cDataGPIODataReg = GPIO_DATA_SM750LE;
385     g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
386 
387     /* Initialize the Data GPIO Offset */
388     g_i2cDataGPIO = i2cDataGPIO;
389 
390     /* Note that SM750LE don't have GPIO MUX and power is always on */
391 
392     /* Clear the i2c lines. */
393     for(i=0; i<9; i++)
394         swI2CStop();
395 
396     return 0;
397 }
398 
399 /*
400  * This function initializes the i2c attributes and bus
401  *
402  * Parameters:
403  *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
404  *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
405  *
406  * Return Value:
407  *      -1   - Fail to initialize the i2c
408  *       0   - Success
409  */
410 long swI2CInit(
411     unsigned char i2cClkGPIO,
412     unsigned char i2cDataGPIO
413 )
414 {
415     int i;
416 
417     /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */
418     if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31))
419         return (-1);
420 
421     if (getChipType() == SM750LE)
422         return( swI2CInit_SM750LE(i2cClkGPIO, i2cDataGPIO) );
423 
424     /* Initialize the GPIO pin for the i2c Clock Register */
425     g_i2cClkGPIOMuxReg = GPIO_MUX;
426     g_i2cClkGPIODataReg = GPIO_DATA;
427     g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
428 
429     /* Initialize the Clock GPIO Offset */
430     g_i2cClockGPIO = i2cClkGPIO;
431 
432     /* Initialize the GPIO pin for the i2c Data Register */
433     g_i2cDataGPIOMuxReg = GPIO_MUX;
434     g_i2cDataGPIODataReg = GPIO_DATA;
435     g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
436 
437     /* Initialize the Data GPIO Offset */
438     g_i2cDataGPIO = i2cDataGPIO;
439 
440     /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
441     POKE32(g_i2cClkGPIOMuxReg,
442                       PEEK32(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO));
443     POKE32(g_i2cDataGPIOMuxReg,
444                       PEEK32(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO));
445 
446     /* Enable GPIO power */
447     enableGPIO(1);
448 
449     /* Clear the i2c lines. */
450     for(i=0; i<9; i++)
451         swI2CStop();
452 
453     return 0;
454 }
455 
456 /*
457  *  This function reads the slave device's register
458  *
459  *  Parameters:
460  *      deviceAddress   - i2c Slave device address which register
461  *                        to be read from
462  *      registerIndex   - Slave device's register to be read
463  *
464  *  Return Value:
465  *      Register value
466  */
467 unsigned char swI2CReadReg(
468     unsigned char deviceAddress,
469     unsigned char registerIndex
470 )
471 {
472     unsigned char data;
473 
474     /* Send the Start signal */
475     swI2CStart();
476 
477     /* Send the device address */
478     swI2CWriteByte(deviceAddress);
479 
480     /* Send the register index */
481     swI2CWriteByte(registerIndex);
482 
483     /* Get the bus again and get the data from the device read address */
484     swI2CStart();
485     swI2CWriteByte(deviceAddress + 1);
486     data = swI2CReadByte(1);
487 
488     /* Stop swI2C and release the bus */
489     swI2CStop();
490 
491     return data;
492 }
493 
494 /*
495  *  This function writes a value to the slave device's register
496  *
497  *  Parameters:
498  *      deviceAddress   - i2c Slave device address which register
499  *                        to be written
500  *      registerIndex   - Slave device's register to be written
501  *      data            - Data to be written to the register
502  *
503  *  Result:
504  *          0   - Success
505  *         -1   - Fail
506  */
507 long swI2CWriteReg(
508     unsigned char deviceAddress,
509     unsigned char registerIndex,
510     unsigned char data
511 )
512 {
513     long returnValue = 0;
514 
515     /* Send the Start signal */
516     swI2CStart();
517 
518     /* Send the device address and read the data. All should return success
519        in order for the writing processed to be successful
520      */
521     if ((swI2CWriteByte(deviceAddress) != 0) ||
522         (swI2CWriteByte(registerIndex) != 0) ||
523         (swI2CWriteByte(data) != 0))
524     {
525         returnValue = -1;
526     }
527 
528     /* Stop i2c and release the bus */
529     swI2CStop();
530 
531     return returnValue;
532 }
533