From c3ab9f1a60afe1f5e86db1cf2635acda14fae2f5 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Thu, 6 Jul 2006 14:56:42 -0600 Subject: Initial commit of the xf86-video-amd tree --- src/gfx/i2c_gpio.c | 639 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 639 insertions(+) create mode 100644 src/gfx/i2c_gpio.c (limited to 'src/gfx/i2c_gpio.c') diff --git a/src/gfx/i2c_gpio.c b/src/gfx/i2c_gpio.c new file mode 100644 index 0000000..7614cd0 --- /dev/null +++ b/src/gfx/i2c_gpio.c @@ -0,0 +1,639 @@ +/* Copyright (c) 2005 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Neither the name of the Advanced Micro Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * */ + +/* + * This file contains routines to write to and read from the I2C bus using + * the GPIO pins of the CS5530. + * */ + +/* STATIC VARIABLES TO STORE WHAT GPIO PINS TO USE */ + +int gpio_clock = 0; +int gpio_data = 0; + +static int g_initialized = 0; + +#define I2CWRITE 0x00 /* Write address */ +#define I2CREAD 0x01 /* Read address */ + +#define I2CACK 0x00 /* Ack value */ +#define I2CNACK 0x01 /* Not - ack value */ + +#define CS5530_ID (0x80000000 | (0x00<<16) | (0x12<<11) | (0<<8) | 0x00) +#define CS5530_GPIO (0x80000000 | (0x00<<16) | (0x12<<11) | (0<<8) | 0x90) +#define SDA 0x0800 +#define SCL 0x0400 +#define SDADIR 0x0008 +#define SCLDIR 0x0004 + +int I2C_init(void); +void I2C_cleanup(void); + +int I2C_Read(unsigned char address, unsigned int reg, unsigned long *p_value, + unsigned int bytes); +int I2C_Write(unsigned char address, unsigned int reg, unsigned long value, + unsigned int bytes); +int I2CAL_init(void); +void I2CAL_cleanup(void); + +void I2CAL_output_clock(int state); +void I2CAL_output_data(int state); +unsigned char I2CAL_input_data(void); + +void I2CAL_set_data_for_input(void); +void I2CAL_set_data_for_output(void); + +void SendI2CStart(void); +void SendI2CData(unsigned char inData); + +unsigned char ReceiveI2CAck(void); +void SendI2CStop(void); +void SendI2CNack(void); +void SendI2CAck(void); +unsigned char ReceiveI2CData(void); + +/* ### ADD ### ANY LOCAL ROUTINE DEFINITIONS SPECIFIC TO GPIO */ + +/*--------------------------------------------------------------------------- + * gfx_i2c_reset + * + * This routine resets the I2C bus. + *--------------------------------------------------------------------------- + */ + +#if GFX_I2C_DYNAMIC +int +gpio_i2c_reset(unsigned char busnum, short adr, char freq) +#else +int +gfx_i2c_reset(unsigned char busnum, short adr, char freq) +#endif +{ + /* ### ADD ### Any code needed to reset the state of the GPIOs. */ + return GFX_STATUS_OK; +} + +/*--------------------------------------------------------------------------- + * gfx_i2c_select_gpio + * + * This routine selects which GPIO pins to use. + *--------------------------------------------------------------------------- + */ +#if GFX_I2C_DYNAMIC +int +gpio_i2c_select_gpio(int clock, int data) +#else +int +gfx_i2c_select_gpio(int clock, int data) +#endif +{ + gpio_clock = clock; + gpio_data = data; + return (0); +} + +/*--------------------------------------------------------------------------- + * gfx_i2c_write + * + * This routine writes data to the specified I2C address. + *--------------------------------------------------------------------------- + */ +#if GFX_I2C_DYNAMIC +int +gpio_i2c_write(unsigned char busnum, unsigned char address, unsigned char reg, + unsigned char bytes, unsigned char *value) +#else +int +gfx_i2c_write(unsigned char busnum, unsigned char address, unsigned char reg, + unsigned char bytes, unsigned char *value) +#endif +{ + /* ### ADD ### CODE TO WRITE BYTE TO I2B BUS */ + + int restart_count = 0; + + while (restart_count++ < 5) { + /* set the access pointer register. */ + /* The address is shifted left by one to make room for Read/Write + * bit */ + SendI2CStart(); + SendI2CData((char)((address << 1) | I2CWRITE)); + if (!ReceiveI2CAck()) { + SendI2CStop(); + gfx_delay_milliseconds(10); + continue; + } + SendI2CData((unsigned char)reg); + if (!ReceiveI2CAck()) { + SendI2CStop(); + gfx_delay_milliseconds(10); + continue; + } + + /* write the first byte */ + SendI2CData(*value); + if (!ReceiveI2CAck()) { + SendI2CStop(); + gfx_delay_milliseconds(10); + continue; + } + + /* write the second byte. */ + if (bytes == 2) { + SendI2CData(*(value + 1)); + if (!ReceiveI2CAck()) { + SendI2CStop(); + gfx_delay_milliseconds(10); + continue; + } + } + + /* done. */ + SendI2CStop(); + + return 0; + } + + return (0); + +} + +/*--------------------------------------------------------------------------- + * gfx_i2c_read + * + * This routine reads data from the specified I2C address. + *--------------------------------------------------------------------------- + */ +#if GFX_I2C_DYNAMIC +int +gpio_i2c_read(unsigned char busnum, unsigned char address, unsigned char reg, + unsigned char bytes, unsigned char *p_value) +#else +int +gfx_i2c_read(unsigned char busnum, unsigned char address, unsigned char reg, + unsigned char bytes, unsigned char *p_value) +#endif +{ + /* ### ADD ### CODE TO WRITE BYTE TO I2B BUS */ + /* For now return clock and data pins */ + + int restart_count = 0; + + if (!p_value) + return (1); + + while (restart_count++ < 5) { + /* set the access pointer register. */ + /* The address is shifted left by one to make room for Read/Write + * bit */ + SendI2CStart(); + SendI2CData((char)((address << 1) | I2CWRITE)); + if (!ReceiveI2CAck()) { + SendI2CStop(); + gfx_delay_milliseconds(10); + continue; + } + SendI2CData((unsigned char)(reg & 0xFF)); + SendI2CNack(); + + /* read the first data byte. */ + SendI2CStart(); + SendI2CData((char)((address << 1) | I2CREAD)); + if (!ReceiveI2CAck()) { + SendI2CStop(); + gfx_delay_milliseconds(10); + continue; + } + *p_value = ReceiveI2CData(); + + /* read the second byte. */ + if (bytes == 2) { + SendI2CAck(); + *(p_value + 1) = ReceiveI2CData(); + } + + /* done. */ + SendI2CNack(); + SendI2CStop(); + + return 0; + } + + return (1); +} + +/* Added i2c/gpio code to test fs451 chip. */ + +/* + * ---------------------------------------------------------------------- + * + * void SendI2CStart(void) + * + * Sends an I2C start signal on the bus. + * + *---------------------------------------------------------------------- + */ +void +SendI2CStart(void) +{ + I2CAL_output_data(1); + I2CAL_output_clock(1); + I2CAL_output_data(0); + I2CAL_output_clock(0); +} + +/* + *---------------------------------------------------------------------- + * + * void SendI2CStop(void) + * + * Sends an I2C stop signal on the bus. + * + *---------------------------------------------------------------------- + */ +void +SendI2CStop(void) +{ + I2CAL_output_data(0); + I2CAL_output_clock(1); + I2CAL_output_data(1); +} + +/* + *---------------------------------------------------------------------- + * + * void SendI2CAck(void) + * + * Sends the Ack signal on the I2C bus. + * + *---------------------------------------------------------------------- + */ +void +SendI2CAck(void) +{ + I2CAL_output_data(0); + I2CAL_output_clock(1); + I2CAL_output_clock(0); +} + +/* + *---------------------------------------------------------------------- + * + * void SendI2CNack(void) + * + * Sends the Nt-Ack signal on the I2C bus. + * + *---------------------------------------------------------------------- + */ +void +SendI2CNack(void) +{ + I2CAL_output_data(1); + I2CAL_output_clock(1); + I2CAL_output_clock(0); +} + +/* + *---------------------------------------------------------------------- + * + * UInt8 SendI2CData( UInt8 inData ) + * + * Sends a byte of data on the I2C bus and returns the TRUE if the slave + * ACK'dthe data. + * + * Input: inData - the byte of data to send + * Output: (return) - TRUE (1) if ACK was received, FALSE (0) if not + * + *---------------------------------------------------------------------- + */ +void +SendI2CData(unsigned char inData) +{ + unsigned char bit; + + /* Send all 8 bits of data byte, MSB to LSB */ + for (bit = 0x80; bit != 0; bit >>= 1) { + if (inData & bit) + I2CAL_output_data(1); + else + I2CAL_output_data(0); + + I2CAL_output_clock(1); + I2CAL_output_clock(0); + } +} + +/* + *---------------------------------------------------------------------- + * + * UInt8 ReceiveI2CAck( ) + * + * Receives the Ack (or Nack) from the slave. + * + * Output: (return) - TRUE (1) if ACK was received, FALSE (0) if not + * + *---------------------------------------------------------------------- + */ +unsigned char +ReceiveI2CAck(void) +{ + unsigned char bit; + + /* Test for Ack/Nack */ + I2CAL_set_data_for_input(); + I2CAL_output_data(1); + I2CAL_output_clock(1); + bit = I2CAL_input_data(); + I2CAL_output_clock(0); + I2CAL_set_data_for_output(); + return !bit; +} + +/* + *---------------------------------------------------------------------- + * + * unsigned char ReceiveI2CData(void) + * + * Receives a byte of data from the I2C bus. + * + * Output: (return) - The data byte recehved from the bus + * + *---------------------------------------------------------------------- + */ +unsigned char +ReceiveI2CData(void) +{ + unsigned char data = 0; + unsigned char x; + + /* make sure the data line is released */ + I2CAL_set_data_for_input(); + I2CAL_output_data(1); + + /* shift in the data */ + for (x = 0; x < 8; x++) { + /* shift the data left */ + I2CAL_output_clock(1); + data <<= 1; + data |= I2CAL_input_data(); + I2CAL_output_clock(0); + } + + I2CAL_set_data_for_output(); + I2CAL_output_data(1); + return data; +} + +/* + *---------------------------------------------------------------------- + * + * void I2C_init(void) + * + * This routine initializes the I2C interface. Clients of the I2C.c + * will call this routine before calling any other routine in the I2C.c + * + *---------------------------------------------------------------------- + */ + +#if GFX_I2C_DYNAMIC +int +gpio_i2c_init(void) +#else +int +gfx_i2c_init(void) +#endif +{ + int errc; + + /* init I2CAL */ + errc = I2CAL_init(); + if (errc) + return errc; + + /* set the clock and data lines to the proper states */ + I2CAL_output_clock(1); + I2CAL_output_data(1); + I2CAL_set_data_for_output(); + + SendI2CStart(); + SendI2CStop(); + SendI2CStop(); + + g_initialized = 1; + + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * void I2C_cleanup(void) + * + * This routine disables the I2C interface. Clients of the I2C.c will not + * call any other I2C routine after calling this routine. + * + *---------------------------------------------------------------------- + */ + +#if GFX_I2C_DYNAMIC +void +gpio_i2c_cleanup(void) +#else +void +gfx_i2c_cleanup(void) +#endif +{ + if (g_initialized) { + + /* set the clock and data lines to a harmless state */ + I2CAL_output_clock(1); + I2CAL_output_data(1); + + g_initialized = 0; + } + + I2CAL_cleanup(); +} + +int +I2CAL_init(void) +{ + unsigned long l_reg; + unsigned short reg; + + /* initialize the i2c port. */ + l_reg = gfx_pci_config_read(CS5530_GPIO); + + if (l_reg != 0x01001078) + return 1; + + l_reg = gfx_pci_config_read(CS5530_GPIO); + reg = (unsigned short)l_reg; + + /* both outputs, both high. */ + reg |= (SDADIR | SCLDIR | SDA | SCL); + l_reg = reg; + gfx_pci_config_write(CS5530_GPIO, l_reg); + + g_initialized = 1; + + return 0; +} + +void +I2CAL_cleanup(void) +{ + if (g_initialized) { + + g_initialized = 0; + } +} + +/* + *---------------------------------------------------------------------------- + * + * set the I2C clock line state + * + *---------------------------------------------------------------------------- + */ +void +I2CAL_output_clock(int inState) +{ + unsigned short reg; + unsigned long value; + + value = gfx_pci_config_read(CS5530_GPIO); + reg = (unsigned short)value; + + if (inState) { /* write a 1. */ + reg |= SCL; + } else { /* write a 0. */ + reg &= ~SCL; + } + + value = reg; + gfx_pci_config_write(CS5530_GPIO, value); + + /* hold it for a minimum of 4.7us */ + gfx_delay_microseconds(5); +} + +/* + *---------------------------------------------------------------------------- + * + * set the I2C data line state + * + *---------------------------------------------------------------------------- + */ +void +I2CAL_output_data(int inState) +{ + unsigned short reg; + unsigned long value; + + value = gfx_pci_config_read(CS5530_GPIO); + reg = (unsigned short)value; + + if (inState) { /* write a 1. */ + reg |= SDA; + } else { + /* write a 0. */ + reg &= ~SDA; + } + value = reg; + gfx_pci_config_write(CS5530_GPIO, value); + + /* 250 ns setup time */ + gfx_delay_microseconds(1); +} + +/* + *---------------------------------------------------------------------------- + * + * read the state of the data line + * + *---------------------------------------------------------------------------- + */ +unsigned char +I2CAL_input_data(void) +{ + unsigned short reg; + unsigned long value; + + value = gfx_pci_config_read(CS5530_GPIO); + reg = (unsigned short)value; + + if (reg & SDA) + return 1; + else + return 0; +} + +/* + *---------------------------------------------------------------------------- + * + * set the I2C data for input mode + * + *---------------------------------------------------------------------------- + */ +void +I2CAL_set_data_for_input(void) +{ + unsigned short reg; + unsigned long value; + + value = gfx_pci_config_read(CS5530_GPIO); + reg = (unsigned short)value; + + reg &= ~SDADIR; + + value = reg; + + gfx_pci_config_write(CS5530_GPIO, value); +} + +/* + *---------------------------------------------------------------------------- + * + * set the I2C data for output mode + * + *---------------------------------------------------------------------------- + */ +void +I2CAL_set_data_for_output(void) +{ + unsigned short reg; + unsigned long value; + + value = gfx_pci_config_read(CS5530_GPIO); + reg = (unsigned short)value; + reg |= SDADIR; + value = reg; + + gfx_pci_config_write(CS5530_GPIO, value); + +} + +/* END OF FILE */ -- cgit v1.2.3