/*
 * w25q128.c
 *
 * Created: 12/06/2018 16:26:13
 *  Author: Ledo
 */ 

#include "w25qflash.h"
//#include "sam4e.h"

void w25q_SPI_init(uint32_t freq)
{
	//miso Pin
	ioport_set_pin_mode(PIO_PA12_IDX, IOPORT_MODE_MUX_A);
	ioport_disable_pin(PIO_PA12_IDX);
	//mosi Pin
	ioport_set_pin_mode(PIO_PA13_IDX, IOPORT_MODE_MUX_A);
	ioport_disable_pin(PIO_PA13_IDX);
	//spck Pin Pin
	ioport_set_pin_mode(PIO_PA14_IDX, IOPORT_MODE_MUX_A);
	ioport_disable_pin(PIO_PA14_IDX);

	//NPCS0 Pin (W25qflash chip select)
	//ioport_set_pin_mode(PIO_PA11_IDX, IOPORT_MODE_MUX_A);
	//ioport_disable_pin(PIO_PA11_IDX);
    pio_set_output(PIOA,WB_CS_PIN_MASK,1,0,0);
	
	//NPCS1 Pin (Ad7843 chip select)
	//ioport_set_pin_mode(PIO_PA9_IDX, IOPORT_MODE_MUX_A);
	//ioport_disable_pin(PIO_PA9_IDX);
	pio_set_output(PIOA,(1<<9),1,0,0);
	
	//Pin de proteccion de escritura WB_P a nivel alto (no prot)
	pio_set_output(PIOD,WB_P_PIN_MASK,1,0,0);
	
	spi_enable_clock(SPI);
	spi_disable(SPI);
	spi_reset(SPI);
	spi_set_lastxfer(SPI);
	spi_set_master_mode(SPI);
	spi_disable_mode_fault_detect(SPI);
	spi_disable_loopback(SPI);
	spi_set_peripheral_chip_select_value(SPI, spi_get_pcs(0));
	spi_set_fixed_peripheral_select(SPI);
	spi_disable_peripheral_select_decode(SPI);
	spi_set_delay_between_chip_select(SPI, 0);
	
    int16_t baud_div = spi_calc_baudrate_div(freq, sysclk_get_peripheral_hz());
    spi_set_transfer_delay(SPI, 0, 0,0);
    spi_set_bits_per_transfer(SPI, 0,SPI_CSR_BITS_8_BIT);
    spi_set_baudrate_div(SPI, 0, baud_div);
    spi_configure_cs_behavior(SPI, 0, SPI_CS_KEEP_LOW);
    spi_set_clock_polarity(SPI, 0, SPI_MODE_0 >> 1);
    spi_set_clock_phase(SPI, 0, ((SPI_MODE_0 & 0x1) ^ 0x1));	

	spi_enable(SPI);
}

/**
 * \brief Perform SPI master transfer.
 *
 */
uint8_t w25q_spi_master_transfer(uint8_t byte)
{
	uint8_t uc_pcs;
	uint16_t data;
	//SPIe.transfer(byte);
	spi_write(SPI, byte, 0, 0);
	/* Wait transfer done. */
	while ((spi_read_status(SPI) & SPI_SR_RDRF) == 0);
	spi_read(SPI, &data, &uc_pcs);
    return data;
}

void w25q_IO_Send_Byte(uint8_t byte)
{
	chip_select();
    w25q_spi_master_transfer(byte);
}



uint8_t w25q_IO_Get_Byte()
{
	chip_select();
	return w25q_spi_master_transfer(0);
}

void w25q_IO_Wait_Busy()
{
	/*  waste time until not busy WEL & Busy bit all be 1 (0x03). */
	while (w25q_IO_Read_StatusReg() == 0x03)
	w25q_IO_Read_StatusReg();
}



uint8_t w25q_IO_Read_StatusReg()
{
	uint8_t byte = 0;
	chip_select();   /* enable device */
	w25q_IO_Send_Byte(W25P_ReadStatusReg); /* send Read Status Register command */
	byte = w25q_IO_Get_Byte();   /* receive byte */
	chip_deselect();    /* disable device */
	return byte;
}




void w25q_IO_Write_StatusReg(uint8_t byte)
{
	chip_select();    /* enable device */
	w25q_IO_Send_Byte(W25P_WriteStatusReg); /* select write to status register */
	w25q_IO_Send_Byte(byte); /* data that will change the status(only bits 2,3,7 can be written) */
	chip_deselect();    /* disable the device */
}

void w25q_IO_Write_Enable()
{
	chip_unprotect();
	chip_select();   /* enable device */
	w25q_IO_Send_Byte(W25P_WriteEnable); /* send W25P_Write_Enable command */
	chip_deselect();   /* disable device */
}




void w25q_IO_PowerDown()
{
	chip_select();    /* enable device */
	w25q_IO_Send_Byte(W25P_PowerDown);  /* send W25P_PowerDown command 0xB9 */
	chip_deselect();    /* disable device */
	delay_us(3);    /* remain CS high for tPD = 3uS */
}




void w25q_IO_ReleasePowerDown()
{
	chip_select();   /* enable device */
	w25q_IO_Send_Byte(W25P_ReleasePowerDown); /* send W25P_PowerDown command 0xAB */
	chip_deselect();    /* disable device */
	delay_us(3);    /* remain CS high for tPD = 3uS */
}


uint8_t IO_Read_ID1()
{
	uint8_t byte;
	chip_select();  /* enable device */
	w25q_IO_Send_Byte(W25P_DeviceID); /* send read device ID command (ABh) */
	w25q_IO_Send_Byte(0);  /* send address */
	w25q_IO_Send_Byte(0);  /* send address */
	w25q_IO_Send_Byte(0);  /* send 3_Dummy address */
	byte = w25q_IO_Get_Byte();  /* receive Device ID byte */
	chip_deselect();   /* disable device */
	delay_us(2);   /* remain CS high for tRES2 = 1.8uS */
	return byte;
}




uint16_t w25q_IO_Read_ID2(uint8_t ID_Addr)
{
	uint16_t IData16;
	chip_select();   /* enable device */
	w25q_IO_Send_Byte(W25P_ManufactDeviceID); /* send read ID command (90h) */
	w25q_IO_Send_Byte(0x00);   /* send address */
	w25q_IO_Send_Byte(0x00);   /* send address */
	w25q_IO_Send_Byte(ID_Addr);   /* send W25Pxx selectable ID address 00H or 01H */
	IData16 = w25q_IO_Get_Byte()<<8;  /* receive Manufature or Device ID byte */
	IData16 |= w25q_IO_Get_Byte();  /* receive Device or Manufacture ID byte */
	chip_deselect();    /* disable device */
	return IData16;
}


uint16_t w25q_IO_Read_ID3()
{
	uint16_t IData16;
	chip_select();   /* enable device */
	w25q_IO_Send_Byte(R_JEDEC_ID); /* send read ID command (9Fh) */
	IData16 = w25q_IO_Get_Byte()<<8;  /* receive Manufature or Device ID byte */
	IData16 |= w25q_IO_Get_Byte();  /* receive Device or Manufacture ID byte */
	tx_buff[2] = w25q_IO_Get_Byte();
	chip_deselect();    /* disable device */
	return IData16;
}




uint8_t w25q_IO_Read_Byte(unsigned long Dst_Addr)
{
	uint8_t byte = 0;
	chip_select();     /* enable device */
	w25q_IO_Send_Byte(W25P_ReadData);    /* read command */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFFFF) >> 16)); /* send 3 address bytes */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFF) >> 8));
	w25q_IO_Send_Byte(Dst_Addr & 0xFF);
	byte = w25q_IO_Get_Byte();
	chip_deselect();   /* disable device */
	return byte;   /* return one byte read */
}

void w25q_IO_Read_nBytes(unsigned long Dst_Addr, uint16_t nBytes_128)
{
	unsigned long i = 0;
	
	chip_select();     /* enable device */
	w25q_IO_Send_Byte(W25P_ReadData);    /* read command */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFFFF) >> 16));  /* send 3 address bytes */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFF) >> 8));
	w25q_IO_Send_Byte(Dst_Addr & 0xFF);
	for (i = 0; i < nBytes_128; i++)  /* read until no_bytes is reached */
	{
		temp_buffer[i] = w25q_IO_Get_Byte(); /* receive byte and store at address 80H - FFH */
	}
	
	chip_deselect();    /* disable device */
	
}




uint8_t w25q_IO_FastRead_Byte(unsigned long Dst_Addr)
{
	uint8_t byte = 0;
	chip_select();     /* enable device */
	w25q_IO_Send_Byte(W25P_FastReadData);   /* fast read command */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFFFF) >> 16)); /* send 3 address bytes */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFF) >> 8));
	w25q_IO_Send_Byte(Dst_Addr & 0xFF);
	w25q_IO_Send_Byte(0xFF);  /*dummy byte*/
	byte = w25q_IO_Get_Byte();
	chip_deselect();   /* disable device */
	
	return byte;   /* return one byte read */
}


void w25q_IO_FastRead_nBytes(uint32_t Dst_Addr, uint16_t nBytes_128)
{
	uint8_t i = 0;
	
	chip_select();     /* enable device */
	w25q_IO_Send_Byte(W25P_FastReadData);   /* read command */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFFFF) >> 16));  /* send 3 address bytes */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFF) >> 8));
	w25q_IO_Send_Byte(Dst_Addr & 0xFF);
	w25q_IO_Send_Byte(0xFF);   /*dummy byte*/
	for (i = 0; i < nBytes_128; i++) /* read until no_bytes is reached */
	{
		temp_buffer[i] = w25q_IO_Get_Byte(); /* receive byte and store at address 80H - FFH */
	}
	chip_deselect();    /* disable device */

}


void w25q_IO_Write_Byte(uint32_t Dst_Addr, uint8_t byte)
{
	chip_select();    /* enable device */
	w25q_IO_Write_Enable();    /* set WEL */
	w25q_IO_Wait_Busy();
	
	chip_select();
	w25q_IO_Send_Byte(W25P_PageProgram);   /* send Byte Program command */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFFFF) >> 16)); /* send 3 address bytes */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFF) >> 8));
	w25q_IO_Send_Byte(Dst_Addr & 0xFF);
	w25q_IO_Send_Byte(byte);   /* send byte to be programmed */
	chip_deselect();    /* disable device */
}




void w25q_IO_Write_nBytes(uint32_t Dst_Addr, uint16_t nBytes_128)
{
	uint16_t i;
	uint8_t byte;
	chip_select();     /* enable device */
	w25q_IO_Write_Enable();    /* set WEL */
	chip_select();
	w25q_IO_Send_Byte(W25P_PageProgram);   /* send Byte Program command */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFFFF) >> 16)); /* send 3 address bytes */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFF) >> 8));
	w25q_IO_Send_Byte(Dst_Addr & 0xFF);
	
	for (i = 0; i < nBytes_128; i++)
	{
		byte = temp_buffer[i];
		w25q_IO_Send_Byte(byte);  /* send byte to be programmed */
	}
	chip_deselect();   /* disable device */
	
	//printf("\nPage program (%d nBytes)! please waiting....\n");
}




void w25q_IO_Erase_Chip()
{
	chip_select();    /* enable device */
	w25q_IO_Write_Enable();    /* set WEL */
	chip_select();
	w25q_IO_Wait_Busy();
	chip_select();
	w25q_IO_Send_Byte(W25P_ChipErase);  /* send Chip Erase command */
	chip_deselect();   /* disable device */
}


void w25q_IO_Erase_Sector(uint32_t Dst_Addr)
{
	chip_select();     /* enable device */
	w25q_IO_Write_Enable();    /* set WEL */
	chip_select();
	w25q_IO_Send_Byte(W25P_SectorErase);   /* send Sector Erase command */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFFFF) >> 16));  /* send 3 address bytes */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFF) >> 8));
	w25q_IO_Send_Byte(Dst_Addr & 0xFF);
	chip_deselect();     /* disable device */
}




void w25q_Verify(uint8_t byte, uint8_t cor_byte)
{
	if (byte != cor_byte)
	{
		while(1);
		//LED_Error = 0; /* display to view error on LED. */
	}
}




void w25q_IO_Write_Disable()
{
	chip_protect();
	chip_select();    /* enable device */
	w25q_IO_Send_Byte(W25P_WriteDisable); /* send W25P_Write_Disable command */
	chip_deselect();    /* disable device */
}

uint16_t w25q_IO_Read_word(unsigned long Dst_Addr)
{
	unsigned long i = 0;
	uint8_t bl, bh;
	chip_select();     /* enable device */
	w25q_IO_Send_Byte(W25P_ReadData);    /* read command */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFFFF) >> 16));  /* send 3 address bytes */
	w25q_IO_Send_Byte(((Dst_Addr & 0xFFFF) >> 8));
	w25q_IO_Send_Byte(Dst_Addr & 0xFF);
	bl = w25q_IO_Get_Byte(); /* receive byte and store at address 80H - FFH */
	bh = w25q_IO_Get_Byte();
	chip_deselect();    /* disable device */
	return bh << 8 | bl;
}

