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 /*
83  *  This function puts a delay between command
84  */
85 static void swI2CWait(void)
86 {
87 	/* find a bug:
88 	 * peekIO method works well before suspend/resume
89 	 * but after suspend, peekIO(0x3ce,0x61) & 0x10
90 	 * always be non-zero,which makes the while loop
91 	 * never finish.
92 	 * use non-ultimate for loop below is safe
93 	 * */
94 #if 0
95     /* Change wait algorithm to use PCI bus clock,
96        it's more reliable than counter loop ..
97        write 0x61 to 0x3ce and read from 0x3cf
98        */
99 	while(peekIO(0x3ce,0x61) & 0x10);
100 #else
101     int i, Temp;
102 
103     for(i=0; i<600; i++)
104     {
105         Temp = i;
106         Temp += i;
107     }
108 #endif
109 }
110 
111 /*
112  *  This function set/reset the SCL GPIO pin
113  *
114  *  Parameters:
115  *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
116  *
117  *  Notes:
118  *      When setting SCL to high, just set the GPIO as input where the pull up
119  *      resistor will pull the signal up. Do not use software to pull up the
120  *      signal because the i2c will fail when other device try to drive the
121  *      signal due to SM50x will drive the signal to always high.
122  */
123 void swI2CSCL(unsigned char value)
124 {
125     unsigned long ulGPIOData;
126     unsigned long ulGPIODirection;
127 
128     ulGPIODirection = PEEK32(g_i2cClkGPIODataDirReg);
129     if (value)      /* High */
130     {
131         /* Set direction as input. This will automatically pull the signal up. */
132         ulGPIODirection &= ~(1 << g_i2cClockGPIO);
133         POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection);
134     }
135     else            /* Low */
136     {
137         /* Set the signal down */
138         ulGPIOData = PEEK32(g_i2cClkGPIODataReg);
139         ulGPIOData &= ~(1 << g_i2cClockGPIO);
140         POKE32(g_i2cClkGPIODataReg, ulGPIOData);
141 
142         /* Set direction as output */
143         ulGPIODirection |= (1 << g_i2cClockGPIO);
144         POKE32(g_i2cClkGPIODataDirReg, ulGPIODirection);
145     }
146 }
147 
148 /*
149  *  This function set/reset the SDA GPIO pin
150  *
151  *  Parameters:
152  *      value    - Bit value to set to the SCL or SDA (0 = low, 1 = high)
153  *
154  *  Notes:
155  *      When setting SCL to high, just set the GPIO as input where the pull up
156  *      resistor will pull the signal up. Do not use software to pull up the
157  *      signal because the i2c will fail when other device try to drive the
158  *      signal due to SM50x will drive the signal to always high.
159  */
160 void swI2CSDA(unsigned char value)
161 {
162     unsigned long ulGPIOData;
163     unsigned long ulGPIODirection;
164 
165     ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg);
166     if (value)      /* High */
167     {
168         /* Set direction as input. This will automatically pull the signal up. */
169         ulGPIODirection &= ~(1 << g_i2cDataGPIO);
170         POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
171     }
172     else            /* Low */
173     {
174         /* Set the signal down */
175         ulGPIOData = PEEK32(g_i2cDataGPIODataReg);
176         ulGPIOData &= ~(1 << g_i2cDataGPIO);
177         POKE32(g_i2cDataGPIODataReg, ulGPIOData);
178 
179         /* Set direction as output */
180         ulGPIODirection |= (1 << g_i2cDataGPIO);
181         POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
182     }
183 }
184 
185 /*
186  *  This function read the data from the SDA GPIO pin
187  *
188  *  Return Value:
189  *      The SDA data bit sent by the Slave
190  */
191 static unsigned char swI2CReadSDA(void)
192 {
193     unsigned long ulGPIODirection;
194     unsigned long ulGPIOData;
195 
196     /* Make sure that the direction is input (High) */
197     ulGPIODirection = PEEK32(g_i2cDataGPIODataDirReg);
198     if ((ulGPIODirection & (1 << g_i2cDataGPIO)) != (~(1 << g_i2cDataGPIO)))
199     {
200         ulGPIODirection &= ~(1 << g_i2cDataGPIO);
201         POKE32(g_i2cDataGPIODataDirReg, ulGPIODirection);
202     }
203 
204     /* Now read the SDA line */
205     ulGPIOData = PEEK32(g_i2cDataGPIODataReg);
206     if (ulGPIOData & (1 << g_i2cDataGPIO))
207         return 1;
208     else
209         return 0;
210 }
211 
212 /*
213  *  This function sends ACK signal
214  */
215 static void swI2CAck(void)
216 {
217     return;  /* Single byte read is ok without it. */
218 }
219 
220 /*
221  *  This function sends the start command to the slave device
222  */
223 void swI2CStart(void)
224 {
225     /* Start I2C */
226     swI2CSDA(1);
227     swI2CSCL(1);
228     swI2CSDA(0);
229 }
230 
231 /*
232  *  This function sends the stop command to the slave device
233  */
234 void swI2CStop(void)
235 {
236     /* Stop the I2C */
237     swI2CSCL(1);
238     swI2CSDA(0);
239     swI2CSDA(1);
240 }
241 
242 /*
243  *  This function writes one byte to the slave device
244  *
245  *  Parameters:
246  *      data    - Data to be write to the slave device
247  *
248  *  Return Value:
249  *       0   - Success
250  *      -1   - Fail to write byte
251  */
252 long swI2CWriteByte(unsigned char data)
253 {
254     unsigned char value = data;
255     int i;
256 
257     /* Sending the data bit by bit */
258     for (i=0; i<8; i++)
259     {
260         /* Set SCL to low */
261         swI2CSCL(0);
262 
263         /* Send data bit */
264         if ((value & 0x80) != 0)
265             swI2CSDA(1);
266         else
267             swI2CSDA(0);
268 
269         swI2CWait();
270 
271         /* Toggle clk line to one */
272         swI2CSCL(1);
273         swI2CWait();
274 
275         /* Shift byte to be sent */
276         value = value << 1;
277     }
278 
279     /* Set the SCL Low and SDA High (prepare to get input) */
280     swI2CSCL(0);
281     swI2CSDA(1);
282 
283     /* Set the SCL High for ack */
284     swI2CWait();
285     swI2CSCL(1);
286     swI2CWait();
287 
288     /* Read SDA, until SDA==0 */
289     for(i=0; i<0xff; i++)
290     {
291         if (!swI2CReadSDA())
292             break;
293 
294         swI2CSCL(0);
295         swI2CWait();
296         swI2CSCL(1);
297         swI2CWait();
298     }
299 
300     /* Set the SCL Low and SDA High */
301     swI2CSCL(0);
302     swI2CSDA(1);
303 
304     if (i<0xff)
305         return 0;
306     else
307         return -1;
308 }
309 
310 /*
311  *  This function reads one byte from the slave device
312  *
313  *  Parameters:
314  *      ack    - Flag to indicate either to send the acknowledge
315  *            message to the slave device or not
316  *
317  *  Return Value:
318  *      One byte data read from the Slave device
319  */
320 unsigned char swI2CReadByte(unsigned char ack)
321 {
322     int i;
323     unsigned char data = 0;
324 
325     for(i=7; i>=0; i--)
326     {
327         /* Set the SCL to Low and SDA to High (Input) */
328         swI2CSCL(0);
329         swI2CSDA(1);
330         swI2CWait();
331 
332         /* Set the SCL High */
333         swI2CSCL(1);
334         swI2CWait();
335 
336         /* Read data bits from SDA */
337         data |= (swI2CReadSDA() << i);
338     }
339 
340     if (ack)
341         swI2CAck();
342 
343     /* Set the SCL Low and SDA High */
344     swI2CSCL(0);
345     swI2CSDA(1);
346 
347     return data;
348 }
349 
350 /*
351  * This function initializes GPIO port for SW I2C communication.
352  *
353  * Parameters:
354  *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
355  *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
356  *
357  * Return Value:
358  *      -1   - Fail to initialize the i2c
359  *       0   - Success
360  */
361 long swI2CInit_SM750LE(
362     unsigned char i2cClkGPIO,
363     unsigned char i2cDataGPIO
364 )
365 {
366     int i;
367 
368     /* Initialize the GPIO pin for the i2c Clock Register */
369     g_i2cClkGPIODataReg = GPIO_DATA_SM750LE;
370     g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
371 
372     /* Initialize the Clock GPIO Offset */
373     g_i2cClockGPIO = i2cClkGPIO;
374 
375     /* Initialize the GPIO pin for the i2c Data Register */
376     g_i2cDataGPIODataReg = GPIO_DATA_SM750LE;
377     g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
378 
379     /* Initialize the Data GPIO Offset */
380     g_i2cDataGPIO = i2cDataGPIO;
381 
382     /* Note that SM750LE don't have GPIO MUX and power is always on */
383 
384     /* Clear the i2c lines. */
385     for(i=0; i<9; i++)
386         swI2CStop();
387 
388     return 0;
389 }
390 
391 /*
392  * This function initializes the i2c attributes and bus
393  *
394  * Parameters:
395  *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
396  *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
397  *
398  * Return Value:
399  *      -1   - Fail to initialize the i2c
400  *       0   - Success
401  */
402 long swI2CInit(
403     unsigned char i2cClkGPIO,
404     unsigned char i2cDataGPIO
405 )
406 {
407     int i;
408 
409     /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */
410     if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31))
411         return -1;
412 
413     if (getChipType() == SM750LE)
414         return swI2CInit_SM750LE(i2cClkGPIO, i2cDataGPIO);
415 
416     /* Initialize the GPIO pin for the i2c Clock Register */
417     g_i2cClkGPIOMuxReg = GPIO_MUX;
418     g_i2cClkGPIODataReg = GPIO_DATA;
419     g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
420 
421     /* Initialize the Clock GPIO Offset */
422     g_i2cClockGPIO = i2cClkGPIO;
423 
424     /* Initialize the GPIO pin for the i2c Data Register */
425     g_i2cDataGPIOMuxReg = GPIO_MUX;
426     g_i2cDataGPIODataReg = GPIO_DATA;
427     g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
428 
429     /* Initialize the Data GPIO Offset */
430     g_i2cDataGPIO = i2cDataGPIO;
431 
432     /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
433     POKE32(g_i2cClkGPIOMuxReg,
434                       PEEK32(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO));
435     POKE32(g_i2cDataGPIOMuxReg,
436                       PEEK32(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO));
437 
438     /* Enable GPIO power */
439     enableGPIO(1);
440 
441     /* Clear the i2c lines. */
442     for(i=0; i<9; i++)
443         swI2CStop();
444 
445     return 0;
446 }
447 
448 /*
449  *  This function reads the slave device's register
450  *
451  *  Parameters:
452  *      deviceAddress   - i2c Slave device address which register
453  *                        to be read from
454  *      registerIndex   - Slave device's register to be read
455  *
456  *  Return Value:
457  *      Register value
458  */
459 unsigned char swI2CReadReg(
460     unsigned char deviceAddress,
461     unsigned char registerIndex
462 )
463 {
464     unsigned char data;
465 
466     /* Send the Start signal */
467     swI2CStart();
468 
469     /* Send the device address */
470     swI2CWriteByte(deviceAddress);
471 
472     /* Send the register index */
473     swI2CWriteByte(registerIndex);
474 
475     /* Get the bus again and get the data from the device read address */
476     swI2CStart();
477     swI2CWriteByte(deviceAddress + 1);
478     data = swI2CReadByte(1);
479 
480     /* Stop swI2C and release the bus */
481     swI2CStop();
482 
483     return data;
484 }
485 
486 /*
487  *  This function writes a value to the slave device's register
488  *
489  *  Parameters:
490  *      deviceAddress   - i2c Slave device address which register
491  *                        to be written
492  *      registerIndex   - Slave device's register to be written
493  *      data            - Data to be written to the register
494  *
495  *  Result:
496  *          0   - Success
497  *         -1   - Fail
498  */
499 long swI2CWriteReg(
500     unsigned char deviceAddress,
501     unsigned char registerIndex,
502     unsigned char data
503 )
504 {
505     long returnValue = 0;
506 
507     /* Send the Start signal */
508     swI2CStart();
509 
510     /* Send the device address and read the data. All should return success
511        in order for the writing processed to be successful
512      */
513     if ((swI2CWriteByte(deviceAddress) != 0) ||
514         (swI2CWriteByte(registerIndex) != 0) ||
515         (swI2CWriteByte(data) != 0))
516     {
517         returnValue = -1;
518     }
519 
520     /* Stop i2c and release the bus */
521     swI2CStop();
522 
523     return returnValue;
524 }
525