/*******************************************************************************
  Filename:     bareMetalEEPROM.c
  Revised:      $Date: 2015-10-05 10:11:47 +0200 (Mon, 05. Oct 2015) $
  Revision:     $Revision: 1370 $
  Copyright:    2015 Lytentec, info@lytentec.com

  Description:  EEPROM access without RTOS driver. Use only I2C functions declared in
                C:/ti/tirtos_simplelink_2_13_00_06/products/cc26xxware_2_21_01_15600/driverlib/i2c.h

  IMPORTANT:
  YOU ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  ANYONE BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
*/
#include "stdint.h"
#include "i2c.h"

// EEPROM has 2 I2C addresses! Lower 64kByte have 0x50, higher 64kByte have 0x51
#define EEPROM_I2C_ADDRESS         0x50
#define I2CADDRESS(a) EEPROM_I2C_ADDRESS + (a & 0xFFFF0000 ? 1 : 0)

#define CPUFREQ 48000000

/***
 * Must be called once prior to any access to the eeprom. I2C must be intialized already! No pin
 * initialization nor Power domain init is done
 */
void at24CM01Init(void)
{
	I2CMasterIntDisable(I2C0_BASE);

	I2CMasterInitExpClk(I2C0_BASE, CPUFREQ, true);
}
/***
 * perform an atomic I2C write including start and stop condition.
 * No ack test is done
 */
static uint32_t i2cwrite(uint8_t slaveAddress, uint8_t *data, uint32_t len)
{
	uint32_t i;
	I2CMasterSlaveAddrSet(I2C0_BASE, slaveAddress, false);// true = about to issue a receive, false= about to issue a write.
	I2CMasterDataPut(I2C0_BASE, data[0]);// first address word
	I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);// sends a byte..
	while(I2CMasterBusy(I2C0_BASE))
		;
	i = 1;
	while (i < (len-1))
	{
		I2CMasterDataPut(I2C0_BASE, data[i]);// first address word
		I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);// sends a byte..
		while(I2CMasterBusy(I2C0_BASE))
			;
		i++;
	}
	I2CMasterDataPut(I2C0_BASE, data[i]);// first address word
	I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
	while(I2CMasterBusy(I2C0_BASE))
		;
	return 1;
}
/***
 * perform an atomic I2C read operation
 */
static void i2cread(uint8_t slaveAddress, uint8_t *data, uint32_t len)
{
	uint32_t i;
	I2CMasterSlaveAddrSet(I2C0_BASE, slaveAddress, true);// true = about to issue a receive, false= about to issue a write.
	I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
	while(I2CMasterBusy(I2C0_BASE))
		;
	data[0] = I2CMasterDataGet(I2C0_BASE);

	i = 1;
	while (i < (len-1))
	{
		I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
		while(I2CMasterBusy(I2C0_BASE))
			;
		data[i] = I2CMasterDataGet(I2C0_BASE);
		i++;
	}
	I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
	while(I2CMasterBusy(I2C0_BASE))
		;
	data[i] = I2CMasterDataGet(I2C0_BASE);
}
/***
 * Read random address range.
 * No page check is done! Memory range must be within in a 256 byte page
 */
int32_t at24CM01read(uint32_t address, uint8_t len, void * target)
{
	uint8_t data[2];
	data[1] = address & 0xFF;
	data[0] = (address >> 8) & 0xFF;
	if (i2cwrite(I2CADDRESS(address), data, 2))
	{
		i2cread(I2CADDRESS(address), (uint8_t*)target, len);
		return 1;
	}
	else
		return -1;
}
/***
 * Write random address range.
 * No page check is done! Memory range must be within in a 256 byte page
 * No ack test is done. Application must guarantee wait time to let the internal
 * write procedure finished.
 * Max one page can be written at once. Len parameter is not checked for
 */
int32_t at24CM01write(uint32_t address, uint8_t len, void * source)
{
	uint8_t data[258];
	data[1] = address & 0xFF;
	data[0] = (address >> 8) & 0xFF;
	memcpy(&data[2], source, len);
	if (i2cwrite(I2CADDRESS(address), data, 2+len))
	{
		return 1;
	}
	else
	{
		if (i2cwrite(I2CADDRESS(address), data, 2+len))
		{
			return 1;
		}
		else
		{
			return -4;
		}
	}
}
