/*
 * SPI_Flash.c
 *
 *  Created on: Nov 8, 2011
 *      Author: RomanM
 */

#include "hal_SPI_Flash.h"
#include "SPI_Flash.h"

/*
 * Flash memory initialization
 */
void SPI_Flash_Init(void) {
	hal_SPI_Flash_Init();
}


/*******************************************************************************
 * Read Commands
 ******************************************************************************/

/*
 * Read data from SPI flash to inBuff
 */
void SPI_Flash_ReadData(uint32_t address, uint8_t *inBuff, uint8_t n) {
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x0b);
	hal_SPI_Flash_SendAddress(address);
	hal_SPI_Flash_RW(0x00);
	hal_SPI_Flash_ReadN(inBuff, n);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Read data from SPI flash to inBuff at low frequency
 */
void SPI_Flash_ReadData_LowFreq(uint32_t address, uint8_t *inBuff, uint8_t n) {
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x03);
	hal_SPI_Flash_SendAddress(address);
	hal_SPI_Flash_ReadN(inBuff, n);
	hal_SPI_FLASH_CS_HIGH();
}


/*******************************************************************************
 * Program and Erase Commands
 ******************************************************************************/

/*
 * Block Erase 4kB
 */
void SPI_Flash_BlockErase4kB(uint32_t address) {
	SPI_Flash_WriteEnable();
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x20);
	hal_SPI_Flash_SendAddress(address);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Block Erase 32kB
 */
void SPI_Flash_BlockErase32kB(uint32_t address) {
	SPI_Flash_WriteEnable();
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x52);
	hal_SPI_Flash_SendAddress(address);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Block Erase 64kB
 */
void SPI_Flash_BlockErase64kB(uint32_t address) {
	SPI_Flash_WriteEnable();
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0xd8);
	hal_SPI_Flash_SendAddress(address);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Chip Erase
 */
void SPI_Flash_ChipErase(void) {
	SPI_Flash_WriteEnable();
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x60);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Write data to SPI flash
 */
void SPI_Flash_WriteData(uint32_t address, uint8_t *outBuff, uint8_t n) {
	uint8_t tempN;

	SPI_Flash_WriteEnable();
	while (FLASH_IS_BUSY());

	if (((address & 0x000000ff) + n) <= 0x00000100) {
		hal_SPI_FLASH_CS_LOW();
		hal_SPI_Flash_RW(0x02);
		hal_SPI_Flash_SendAddress(address);
		hal_SPI_Flash_WriteN(outBuff, n);
		hal_SPI_FLASH_CS_HIGH();
	}
	else {
		tempN = 0xff - (uint8_t)(address & 0x000000ff) + 1;

		hal_SPI_FLASH_CS_LOW();
		hal_SPI_Flash_RW(0x02);
		hal_SPI_Flash_SendAddress(address);
		hal_SPI_Flash_WriteN(outBuff, tempN);
		hal_SPI_FLASH_CS_HIGH();

		while (FLASH_IS_BUSY());
		SPI_Flash_WriteEnable();

		hal_SPI_FLASH_CS_LOW();
		hal_SPI_Flash_RW(0x02);
		hal_SPI_Flash_SendAddress(address + tempN);
		hal_SPI_Flash_WriteN(outBuff + tempN, n - tempN);
		hal_SPI_FLASH_CS_HIGH();
	}
}


/*******************************************************************************
 * Program and Erase Commands
 ******************************************************************************/

/*
 * Write Enable
 */
void SPI_Flash_WriteEnable(void) {
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x06);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Write Disable
 */
void SPI_Flash_WriteDisable(void) {
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x04);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Protect Sector
 */
void SPI_Flash_ProtectSector(uint32_t address) {
	SPI_Flash_WriteEnable();
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x36);
	hal_SPI_Flash_SendAddress(address);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Unprotect Sector
 */
void SPI_Flash_UnprotectSector(uint32_t address) {
	SPI_Flash_WriteEnable();
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x39);
	hal_SPI_Flash_SendAddress(address);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Read Sector Protection Registers
 */
uint8_t SPI_Flash_ReadProtectionRegister(uint32_t address) {
	uint8_t retValue;
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x3c);
	hal_SPI_Flash_SendAddress(address);
	retValue = hal_SPI_Flash_RW(0x00);
	hal_SPI_FLASH_CS_HIGH();

	return retValue;
}


/*******************************************************************************
 * Status Register Commands
 ******************************************************************************/

/*
 * Read status register
 */
uint8_t SPI_Flash_ReadStatus(void) {
	uint8_t returnValue;

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x05);
	returnValue = hal_SPI_Flash_RW(0x00);
	hal_SPI_FLASH_CS_HIGH();
	return returnValue;
}

/*
 * Write status register
 */
void SPI_Flash_WriteStatus(uint8_t data) {
	SPI_Flash_WriteEnable();
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x01);
	hal_SPI_Flash_RW(data);
	hal_SPI_FLASH_CS_HIGH();
}


/*******************************************************************************
 * Miscellaneous Commands
 ******************************************************************************/

/*
 * Read Manufacturer and Device ID
 */
SPI_Flash_InfoStruct_t SPI_Flash_ReadInfo(void) {
	SPI_Flash_InfoStruct_t info;

	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0x9f);
	hal_SPI_Flash_ReadN((uint8_t*)(&info), sizeof(info));
	hal_SPI_FLASH_CS_HIGH();

	return info;
}

/*
 * Deep Power-down
 */
void SPI_Flash_DeepPowerDown(void) {
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0xb9);
	hal_SPI_FLASH_CS_HIGH();
}

/*
 * Resume from Deep Power-down
 */
void SPI_Flash_Resume(void) {
	while (FLASH_IS_BUSY());

	hal_SPI_FLASH_CS_LOW();
	hal_SPI_Flash_RW(0xab);
	hal_SPI_FLASH_CS_HIGH();
}
