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