summaryrefslogtreecommitdiff
path: root/src/gfx/i2c_gpio.c
diff options
context:
space:
mode:
authorJordan Crouse <jordan.crouse@amd.com>2006-07-06 14:56:42 -0600
committerJordan Crouse <jordan.crouse@amd.com>2006-07-06 14:56:42 -0600
commitc3ab9f1a60afe1f5e86db1cf2635acda14fae2f5 (patch)
tree00cfb19765f276220eb794553b545e9f67402688 /src/gfx/i2c_gpio.c
Initial commit of the xf86-video-amd tree
Diffstat (limited to 'src/gfx/i2c_gpio.c')
-rw-r--r--src/gfx/i2c_gpio.c639
1 files changed, 639 insertions, 0 deletions
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 */