diff options
Diffstat (limited to 'drivers/i2c/aspeed_i2c.c')
-rwxr-xr-x | drivers/i2c/aspeed_i2c.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/drivers/i2c/aspeed_i2c.c b/drivers/i2c/aspeed_i2c.c new file mode 100755 index 0000000000..ff6c7565ba --- /dev/null +++ b/drivers/i2c/aspeed_i2c.c @@ -0,0 +1,286 @@ +/* + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/arch/aspeed_i2c.h> + +#ifdef CONFIG_DRIVER_ASPEED_I2C + +void i2c_init (int speed, int slaveadd) +{ + unsigned long SCURegister; +//I2C Reset + SCURegister = inl (SCU_BASE + SCU_RESET_CONTROL); + outl (SCURegister & ~(0x04), SCU_BASE + SCU_RESET_CONTROL); +//I2C Multi-Pin + SCURegister = inl (SCU_BASE + SCU_MULTIFUNCTION_PIN_CTL5_REG); + outl ((SCURegister | 0x30000), SCU_BASE + SCU_MULTIFUNCTION_PIN_CTL5_REG); +//Reset + outl (0, I2C_FUNCTION_CONTROL_REGISTER); +//Set AC Timing, we use fix AC timing for eeprom in u-boot + outl (AC_TIMING, I2C_AC_TIMING_REGISTER_1); + outl (0, I2C_AC_TIMING_REGISTER_2); +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); +//Enable Master Mode + outl (MASTER_ENABLE, I2C_FUNCTION_CONTROL_REGISTER); +//Enable Interrupt, STOP Interrupt has bug in AST2000 + outl (0xAF, I2C_INTERRUPT_CONTROL_REGISTER); +//Set Slave address, should not use for eeprom + outl (slaveadd, I2C_DEVICE_ADDRESS_REGISTER); +} + +static int i2c_read_byte (u8 devaddr, u16 regoffset, u8 * value, int alen) +{ + int i2c_error = 0; + u32 status, count = 0; + +//Start and Send Device Address + outl (devaddr, I2C_BYTE_BUFFER_REGISTER); + outl (MASTER_START_COMMAND | MASTER_TX_COMMAND, I2C_COMMAND_REGISTER); +//Wait Tx ACK + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & (TX_ACK | TX_NACK)); + count++; + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Start and Send Device Address can't get ACK back\n"); + return i2c_error; + } + } while (status != TX_ACK); + count = 0; +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); +//Check if address length equals to 16bits + if (alen != 1) { +//Send Device Register Offset (HIGH BYTE) + outl ((regoffset & 0xFF00) >> 8, I2C_BYTE_BUFFER_REGISTER); + outl (MASTER_TX_COMMAND, I2C_COMMAND_REGISTER); +//Wait Tx ACK + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & (TX_ACK | TX_NACK)); + count++; + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Send Device Register Offset can't get ACK back\n"); + return i2c_error; + } + } while (status != TX_ACK); + count = 0; +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); + } +//Send Device Register Offset(LOW) + outl (regoffset & 0xFF, I2C_BYTE_BUFFER_REGISTER); + outl (MASTER_TX_COMMAND, I2C_COMMAND_REGISTER); +//Wait Tx ACK + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & (TX_ACK | TX_NACK)); + count++; + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Send Device Register Offset can't get ACK back\n"); + return i2c_error; + } + } while (status != TX_ACK); + count = 0; +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); +//Start, Send Device Address + 1 (Read Mode), Receive Data + outl (devaddr + 1, I2C_BYTE_BUFFER_REGISTER); + outl (MASTER_START_COMMAND | MASTER_TX_COMMAND | MASTER_RX_COMMAND | RX_COMMAND_LIST, I2C_COMMAND_REGISTER); +//Wait Rx Done + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & RX_DONE); + count++; + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Can't get RX_DONE back\n"); + return i2c_error; + } + } while (status != RX_DONE); + count = 0; +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); +//Enable Interrupt + Stop Interrupt + outl (0xBF, I2C_INTERRUPT_CONTROL_REGISTER); +//Issue Stop Command + outl (MASTER_STOP_COMMAND, I2C_COMMAND_REGISTER); +//Wait Stop + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & STOP_DONE); + count++; + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Can't get STOP back\n"); + return i2c_error; + } + } while (status != STOP_DONE); +//Disable Stop Interrupt + outl (0xAF, I2C_INTERRUPT_CONTROL_REGISTER); +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); +//Read Received Data + *value = ((inl (I2C_BYTE_BUFFER_REGISTER) & 0xFF00) >> 8); + + return i2c_error; +} + +static int i2c_write_byte (u8 devaddr, u16 regoffset, u8 value, int alen) +{ + int i2c_error = 0; + u32 status, count = 0; + +//Start and Send Device Address + outl (devaddr, I2C_BYTE_BUFFER_REGISTER); + outl (MASTER_START_COMMAND | MASTER_TX_COMMAND, I2C_COMMAND_REGISTER); +//Wait Tx ACK + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & (TX_ACK | TX_NACK)); + count++; + if (status == TX_NACK) { +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); +//Re-send Start and Send Device Address while NACK return + outl (devaddr, I2C_BYTE_BUFFER_REGISTER); + outl (MASTER_START_COMMAND | MASTER_TX_COMMAND, I2C_COMMAND_REGISTER); + } + else { + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Start and Send Device Address can't get ACK back\n"); + return i2c_error; + } + } + } while (status != TX_ACK); + count = 0; +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); +//Check if address length equals to 16bits + if (alen != 1) { +//Send Device Register Offset (HIGH BYTE) + outl ((regoffset & 0xFF00) >> 8, I2C_BYTE_BUFFER_REGISTER); + outl (MASTER_TX_COMMAND, I2C_COMMAND_REGISTER); +//Wait Tx ACK + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & (TX_ACK | TX_NACK)); + count++; + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Send Device Register Offset can't get ACK back\n"); + return i2c_error; + } + } while (status != TX_ACK); + count = 0; +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); + } +//Send Device Register Offset + outl (regoffset & 0xFF, I2C_BYTE_BUFFER_REGISTER); + outl (MASTER_TX_COMMAND, I2C_COMMAND_REGISTER); +//Wait Tx ACK + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & (TX_ACK | TX_NACK)); + count++; + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Send Device Register Offset can't get ACK back\n"); + return i2c_error; + } + } while (status != TX_ACK); + count = 0; +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); +//Send Device Register Value + outl (value, I2C_BYTE_BUFFER_REGISTER); + outl (MASTER_TX_COMMAND, I2C_COMMAND_REGISTER); +//Wait Tx ACK + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & (TX_ACK | TX_NACK)); + count++; + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Send Device Register Value can't get ACK back\n"); + return i2c_error; + } + } while (status != TX_ACK); + count = 0; +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); +//Enable Interrupt + Stop Interrupt + outl (0xBF, I2C_INTERRUPT_CONTROL_REGISTER); +//Issue Stop Command + outl (MASTER_STOP_COMMAND, I2C_COMMAND_REGISTER); +//Wait Stop + do { + status = (inl (I2C_INTERRUPT_STATUS_REGISTER) & STOP_DONE); + count++; + if (count == LOOP_COUNT) { + i2c_error = 1; + printf ("Can't get STOP back\n"); + return i2c_error; + } + } while (status != STOP_DONE); +//Disable Stop Interrupt + outl (0xAF, I2C_INTERRUPT_CONTROL_REGISTER); +//Clear Interrupt + outl (ALL_CLEAR, I2C_INTERRUPT_STATUS_REGISTER); + + return i2c_error; +} + +int i2c_probe (uchar chip) +{ +//Suppose IP is always on chip + int res = 0; + + return res; +} + +int i2c_read (uchar device_addr, uint register_offset, int alen, uchar * buffer, int len) +{ + int i; + + if ((alen == 1) && ((register_offset + len) > 256)) { + printf ("Register index overflow\n"); + } + + for (i = 0; i < len; i++) { + if (i2c_read_byte (device_addr, register_offset + i, &buffer[i], alen)) { + printf ("I2C read: I/O error\n"); + i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + return 1; + } + } + + return 0; +} + +int i2c_write (uchar device_addr, uint register_offset, int alen, uchar * buffer, int len) +{ + int i; + + if ((alen == 1) && ((register_offset + len) > 256)) { + printf ("Register index overflow\n"); + } + + for (i = 0; i < len; i++) { + if (i2c_write_byte (device_addr, register_offset + i, buffer[i], alen)) { + printf ("I2C read: I/O error\n"); + i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + return 1; + } + } + + return 0; +} + +#endif /* CONFIG_DRIVER_ASPEED_I2C */ |