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