1/* Copyright (c) 2005 Advanced Micro Devices, Inc. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 * 21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its 22 * contributors may be used to endorse or promote products derived from this 23 * software without specific prior written permission. 24 * */ 25 26/* 27 * This file contains routines to write to and read from the I2C bus using 28 * the GPIO pins of the CS5530. 29 * */ 30 31/* STATIC VARIABLES TO STORE WHAT GPIO PINS TO USE */ 32 33int gpio_clock = 0; 34int gpio_data = 0; 35 36static int g_initialized = 0; 37 38#define I2CWRITE 0x00 /* Write address */ 39#define I2CREAD 0x01 /* Read address */ 40 41#define I2CACK 0x00 /* Ack value */ 42#define I2CNACK 0x01 /* Not - ack value */ 43 44#define CS5530_ID (0x80000000 | (0x00<<16) | (0x12<<11) | (0<<8) | 0x00) 45#define CS5530_GPIO (0x80000000 | (0x00<<16) | (0x12<<11) | (0<<8) | 0x90) 46#define SDA 0x0800 47#define SCL 0x0400 48#define SDADIR 0x0008 49#define SCLDIR 0x0004 50 51int I2C_init(void); 52void I2C_cleanup(void); 53 54int I2C_Read(unsigned char address, unsigned int reg, unsigned long *p_value, 55 unsigned int bytes); 56int I2C_Write(unsigned char address, unsigned int reg, unsigned long value, 57 unsigned int bytes); 58int I2CAL_init(void); 59void I2CAL_cleanup(void); 60 61void I2CAL_output_clock(int state); 62void I2CAL_output_data(int state); 63unsigned char I2CAL_input_data(void); 64 65void I2CAL_set_data_for_input(void); 66void I2CAL_set_data_for_output(void); 67 68void SendI2CStart(void); 69void SendI2CData(unsigned char inData); 70 71unsigned char ReceiveI2CAck(void); 72void SendI2CStop(void); 73void SendI2CNack(void); 74void SendI2CAck(void); 75unsigned char ReceiveI2CData(void); 76 77/* ### ADD ### ANY LOCAL ROUTINE DEFINITIONS SPECIFIC TO GPIO */ 78 79/*--------------------------------------------------------------------------- 80 * gfx_i2c_reset 81 * 82 * This routine resets the I2C bus. 83 *--------------------------------------------------------------------------- 84 */ 85 86#if GFX_I2C_DYNAMIC 87int 88gpio_i2c_reset(unsigned char busnum, short adr, char freq) 89#else 90int 91gfx_i2c_reset(unsigned char busnum, short adr, char freq) 92#endif 93{ 94 /* ### ADD ### Any code needed to reset the state of the GPIOs. */ 95 return GFX_STATUS_OK; 96} 97 98/*--------------------------------------------------------------------------- 99 * gfx_i2c_select_gpio 100 * 101 * This routine selects which GPIO pins to use. 102 *--------------------------------------------------------------------------- 103 */ 104#if GFX_I2C_DYNAMIC 105int 106gpio_i2c_select_gpio(int clock, int data) 107#else 108int 109gfx_i2c_select_gpio(int clock, int data) 110#endif 111{ 112 gpio_clock = clock; 113 gpio_data = data; 114 return (0); 115} 116 117/*--------------------------------------------------------------------------- 118 * gfx_i2c_write 119 * 120 * This routine writes data to the specified I2C address. 121 *--------------------------------------------------------------------------- 122 */ 123#if GFX_I2C_DYNAMIC 124int 125gpio_i2c_write(unsigned char busnum, unsigned char address, unsigned char reg, 126 unsigned char bytes, unsigned char *value) 127#else 128int 129gfx_i2c_write(unsigned char busnum, unsigned char address, unsigned char reg, 130 unsigned char bytes, unsigned char *value) 131#endif 132{ 133 /* ### ADD ### CODE TO WRITE BYTE TO I2B BUS */ 134 135 int restart_count = 0; 136 137 while (restart_count++ < 5) { 138 /* set the access pointer register. */ 139 /* The address is shifted left by one to make room for Read/Write 140 * bit */ 141 SendI2CStart(); 142 SendI2CData((char) ((address << 1) | I2CWRITE)); 143 if (!ReceiveI2CAck()) { 144 SendI2CStop(); 145 gfx_delay_milliseconds(10); 146 continue; 147 } 148 SendI2CData((unsigned char) reg); 149 if (!ReceiveI2CAck()) { 150 SendI2CStop(); 151 gfx_delay_milliseconds(10); 152 continue; 153 } 154 155 /* write the first byte */ 156 SendI2CData(*value); 157 if (!ReceiveI2CAck()) { 158 SendI2CStop(); 159 gfx_delay_milliseconds(10); 160 continue; 161 } 162 163 /* write the second byte. */ 164 if (bytes == 2) { 165 SendI2CData(*(value + 1)); 166 if (!ReceiveI2CAck()) { 167 SendI2CStop(); 168 gfx_delay_milliseconds(10); 169 continue; 170 } 171 } 172 173 /* done. */ 174 SendI2CStop(); 175 176 return 0; 177 } 178 179 return (0); 180 181} 182 183/*--------------------------------------------------------------------------- 184 * gfx_i2c_read 185 * 186 * This routine reads data from the specified I2C address. 187 *--------------------------------------------------------------------------- 188 */ 189#if GFX_I2C_DYNAMIC 190int 191gpio_i2c_read(unsigned char busnum, unsigned char address, unsigned char reg, 192 unsigned char bytes, unsigned char *p_value) 193#else 194int 195gfx_i2c_read(unsigned char busnum, unsigned char address, unsigned char reg, 196 unsigned char bytes, unsigned char *p_value) 197#endif 198{ 199 /* ### ADD ### CODE TO WRITE BYTE TO I2B BUS */ 200 /* For now return clock and data pins */ 201 202 int restart_count = 0; 203 204 if (!p_value) 205 return (1); 206 207 while (restart_count++ < 5) { 208 /* set the access pointer register. */ 209 /* The address is shifted left by one to make room for Read/Write 210 * bit */ 211 SendI2CStart(); 212 SendI2CData((char) ((address << 1) | I2CWRITE)); 213 if (!ReceiveI2CAck()) { 214 SendI2CStop(); 215 gfx_delay_milliseconds(10); 216 continue; 217 } 218 SendI2CData((unsigned char) (reg & 0xFF)); 219 SendI2CNack(); 220 221 /* read the first data byte. */ 222 SendI2CStart(); 223 SendI2CData((char) ((address << 1) | I2CREAD)); 224 if (!ReceiveI2CAck()) { 225 SendI2CStop(); 226 gfx_delay_milliseconds(10); 227 continue; 228 } 229 *p_value = ReceiveI2CData(); 230 231 /* read the second byte. */ 232 if (bytes == 2) { 233 SendI2CAck(); 234 *(p_value + 1) = ReceiveI2CData(); 235 } 236 237 /* done. */ 238 SendI2CNack(); 239 SendI2CStop(); 240 241 return 0; 242 } 243 244 return (1); 245} 246 247/* Added i2c/gpio code to test fs451 chip. */ 248 249/* 250 * ---------------------------------------------------------------------- 251 * 252 * void SendI2CStart(void) 253 * 254 * Sends an I2C start signal on the bus. 255 * 256 *---------------------------------------------------------------------- 257 */ 258void 259SendI2CStart(void) 260{ 261 I2CAL_output_data(1); 262 I2CAL_output_clock(1); 263 I2CAL_output_data(0); 264 I2CAL_output_clock(0); 265} 266 267/* 268 *---------------------------------------------------------------------- 269 * 270 * void SendI2CStop(void) 271 * 272 * Sends an I2C stop signal on the bus. 273 * 274 *---------------------------------------------------------------------- 275 */ 276void 277SendI2CStop(void) 278{ 279 I2CAL_output_data(0); 280 I2CAL_output_clock(1); 281 I2CAL_output_data(1); 282} 283 284/* 285 *---------------------------------------------------------------------- 286 * 287 * void SendI2CAck(void) 288 * 289 * Sends the Ack signal on the I2C bus. 290 * 291 *---------------------------------------------------------------------- 292 */ 293void 294SendI2CAck(void) 295{ 296 I2CAL_output_data(0); 297 I2CAL_output_clock(1); 298 I2CAL_output_clock(0); 299} 300 301/* 302 *---------------------------------------------------------------------- 303 * 304 * void SendI2CNack(void) 305 * 306 * Sends the Nt-Ack signal on the I2C bus. 307 * 308 *---------------------------------------------------------------------- 309 */ 310void 311SendI2CNack(void) 312{ 313 I2CAL_output_data(1); 314 I2CAL_output_clock(1); 315 I2CAL_output_clock(0); 316} 317 318/* 319 *---------------------------------------------------------------------- 320 * 321 * UInt8 SendI2CData( UInt8 inData ) 322 * 323 * Sends a byte of data on the I2C bus and returns the TRUE if the slave 324 * ACK'dthe data. 325 * 326 * Input: inData - the byte of data to send 327 * Output: (return) - TRUE (1) if ACK was received, FALSE (0) if not 328 * 329 *---------------------------------------------------------------------- 330 */ 331void 332SendI2CData(unsigned char inData) 333{ 334 unsigned char bit; 335 336 /* Send all 8 bits of data byte, MSB to LSB */ 337 for (bit = 0x80; bit != 0; bit >>= 1) { 338 if (inData & bit) 339 I2CAL_output_data(1); 340 else 341 I2CAL_output_data(0); 342 343 I2CAL_output_clock(1); 344 I2CAL_output_clock(0); 345 } 346} 347 348/* 349 *---------------------------------------------------------------------- 350 * 351 * UInt8 ReceiveI2CAck( ) 352 * 353 * Receives the Ack (or Nack) from the slave. 354 * 355 * Output: (return) - TRUE (1) if ACK was received, FALSE (0) if not 356 * 357 *---------------------------------------------------------------------- 358 */ 359unsigned char 360ReceiveI2CAck(void) 361{ 362 unsigned char bit; 363 364 /* Test for Ack/Nack */ 365 I2CAL_set_data_for_input(); 366 I2CAL_output_data(1); 367 I2CAL_output_clock(1); 368 bit = I2CAL_input_data(); 369 I2CAL_output_clock(0); 370 I2CAL_set_data_for_output(); 371 return !bit; 372} 373 374/* 375 *---------------------------------------------------------------------- 376 * 377 * unsigned char ReceiveI2CData(void) 378 * 379 * Receives a byte of data from the I2C bus. 380 * 381 * Output: (return) - The data byte recehved from the bus 382 * 383 *---------------------------------------------------------------------- 384 */ 385unsigned char 386ReceiveI2CData(void) 387{ 388 unsigned char data = 0; 389 unsigned char x; 390 391 /* make sure the data line is released */ 392 I2CAL_set_data_for_input(); 393 I2CAL_output_data(1); 394 395 /* shift in the data */ 396 for (x = 0; x < 8; x++) { 397 /* shift the data left */ 398 I2CAL_output_clock(1); 399 data <<= 1; 400 data |= I2CAL_input_data(); 401 I2CAL_output_clock(0); 402 } 403 404 I2CAL_set_data_for_output(); 405 I2CAL_output_data(1); 406 return data; 407} 408 409/* 410 *---------------------------------------------------------------------- 411 * 412 * void I2C_init(void) 413 * 414 * This routine initializes the I2C interface. Clients of the I2C.c 415 * will call this routine before calling any other routine in the I2C.c 416 * 417 *---------------------------------------------------------------------- 418 */ 419 420#if GFX_I2C_DYNAMIC 421int 422gpio_i2c_init(void) 423#else 424int 425gfx_i2c_init(void) 426#endif 427{ 428 int errc; 429 430 /* init I2CAL */ 431 errc = I2CAL_init(); 432 if (errc) 433 return errc; 434 435 /* set the clock and data lines to the proper states */ 436 I2CAL_output_clock(1); 437 I2CAL_output_data(1); 438 I2CAL_set_data_for_output(); 439 440 SendI2CStart(); 441 SendI2CStop(); 442 SendI2CStop(); 443 444 g_initialized = 1; 445 446 return 0; 447} 448 449/* 450 *---------------------------------------------------------------------- 451 * 452 * void I2C_cleanup(void) 453 * 454 * This routine disables the I2C interface. Clients of the I2C.c will not 455 * call any other I2C routine after calling this routine. 456 * 457 *---------------------------------------------------------------------- 458 */ 459 460#if GFX_I2C_DYNAMIC 461void 462gpio_i2c_cleanup(void) 463#else 464void 465gfx_i2c_cleanup(void) 466#endif 467{ 468 if (g_initialized) { 469 470 /* set the clock and data lines to a harmless state */ 471 I2CAL_output_clock(1); 472 I2CAL_output_data(1); 473 474 g_initialized = 0; 475 } 476 477 I2CAL_cleanup(); 478} 479 480int 481I2CAL_init(void) 482{ 483 unsigned long l_reg; 484 unsigned short reg; 485 486 /* initialize the i2c port. */ 487 l_reg = gfx_pci_config_read(CS5530_GPIO); 488 489 if (l_reg != 0x01001078) 490 return 1; 491 492 l_reg = gfx_pci_config_read(CS5530_GPIO); 493 reg = (unsigned short) l_reg; 494 495 /* both outputs, both high. */ 496 reg |= (SDADIR | SCLDIR | SDA | SCL); 497 l_reg = reg; 498 gfx_pci_config_write(CS5530_GPIO, l_reg); 499 500 g_initialized = 1; 501 502 return 0; 503} 504 505void 506I2CAL_cleanup(void) 507{ 508 if (g_initialized) { 509 510 g_initialized = 0; 511 } 512} 513 514/* 515 *---------------------------------------------------------------------------- 516 * 517 * set the I2C clock line state 518 * 519 *---------------------------------------------------------------------------- 520 */ 521void 522I2CAL_output_clock(int inState) 523{ 524 unsigned short reg; 525 unsigned long value; 526 527 value = gfx_pci_config_read(CS5530_GPIO); 528 reg = (unsigned short) value; 529 530 if (inState) { /* write a 1. */ 531 reg |= SCL; 532 } 533 else { /* write a 0. */ 534 reg &= ~SCL; 535 } 536 537 value = reg; 538 gfx_pci_config_write(CS5530_GPIO, value); 539 540 /* hold it for a minimum of 4.7us */ 541 gfx_delay_microseconds(5); 542} 543 544/* 545 *---------------------------------------------------------------------------- 546 * 547 * set the I2C data line state 548 * 549 *---------------------------------------------------------------------------- 550 */ 551void 552I2CAL_output_data(int inState) 553{ 554 unsigned short reg; 555 unsigned long value; 556 557 value = gfx_pci_config_read(CS5530_GPIO); 558 reg = (unsigned short) value; 559 560 if (inState) { /* write a 1. */ 561 reg |= SDA; 562 } 563 else { 564 /* write a 0. */ 565 reg &= ~SDA; 566 } 567 value = reg; 568 gfx_pci_config_write(CS5530_GPIO, value); 569 570 /* 250 ns setup time */ 571 gfx_delay_microseconds(1); 572} 573 574/* 575 *---------------------------------------------------------------------------- 576 * 577 * read the state of the data line 578 * 579 *---------------------------------------------------------------------------- 580 */ 581unsigned char 582I2CAL_input_data(void) 583{ 584 unsigned short reg; 585 unsigned long value; 586 587 value = gfx_pci_config_read(CS5530_GPIO); 588 reg = (unsigned short) value; 589 590 if (reg & SDA) 591 return 1; 592 else 593 return 0; 594} 595 596/* 597 *---------------------------------------------------------------------------- 598 * 599 * set the I2C data for input mode 600 * 601 *---------------------------------------------------------------------------- 602 */ 603void 604I2CAL_set_data_for_input(void) 605{ 606 unsigned short reg; 607 unsigned long value; 608 609 value = gfx_pci_config_read(CS5530_GPIO); 610 reg = (unsigned short) value; 611 612 reg &= ~SDADIR; 613 614 value = reg; 615 616 gfx_pci_config_write(CS5530_GPIO, value); 617} 618 619/* 620 *---------------------------------------------------------------------------- 621 * 622 * set the I2C data for output mode 623 * 624 *---------------------------------------------------------------------------- 625 */ 626void 627I2CAL_set_data_for_output(void) 628{ 629 unsigned short reg; 630 unsigned long value; 631 632 value = gfx_pci_config_read(CS5530_GPIO); 633 reg = (unsigned short) value; 634 reg |= SDADIR; 635 value = reg; 636 637 gfx_pci_config_write(CS5530_GPIO, value); 638 639} 640 641/* END OF FILE */ 642