// i2c_ctrl.c
// 2007/12/21  H. Hagiwara , Altera Japan
// 2008/08/29  Modifications made by Nate Knight.
#include "io.h"

//#include "altera_avalon_pio_regs.h"
#include "alt_types.h"
#include "i2c_ctrl.h"
#include <stdio.h>



// a short delay of a few clock cycles
static void short_delay() 
{
  //this was their orgininal short delay .. messy!
	const int wait=100;
	volatile unsigned int delay_counter;
  for ( delay_counter = 0; delay_counter < wait; delay_counter++ );
  
  //short 5 clock tick delay
  //OSTimeDly(1);
}

// wait for the i2c to be ready - needed at lots of stages during i2c_read and
// i2c_write
static void i2c_wait_tip()
{
  while (( IORD_I2C_SR & I2C_SR_TIP ) > 0 )
  {
    // do nothing
    short_delay();
  }
}

// I2C by Troy
static void i2c_wait_ack()
{
  printf("SR1 is: %x \n",IORD_I2C_SR);
  while (( IORD_I2C_SR & I2C_SR_ACK ) > 0 )
  {
    // do nothing
    short_delay();
  }
  printf("SR2 is: %x \n",IORD_I2C_SR);
}


void i2c_write( unsigned char i2c_address,  unsigned short data )
{
	unsigned char first_byte = ( data >> 8 ) & 0xFF;
	unsigned char second_byte = ( data >> 0 ) & 0xFF;
	i2c_address <<= 1; // 1 bit shift left because the lsb is always the write_n bit.  Needs to be 0 for a write

\
  i2c_wait_tip();
  short_delay();
  IOWR_I2C_TXR(i2c_address);
  short_delay();
  IOWR_I2C_CR(I2C_CR_STA | I2C_CR_WR);
  short_delay();            // -- COMMENTED BY TROY
  i2c_wait_tip();           // -- COMMENTED BY TROY
  //i2c_wait_ack();         // -- ADDED BY TROY
  short_delay();            // -- COMMENTED BY TROY
  IOWR_I2C_TXR(first_byte);
  short_delay();            // -- COMMENTED BY TROY
  IOWR_I2C_CR(I2C_CR_WR);
  short_delay();            // -- COMMENTED BY TROY
  i2c_wait_tip();           // -- COMMENTED BY TROY
  //i2c_wait_ack();         // -- ADDED BY TROY
  short_delay();            // -- COMMENTED BY TROY
  IOWR_I2C_TXR(second_byte);
  short_delay();            // -- COMMENTED BY TROY
  //IOWR_I2C_CR(I2C_CR_WR); // -- ADDED BY TROY
  //i2c_wait_ack();         // -- ADDED BY TROY
  //IOWR_I2C_CR(I2C_CR_STO);// -- ADDED BY TROY
  IOWR_I2C_CR(I2C_CR_WR|I2C_CR_STO);
  short_delay();            // -- COMMENTED BY TROY
  i2c_wait_tip();           // -- COMMENTED BY TROY
  short_delay();            // -- COMMENTED BY TROY

}

unsigned char i2c_read( unsigned char i2c_address,  unsigned char reg )
{
  unsigned char byte;
  unsigned char device_add_wr = i2c_address << 1;
  unsigned char device_add_rd = (i2c_address << 1 | 0x1);
  /* 
  short_delay();
  IOWR_I2C_TXR(0xff);
  short_delay();
  IOWR_I2C_CR(I2C_CR_STA | I2C_CR_RD);
  short_delay();
  IOWR_I2C_CR(I2C_CR_STO);*/ 
  i2c_wait_tip();
  short_delay();
  IOWR_I2C_TXR(device_add_wr);
  short_delay();
  IOWR_I2C_CR(I2C_CR_STA | I2C_CR_WR);
  short_delay();
  i2c_wait_tip();
  short_delay();
  IOWR_I2C_TXR(reg);
  short_delay();
  IOWR_I2C_CR(I2C_CR_WR);
  short_delay();
  i2c_wait_tip();
  short_delay();
  IOWR_I2C_TXR(device_add_rd);
  short_delay();
  IOWR_I2C_CR(I2C_CR_STA | I2C_CR_WR);
  short_delay();
  i2c_wait_tip();
  short_delay();  
  IOWR_I2C_CR(I2C_CR_RD);
  short_delay();
  i2c_wait_tip();
  short_delay();
  byte = IORD_I2C_RXR;  
  IOWR_I2C_CR(I2C_CR_STO);
  short_delay();
  IOWR_I2C_TXR(0xff);
  short_delay();
  IOWR_I2C_CR(I2C_CR_STA | I2C_CR_RD);
  short_delay();
  IOWR_I2C_CR(I2C_CR_STO);
  return byte;
}

// perform some avalon master writes to initialise the I2C master core
void init_i2c()
{
    int prescale, PLO, PHI;

    // setup prescaler for I2C_CLOCKS_PER_SECOND Hz with sysclk of AV_CLOCKS_PER_SECOND Hz
    prescale = (( AV_CLOCKS_PER_SECOND / I2C_CLOCKS_PER_SECOND ) - 1 );
    IOWR_I2C_PRERLO( prescale & 0xff );
    short_delay();
    IOWR_I2C_PRERHI(( prescale & 0xff00 ) >> 8 );
    short_delay();

    // enable core
    IOWR_I2C_CTR( 0x80 );
    short_delay();
}


