i2c_gpio.c revision f29dbc25
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 } else { /* write a 0. */ 533 reg &= ~SCL; 534 } 535 536 value = reg; 537 gfx_pci_config_write(CS5530_GPIO, value); 538 539 /* hold it for a minimum of 4.7us */ 540 gfx_delay_microseconds(5); 541} 542 543/* 544 *---------------------------------------------------------------------------- 545 * 546 * set the I2C data line state 547 * 548 *---------------------------------------------------------------------------- 549 */ 550void 551I2CAL_output_data(int inState) 552{ 553 unsigned short reg; 554 unsigned long value; 555 556 value = gfx_pci_config_read(CS5530_GPIO); 557 reg = (unsigned short)value; 558 559 if (inState) { /* write a 1. */ 560 reg |= SDA; 561 } else { 562 /* write a 0. */ 563 reg &= ~SDA; 564 } 565 value = reg; 566 gfx_pci_config_write(CS5530_GPIO, value); 567 568 /* 250 ns setup time */ 569 gfx_delay_microseconds(1); 570} 571 572/* 573 *---------------------------------------------------------------------------- 574 * 575 * read the state of the data line 576 * 577 *---------------------------------------------------------------------------- 578 */ 579unsigned char 580I2CAL_input_data(void) 581{ 582 unsigned short reg; 583 unsigned long value; 584 585 value = gfx_pci_config_read(CS5530_GPIO); 586 reg = (unsigned short)value; 587 588 if (reg & SDA) 589 return 1; 590 else 591 return 0; 592} 593 594/* 595 *---------------------------------------------------------------------------- 596 * 597 * set the I2C data for input mode 598 * 599 *---------------------------------------------------------------------------- 600 */ 601void 602I2CAL_set_data_for_input(void) 603{ 604 unsigned short reg; 605 unsigned long value; 606 607 value = gfx_pci_config_read(CS5530_GPIO); 608 reg = (unsigned short)value; 609 610 reg &= ~SDADIR; 611 612 value = reg; 613 614 gfx_pci_config_write(CS5530_GPIO, value); 615} 616 617/* 618 *---------------------------------------------------------------------------- 619 * 620 * set the I2C data for output mode 621 * 622 *---------------------------------------------------------------------------- 623 */ 624void 625I2CAL_set_data_for_output(void) 626{ 627 unsigned short reg; 628 unsigned long value; 629 630 value = gfx_pci_config_read(CS5530_GPIO); 631 reg = (unsigned short)value; 632 reg |= SDADIR; 633 value = reg; 634 635 gfx_pci_config_write(CS5530_GPIO, value); 636 637} 638 639/* END OF FILE */ 640