#include #include #include #include #include #define MAX_I2C_RETRYS 10 #define I2C_DELAY 1000 /* Should be at least the # of MHz of Tclk */ #undef DEBUG_I2C #ifdef DEBUG_I2C #define DP(x) x #else #define DP(x) #endif /* Assuming that there is only one master on the bus (us) */ static void i2c_init(int speed, int slaveaddr) { unsigned int n, m, freq, margin, power; unsigned int actualFreq, actualN = 0, actualM = 0; unsigned int control, status; unsigned int minMargin = 0xffffffff; unsigned int tclk = 125000000; DP(puts("i2c_init\n")); for (n = 0 ; n < 8 ; n++) { for (m = 0 ; m < 16 ; m++) { power = 2< freq) margin = speed - freq; else margin = freq - speed; if (margin < minMargin) { minMargin = margin; actualFreq = freq; actualN = n; actualM = m; } } } DP(puts("setup i2c bus\n")); /* Setup bus */ GT_REG_WRITE(I2C_SOFT_RESET, 0); DP(puts("udelay...\n")); udelay(I2C_DELAY); DP(puts("set baudrate\n")); GT_REG_WRITE(I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN); GT_REG_WRITE(I2C_CONTROL, (0x1 << 2) | (0x1 << 6)); udelay(I2C_DELAY * 10); DP(puts("read control, baudrate\n")); GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); GT_REG_READ(I2C_CONTROL, &control); } static uchar i2c_start(void) { unsigned int control, status; int count = 0; DP(puts("i2c_start\n")); /* Set the start bit */ GT_REG_READ(I2C_CONTROL, &control); control |= (0x1 << 5); GT_REG_WRITE(I2C_CONTROL, control); GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); count = 0; while ((status & 0xff) != 0x08) { udelay(I2C_DELAY); if (count > 20) { GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ return status; } GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); count++; } return 0; } static uchar i2c_select_device(uchar dev_addr, uchar read, int ten_bit) { unsigned int status, data, bits = 7; int count = 0; DP(puts("i2c_select_device\n")); /* Output slave address */ if (ten_bit) bits = 10; data = (dev_addr << 1); /* set the read bit */ data |= read; GT_REG_WRITE(I2C_DATA, data); /* assert the address */ RESET_REG_BITS(I2C_CONTROL, BIT3); udelay(I2C_DELAY); GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); count = 0; while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) { udelay(I2C_DELAY); if (count > 20) { GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ return status; } GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); count++; } if (bits == 10) { printf("10 bit I2C addressing not yet implemented\n"); return 0xff; } return 0; } static uchar i2c_get_data(uchar *return_data, int len) { unsigned int data, status = 0; int count = 0; DP(puts("i2c_get_data\n")); while (len) { /* Get and return the data */ RESET_REG_BITS(I2C_CONTROL, (0x1 << 3)); udelay(I2C_DELAY * 5); GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); count++; while ((status & 0xff) != 0x50) { udelay(I2C_DELAY); if (count > 2) { GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ return 0; } GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); count++; } GT_REG_READ(I2C_DATA, &data); len--; *return_data = (uchar)data; return_data++; } RESET_REG_BITS(I2C_CONTROL, BIT2|BIT3); while ((status & 0xff) != 0x58) { udelay(I2C_DELAY); if (count > 200) { GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ return status; } GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); count++; } GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /* stop */ return 0; } static uchar i2c_write_data(unsigned int data, int len) { unsigned int status; int count = 0; DP(puts("i2c_write_data\n")); if (len > 4) return -1; while (len) { /* Set and assert the data */ GT_REG_WRITE(I2C_DATA, (unsigned int)data); RESET_REG_BITS(I2C_CONTROL, (0x1 << 3)); udelay(I2C_DELAY); GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); count++; while ((status & 0xff) != 0x28) { udelay(I2C_DELAY); if (count > 20) { GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ return status; } GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); count++; } len--; } GT_REG_WRITE(I2C_CONTROL, (0x1 << 3) | (0x1 << 4)); GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); udelay(I2C_DELAY * 10); return 0; } static uchar i2c_set_dev_offset(uchar dev_addr, unsigned int offset, int ten_bit) { uchar status; DP(puts("i2c_set_dev_offset\n")); status = i2c_select_device(dev_addr, 0, ten_bit); if (status) { #ifdef DEBUG_I2C printf("Failed to select device setting offset: 0x%02x\n", status); #endif return status; } status = i2c_write_data(offset, 1); if (status) { #ifdef DEBUG_I2C printf("Failed to write data: 0x%02x\n", status); #endif return status; } return 0; } uchar i2c_read(uchar dev_addr, unsigned int offset, int len, uchar *data, int ten_bit) { uchar status = 0; unsigned int i2cFreq = 400000; DP(puts("i2c_read\n")); i2c_init(i2cFreq, 0); status = i2c_start(); if (status) { #ifdef DEBUG_I2C printf("Transaction start failed: 0x%02x\n", status); #endif return status; } status = i2c_set_dev_offset(dev_addr, 0, 0); if (status) { #ifdef DEBUG_I2C printf("Failed to set offset: 0x%02x\n", status); #endif return status; } i2c_init(i2cFreq, 0); status = i2c_start(); if (status) { #ifdef DEBUG_I2C printf("Transaction restart failed: 0x%02x\n", status); #endif return status; } status = i2c_select_device(dev_addr, 1, ten_bit); if (status) { #ifdef DEBUG_I2C printf("Address not acknowledged: 0x%02x\n", status); #endif return status; } status = i2c_get_data(data, len); if (status) { #ifdef DEBUG_I2C printf("Data not received: 0x%02x\n", status); #endif return status; } return 0; }