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 #pragma optimize( "", off )
221 
222 /*
223  *  This function sends ACK signal
224  */
225 static void swI2CAck(void)
226 {
227     return;  /* Single byte read is ok without it. */
228 }
229 
230 /*
231  *  This function sends the start command to the slave device
232  */
233 void swI2CStart(void)
234 {
235     /* Start I2C */
236     swI2CSDA(1);
237     swI2CSCL(1);
238     swI2CSDA(0);
239 }
240 
241 /*
242  *  This function sends the stop command to the slave device
243  */
244 void swI2CStop(void)
245 {
246     /* Stop the I2C */
247     swI2CSCL(1);
248     swI2CSDA(0);
249     swI2CSDA(1);
250 }
251 
252 /*
253  *  This function writes one byte to the slave device
254  *
255  *  Parameters:
256  *      data    - Data to be write to the slave device
257  *
258  *  Return Value:
259  *       0   - Success
260  *      -1   - Fail to write byte
261  */
262 long swI2CWriteByte(unsigned char data)
263 {
264     unsigned char value = data;
265     int i;
266 
267     /* Sending the data bit by bit */
268     for (i=0; i<8; i++)
269     {
270         /* Set SCL to low */
271         swI2CSCL(0);
272 
273         /* Send data bit */
274         if ((value & 0x80) != 0)
275             swI2CSDA(1);
276         else
277             swI2CSDA(0);
278 
279         swI2CWait();
280 
281         /* Toggle clk line to one */
282         swI2CSCL(1);
283         swI2CWait();
284 
285         /* Shift byte to be sent */
286         value = value << 1;
287     }
288 
289     /* Set the SCL Low and SDA High (prepare to get input) */
290     swI2CSCL(0);
291     swI2CSDA(1);
292 
293     /* Set the SCL High for ack */
294     swI2CWait();
295     swI2CSCL(1);
296     swI2CWait();
297 
298     /* Read SDA, until SDA==0 */
299     for(i=0; i<0xff; i++)
300     {
301         if (!swI2CReadSDA())
302             break;
303 
304         swI2CSCL(0);
305         swI2CWait();
306         swI2CSCL(1);
307         swI2CWait();
308     }
309 
310     /* Set the SCL Low and SDA High */
311     swI2CSCL(0);
312     swI2CSDA(1);
313 
314     if (i<0xff)
315         return 0;
316     else
317         return (-1);
318 }
319 
320 /*
321  *  This function reads one byte from the slave device
322  *
323  *  Parameters:
324  *      ack    - Flag to indicate either to send the acknowledge
325  *            message to the slave device or not
326  *
327  *  Return Value:
328  *      One byte data read from the Slave device
329  */
330 unsigned char swI2CReadByte(unsigned char ack)
331 {
332     int i;
333     unsigned char data = 0;
334 
335     for(i=7; i>=0; i--)
336     {
337         /* Set the SCL to Low and SDA to High (Input) */
338         swI2CSCL(0);
339         swI2CSDA(1);
340         swI2CWait();
341 
342         /* Set the SCL High */
343         swI2CSCL(1);
344         swI2CWait();
345 
346         /* Read data bits from SDA */
347         data |= (swI2CReadSDA() << i);
348     }
349 
350     if (ack)
351         swI2CAck();
352 
353     /* Set the SCL Low and SDA High */
354     swI2CSCL(0);
355     swI2CSDA(1);
356 
357     return data;
358 }
359 #pragma optimize( "", on )
360 
361 /*
362  * This function initializes GPIO port for SW I2C communication.
363  *
364  * Parameters:
365  *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
366  *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
367  *
368  * Return Value:
369  *      -1   - Fail to initialize the i2c
370  *       0   - Success
371  */
372 long swI2CInit_SM750LE(
373     unsigned char i2cClkGPIO,
374     unsigned char i2cDataGPIO
375 )
376 {
377     int i;
378 
379     /* Initialize the GPIO pin for the i2c Clock Register */
380     g_i2cClkGPIODataReg = GPIO_DATA_SM750LE;
381     g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
382 
383     /* Initialize the Clock GPIO Offset */
384     g_i2cClockGPIO = i2cClkGPIO;
385 
386     /* Initialize the GPIO pin for the i2c Data Register */
387     g_i2cDataGPIODataReg = GPIO_DATA_SM750LE;
388     g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
389 
390     /* Initialize the Data GPIO Offset */
391     g_i2cDataGPIO = i2cDataGPIO;
392 
393     /* Note that SM750LE don't have GPIO MUX and power is always on */
394 
395     /* Clear the i2c lines. */
396     for(i=0; i<9; i++)
397         swI2CStop();
398 
399     return 0;
400 }
401 
402 /*
403  * This function initializes the i2c attributes and bus
404  *
405  * Parameters:
406  *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
407  *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
408  *
409  * Return Value:
410  *      -1   - Fail to initialize the i2c
411  *       0   - Success
412  */
413 long swI2CInit(
414     unsigned char i2cClkGPIO,
415     unsigned char i2cDataGPIO
416 )
417 {
418     int i;
419 
420     /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */
421     if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31))
422         return (-1);
423 
424     if (getChipType() == SM750LE)
425         return( swI2CInit_SM750LE(i2cClkGPIO, i2cDataGPIO) );
426 
427     /* Initialize the GPIO pin for the i2c Clock Register */
428     g_i2cClkGPIOMuxReg = GPIO_MUX;
429     g_i2cClkGPIODataReg = GPIO_DATA;
430     g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
431 
432     /* Initialize the Clock GPIO Offset */
433     g_i2cClockGPIO = i2cClkGPIO;
434 
435     /* Initialize the GPIO pin for the i2c Data Register */
436     g_i2cDataGPIOMuxReg = GPIO_MUX;
437     g_i2cDataGPIODataReg = GPIO_DATA;
438     g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
439 
440     /* Initialize the Data GPIO Offset */
441     g_i2cDataGPIO = i2cDataGPIO;
442 
443     /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
444     POKE32(g_i2cClkGPIOMuxReg,
445                       PEEK32(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO));
446     POKE32(g_i2cDataGPIOMuxReg,
447                       PEEK32(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO));
448 
449     /* Enable GPIO power */
450     enableGPIO(1);
451 
452     /* Clear the i2c lines. */
453     for(i=0; i<9; i++)
454         swI2CStop();
455 
456     return 0;
457 }
458 
459 /*
460  *  This function reads the slave device's register
461  *
462  *  Parameters:
463  *      deviceAddress   - i2c Slave device address which register
464  *                        to be read from
465  *      registerIndex   - Slave device's register to be read
466  *
467  *  Return Value:
468  *      Register value
469  */
470 unsigned char swI2CReadReg(
471     unsigned char deviceAddress,
472     unsigned char registerIndex
473 )
474 {
475     unsigned char data;
476 
477     /* Send the Start signal */
478     swI2CStart();
479 
480     /* Send the device address */
481     swI2CWriteByte(deviceAddress);
482 
483     /* Send the register index */
484     swI2CWriteByte(registerIndex);
485 
486     /* Get the bus again and get the data from the device read address */
487     swI2CStart();
488     swI2CWriteByte(deviceAddress + 1);
489     data = swI2CReadByte(1);
490 
491     /* Stop swI2C and release the bus */
492     swI2CStop();
493 
494     return data;
495 }
496 
497 /*
498  *  This function writes a value to the slave device's register
499  *
500  *  Parameters:
501  *      deviceAddress   - i2c Slave device address which register
502  *                        to be written
503  *      registerIndex   - Slave device's register to be written
504  *      data            - Data to be written to the register
505  *
506  *  Result:
507  *          0   - Success
508  *         -1   - Fail
509  */
510 long swI2CWriteReg(
511     unsigned char deviceAddress,
512     unsigned char registerIndex,
513     unsigned char data
514 )
515 {
516     long returnValue = 0;
517 
518     /* Send the Start signal */
519     swI2CStart();
520 
521     /* Send the device address and read the data. All should return success
522        in order for the writing processed to be successful
523      */
524     if ((swI2CWriteByte(deviceAddress) != 0) ||
525         (swI2CWriteByte(registerIndex) != 0) ||
526         (swI2CWriteByte(data) != 0))
527     {
528         returnValue = -1;
529     }
530 
531     /* Stop i2c and release the bus */
532     swI2CStop();
533 
534     return returnValue;
535 }
536