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. */
58static unsigned char g_i2cClockGPIO = DEFAULT_I2C_SCL;
59static 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 */
73static unsigned long g_i2cClkGPIOMuxReg = GPIO_MUX;
74static unsigned long g_i2cClkGPIODataReg = GPIO_DATA;
75static unsigned long g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
76
77/* i2c Data GPIO Register usage */
78static unsigned long g_i2cDataGPIOMuxReg = GPIO_MUX;
79static unsigned long g_i2cDataGPIODataReg = GPIO_DATA;
80static unsigned long g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
81
82/*
83 *  This function puts a delay between command
84 */
85static 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 */
123void 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 */
160void 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 */
191static 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 */
215static 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 */
223static 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 */
234static 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 */
252static 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 */
320static 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 */
361static long swI2CInit_SM750LE(unsigned char i2cClkGPIO,
362			      unsigned char i2cDataGPIO)
363{
364    int i;
365
366    /* Initialize the GPIO pin for the i2c Clock Register */
367    g_i2cClkGPIODataReg = GPIO_DATA_SM750LE;
368    g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
369
370    /* Initialize the Clock GPIO Offset */
371    g_i2cClockGPIO = i2cClkGPIO;
372
373    /* Initialize the GPIO pin for the i2c Data Register */
374    g_i2cDataGPIODataReg = GPIO_DATA_SM750LE;
375    g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION_SM750LE;
376
377    /* Initialize the Data GPIO Offset */
378    g_i2cDataGPIO = i2cDataGPIO;
379
380    /* Note that SM750LE don't have GPIO MUX and power is always on */
381
382    /* Clear the i2c lines. */
383    for(i=0; i<9; i++)
384        swI2CStop();
385
386    return 0;
387}
388
389/*
390 * This function initializes the i2c attributes and bus
391 *
392 * Parameters:
393 *      i2cClkGPIO      - The GPIO pin to be used as i2c SCL
394 *      i2cDataGPIO     - The GPIO pin to be used as i2c SDA
395 *
396 * Return Value:
397 *      -1   - Fail to initialize the i2c
398 *       0   - Success
399 */
400long swI2CInit(
401    unsigned char i2cClkGPIO,
402    unsigned char i2cDataGPIO
403)
404{
405    int i;
406
407    /* Return 0 if the GPIO pins to be used is out of range. The range is only from [0..63] */
408    if ((i2cClkGPIO > 31) || (i2cDataGPIO > 31))
409        return -1;
410
411    if (getChipType() == SM750LE)
412        return swI2CInit_SM750LE(i2cClkGPIO, i2cDataGPIO);
413
414    /* Initialize the GPIO pin for the i2c Clock Register */
415    g_i2cClkGPIOMuxReg = GPIO_MUX;
416    g_i2cClkGPIODataReg = GPIO_DATA;
417    g_i2cClkGPIODataDirReg = GPIO_DATA_DIRECTION;
418
419    /* Initialize the Clock GPIO Offset */
420    g_i2cClockGPIO = i2cClkGPIO;
421
422    /* Initialize the GPIO pin for the i2c Data Register */
423    g_i2cDataGPIOMuxReg = GPIO_MUX;
424    g_i2cDataGPIODataReg = GPIO_DATA;
425    g_i2cDataGPIODataDirReg = GPIO_DATA_DIRECTION;
426
427    /* Initialize the Data GPIO Offset */
428    g_i2cDataGPIO = i2cDataGPIO;
429
430    /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
431    POKE32(g_i2cClkGPIOMuxReg,
432                      PEEK32(g_i2cClkGPIOMuxReg) & ~(1 << g_i2cClockGPIO));
433    POKE32(g_i2cDataGPIOMuxReg,
434                      PEEK32(g_i2cDataGPIOMuxReg) & ~(1 << g_i2cDataGPIO));
435
436    /* Enable GPIO power */
437    enableGPIO(1);
438
439    /* Clear the i2c lines. */
440    for(i=0; i<9; i++)
441        swI2CStop();
442
443    return 0;
444}
445
446/*
447 *  This function reads the slave device's register
448 *
449 *  Parameters:
450 *      deviceAddress   - i2c Slave device address which register
451 *                        to be read from
452 *      registerIndex   - Slave device's register to be read
453 *
454 *  Return Value:
455 *      Register value
456 */
457unsigned char swI2CReadReg(
458    unsigned char deviceAddress,
459    unsigned char registerIndex
460)
461{
462    unsigned char data;
463
464    /* Send the Start signal */
465    swI2CStart();
466
467    /* Send the device address */
468    swI2CWriteByte(deviceAddress);
469
470    /* Send the register index */
471    swI2CWriteByte(registerIndex);
472
473    /* Get the bus again and get the data from the device read address */
474    swI2CStart();
475    swI2CWriteByte(deviceAddress + 1);
476    data = swI2CReadByte(1);
477
478    /* Stop swI2C and release the bus */
479    swI2CStop();
480
481    return data;
482}
483
484/*
485 *  This function writes a value to the slave device's register
486 *
487 *  Parameters:
488 *      deviceAddress   - i2c Slave device address which register
489 *                        to be written
490 *      registerIndex   - Slave device's register to be written
491 *      data            - Data to be written to the register
492 *
493 *  Result:
494 *          0   - Success
495 *         -1   - Fail
496 */
497long swI2CWriteReg(
498    unsigned char deviceAddress,
499    unsigned char registerIndex,
500    unsigned char data
501)
502{
503    long returnValue = 0;
504
505    /* Send the Start signal */
506    swI2CStart();
507
508    /* Send the device address and read the data. All should return success
509       in order for the writing processed to be successful
510     */
511    if ((swI2CWriteByte(deviceAddress) != 0) ||
512        (swI2CWriteByte(registerIndex) != 0) ||
513        (swI2CWriteByte(data) != 0))
514    {
515        returnValue = -1;
516    }
517
518    /* Stop i2c and release the bus */
519    swI2CStop();
520
521    return returnValue;
522}
523