/****************************************************************************/
/* Copyright 2004 MBARI.                                                    */
/* Monterey Bay Aquarium Research Institute Proprietary Information.        */
/* All rights reserved.                                                     */
/****************************************************************************/

/****************************************************************************/
/*  The EEPROM size and CS pin must be specified before using eeprom.c.     */
/*  For example,                                                            */
/*                                                                          */
/*  #define EEPROM_SIZE     0x800                                           */
/*  #define EEPROM_CS_PIN   PIN_C1                                          */
/*  #include "eeprom.c"                                                     */
/****************************************************************************/

/* EEPROM commands */
#define EE_READ     0x03          
#define EE_WRITE    0x02
#define EE_WREN     0x06
#define EE_RDSR     0x05
#define EE_WRSR     0x01

/* EEPROM registers and bits */
#define SSPSTAT 0x94
#define EE_WIP  0x01

/* macro for EEPROM chip select line */
#define eepromCS(X)    output_bit(EEPROM_CS_PIN, X)
     
     
void eepromSpiSetup()
{
    byte* reg = SSPSTAT;

    setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4);
    
    /* set CKE bit in SSPSTAT */
    *reg |= 0x40;
}

void eepromWait()
{
    /* strobe the CS line */
    eepromCS(HI);
    eepromCS(LO);

    /* send read status register cmd */
    spi_write(EE_RDSR);
    
    while ( spi_read(0) & EE_WIP )
    {
        /* strobe the CS line */
        eepromCS(HI);
        eepromCS(LO);

        /* send read status register cmd */
        spi_write(EE_RDSR);
    }

    /* deassert the SPI CS */
    eepromCS(HI);
}

void eepromWren()
{
    /* strobe the CS line */
    eepromCS(HI);
    eepromCS(LO);

    /* send read status register cmd */
    spi_write(EE_WREN);

    /* deassert the SPI CS */
    eepromCS(HI);
}

char eepromRead(long address)
{
    char data;

    /* setup the SPI bus for memory access */
    eepromSpiSetup();

    /* strobe the CS line */
    eepromCS(HI);
    eepromCS(LO);

    /* issue the EEPROM read command */
    spi_write(EE_READ);

    /* write the address */
    spi_write(address >> 8);
    spi_write(address & 0x00FF);

    /* read the data */
    data = spi_read(0);

    /* deassert the SPI CS */
    eepromCS(HI);

    return data;
}

char eepromWrite(long address, char data)
{
    /* setup the SPI bus for memory access */
    eepromSpiSetup();

    /* enable writes */
    eepromWren();

    /* strobe the CS line */
    eepromCS(HI);
    eepromCS(LO);
        
    /* issue the EEPROM read command */
    spi_write(EE_WRITE);

    /* write the address */
    spi_write(address >> 8);
    spi_write(address & 0x00FF);

    /* write the data */
    spi_write(data);

    /* deassert the SPI CS */
    eepromCS(HI);

    /* wait for the write to complete */
    eepromWait();


    return ERR_SUCCESS;
}

int eepromErase()
{
    long i;
    
    /* erase part, this bone head approach can take as much as 5 secs per 1K*/
    for (i = 0; i < EEPROM_SIZE; ++i)
        eepromWrite(i, 0);

    return ERR_SUCCESS;
}

int eepromInit()
{
    /* setup the SPI bus for memory access */
    eepromSpiSetup();

    /* strobe the CS line */
    eepromCS(HI);
    eepromCS(LO);
    
    /* read the EEPROM status reg and check the BP0 and BP1 bits, if the bits 
    are high, clear them */
    spi_write(EE_RDSR);

    /* raise the CS line */
    eepromCS(HI);

    if ( spi_read(0) & 0x0C )
    {
        /* enable CS if BP bits are set */
        eepromCS(LO);
        
        /* enable writes */
        eepromWren();
        
        /* strobe the CS line */
        eepromCS(HI);
        eepromCS(LO);
        
        /* disable array protection if it's set */
        spi_write(EE_WRSR);
        spi_write(0x00);

        /* deassert the SPI CS */
        eepromCS(HI);
        
        /* wait for the write to complete */
        eepromWait();
    }

    /* deassert the SPI CS */
    eepromCS(HI);

    return ERR_SUCCESS;
}

