/**
*	@fn			spi_flash_erase
*	@brief		Erase from data from SPI flash
*	@param[IN]	u32Offset
*					Address to write to at the SPI flash
*	@param[IN]	u32Sz
*					Data size
*	@return		Status of execution
*	@note		Data size is limited by the SPI flash size only
*/ 
sint8 spi_flash_erase(uint32 u32Offset, uint32 u32Sz)
{
	uint32 i = 0;
	sint8 ret = M2M_SUCCESS;
	uint8  tmp = 0;
#ifdef PROFILING
	uint32 t;
	t = GetTickCount();
#endif
	M2M_PRINT("\r\n>Start erasing...\r\n");
	for(i = u32Offset; i < (u32Sz +u32Offset); i += (16*FLASH_PAGE_SZ))
	{
		ret += spi_flash_write_enable();
		ret += spi_flash_read_status_reg(&tmp);
		ret += spi_flash_sector_erase(i + 10);
		ret += spi_flash_read_status_reg(&tmp);
		do
		{
			if(ret != M2M_SUCCESS) goto ERR;
			ret += spi_flash_read_status_reg(&tmp);
		}while(tmp & 0x01);
		
	}
	M2M_PRINT("Done\r\n");
#ifdef PROFILING
	M2M_PRINT("#Erase time = %f sec\n", (GetTickCount()-t)/1000.0);
#endif
ERR:
	return ret;
}
/**
*	@fn			spi_flash_pp
*	@brief		Program data of size less than a page (256 bytes) at the SPI flash
*	@param[IN]	u32Offset
*					Address to write to at the SPI flash
*	@param[IN]	pu8Buf
*					Pointer to data buffer
*	@param[IN]	u32Sz
*					Data size
*	@return		Status of execution
*/
static sint8 spi_flash_pp(uint32 u32Offset, uint8 *pu8Buf, uint16 u16Sz)
{
	sint8 ret = M2M_SUCCESS;
	uint8 tmp;
	spi_flash_write_enable();
	/* use shared packet memory as temp mem */
	ret += nm_write_block(HOST_SHARE_MEM_BASE, pu8Buf, u16Sz);
	ret += spi_flash_page_program(HOST_SHARE_MEM_BASE, u32Offset, u16Sz);
	ret += spi_flash_read_status_reg(&tmp);
	do
	{
		if(ret != M2M_SUCCESS) goto ERR;
		ret += spi_flash_read_status_reg(&tmp);
	}while(tmp & 0x01);
	ret += spi_flash_write_disable();
ERR:
	return ret;
}
/**
 ****************************************************************************************
 * @brief Wait till flash is ready for next action 
* @return  Success : ERR_OK
*          Failure : ERR_TIMEOUT 
 ****************************************************************************************
 */
int8_t spi_flash_wait_till_ready (void)
{
	uint32_t statusReadCount;
	for (statusReadCount = 0; statusReadCount < MAX_READY_WAIT_COUNT; statusReadCount++)
	{
		if ((spi_flash_read_status_reg() & STATUS_BUSY) == 0)
			return ERR_OK;
	}
	return ERR_TIMEOUT;
}
/**
 ****************************************************************************************
 * @brief Selects the memory protection configuration
 * @param[in] SPI_flash_memory_protection_setting
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int32_t spi_flash_configure_memory_protection(uint8_t spi_flash_memory_protection_setting)
{
	if (spi_flash_detected_device == 0)
		return ERR_UNKNOWN_FLASH_VENDOR;        // cannot configure memory protection for an unknown device	
	
	if (spi_flash_set_write_enable() != ERR_OK) // send [Write Enable] instruction
		return ERR_TIMEOUT;   
	
	return spi_flash_write_status_reg((spi_flash_read_status_reg() & (~spi_flash_detected_device->memory_protection_bitmask)) |\
		((spi_flash_memory_protection_setting)&(spi_flash_detected_device->memory_protection_bitmask)));        
}
/**
 ****************************************************************************************
 * @brief Issue a Write Disable Command  
 * @return error code or success (ERR_OK)  
 ****************************************************************************************
 */  
int8_t spi_flash_set_write_disable(void)
{
	uint32_t commandSendCount;
	uint32_t statusReadCount;
	uint8_t status;
	if (spi_flash_wait_till_ready() == ERR_OK)
	{
		spi_set_bitmode(SPI_MODE_8BIT);           	// set SPI bitmode to 8-bit               
		for (commandSendCount = 0; commandSendCount < MAX_COMMAND_SEND_COUNT; commandSendCount++)   
		{
			spi_transaction(WRITE_DISABLE);         // send instruction              
			for (statusReadCount = 0; statusReadCount < MAX_READY_WAIT_COUNT; statusReadCount++)
			{
				status = spi_flash_read_status_reg();
				if ( ((status & STATUS_BUSY) == 0) && ((status & STATUS_WEL) == 0) ) 
					return ERR_OK;    
			}
		}
	}
	return ERR_TIMEOUT;    
}