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