/**
 * @brief  Disables dynamically FSMC_NAND ECC feature.
 * @param  Device: Pointer to NAND device instance
 * @param  ECCval: Pointer to ECC value
 * @param  Bank: NAND bank number
 * @param  Timeout: Timeout wait value  
 * @retval HAL status
 */
HAL_StatusTypeDef FSMC_NAND_GetECC(FSMC_NAND_TypeDef *Device, uint32_t *ECCval,
		uint32_t Bank, uint32_t Timeout) {
	uint32_t tickstart = 0U;

	/* Check the parameters */
	assert_param(IS_FSMC_NAND_DEVICE(Device));
	assert_param(IS_FSMC_NAND_BANK(Bank));

	/* Get tick */
	tickstart = HAL_GetTick();

	/* Wait until FIFO is empty */
	while (__FSMC_NAND_GET_FLAG(Device, Bank, FSMC_FLAG_FEMPT) == RESET) {
		/* Check for the Timeout */
		if (Timeout != HAL_MAX_DELAY) {
			if ((Timeout == 0U) || ((HAL_GetTick() - tickstart) > Timeout)) {
				return HAL_TIMEOUT;
			}
		}
	}

	if (Bank == FSMC_NAND_BANK2) {
		/* Get the ECCR2 register value */
		*ECCval = (uint32_t) Device->ECCR2;
	} else {
		/* Get the ECCR3 register value */
		*ECCval = (uint32_t) Device->ECCR3;
	}

	return HAL_OK;
}
/**
  * @brief  Initializes the FSMC_NAND Attribute space Timing according to the specified
  *         parameters in the FSMC_NAND_PCC_TimingTypeDef
  * @param  Device: Pointer to NAND device instance
  * @param  Timing: Pointer to NAND timing structure
  * @param  Bank: NAND bank number 
  * @retval HAL status
  */
HAL_StatusTypeDef FSMC_NAND_AttributeSpace_Timing_Init(FSMC_NAND_TypeDef *Device, FSMC_NAND_PCC_TimingTypeDef *Timing, uint32_t Bank)
{
  /* Check the parameters */ 
  assert_param(IS_FSMC_NAND_DEVICE(Device)); 
  assert_param(IS_FSMC_SETUP_TIME(Timing->SetupTime));
  assert_param(IS_FSMC_WAIT_TIME(Timing->WaitSetupTime));
  assert_param(IS_FSMC_HOLD_TIME(Timing->HoldSetupTime));
  assert_param(IS_FSMC_HIZ_TIME(Timing->HiZSetupTime));
  assert_param(IS_FSMC_NAND_BANK(Bank));
  
  if(Bank == FSMC_NAND_BANK2)
  {
    /* NAND bank 2 registers configuration */
    MODIFY_REG(Device->PATT2, PATT_CLEAR_MASK, (Timing->SetupTime                       |\
                   ((Timing->WaitSetupTime) << POSITION_VAL(FSMC_PATTx_ATTWAITx))       |\
                   ((Timing->HoldSetupTime) << POSITION_VAL(FSMC_PATTx_ATTHOLDx))       |\
                   ((Timing->HiZSetupTime) << POSITION_VAL(FSMC_PATTx_ATTHIZx))));
  }
  else
  {
    /* NAND bank 3 registers configuration */
    MODIFY_REG(Device->PATT3, PATT_CLEAR_MASK, (Timing->SetupTime                       |\
                   ((Timing->WaitSetupTime) << POSITION_VAL(FSMC_PATTx_ATTWAITx))       |\
                   ((Timing->HoldSetupTime) << POSITION_VAL(FSMC_PATTx_ATTHOLDx))       |\
                   ((Timing->HiZSetupTime) << POSITION_VAL(FSMC_PATTx_ATTHIZx))));
  }   
  
  return HAL_OK;
}
/**
  * @brief  DeInitializes the FSMC_NAND device 
  * @param  Device: Pointer to NAND device instance
  * @param  Bank: NAND bank number
  * @retval HAL status
  */
HAL_StatusTypeDef FSMC_NAND_DeInit(FSMC_NAND_TypeDef *Device, uint32_t Bank)
{
  /* Check the parameters */ 
  assert_param(IS_FSMC_NAND_DEVICE(Device)); 
  assert_param(IS_FSMC_NAND_BANK(Bank));
      
  /* Disable the NAND Bank */
  __FSMC_NAND_DISABLE(Device, Bank);
 
  /* De-initialize the NAND Bank */
  if(Bank == FSMC_NAND_BANK2)
  {
    /* Set the FSMC_NAND_BANK2 registers to their reset values */
    WRITE_REG(Device->PCR2,  0x00000018);
    WRITE_REG(Device->SR2,   0x00000040);
    WRITE_REG(Device->PMEM2, 0xFCFCFCFC);
    WRITE_REG(Device->PATT2, 0xFCFCFCFC);
  }
  /* FSMC_Bank3_NAND */  
  else
  {
    /* Set the FSMC_NAND_BANK3 registers to their reset values */
    WRITE_REG(Device->PCR3,  0x00000018);
    WRITE_REG(Device->SR3,   0x00000040);
    WRITE_REG(Device->PMEM3, 0xFCFCFCFC);
    WRITE_REG(Device->PATT3, 0xFCFCFCFC);
  }
  
  return HAL_OK;
}
/**
  * @brief  Disables dynamically FSMC_NAND ECC feature.
  * @param  Device: Pointer to NAND device instance
  * @param  Bank: NAND bank number
  * @retval HAL status
  */  
HAL_StatusTypeDef FSMC_NAND_ECC_Disable(FSMC_NAND_TypeDef *Device, uint32_t Bank)  
{  
  /* Check the parameters */ 
  assert_param(IS_FSMC_NAND_DEVICE(Device)); 
  assert_param(IS_FSMC_NAND_BANK(Bank));
    
  /* Disable ECC feature */
  if(Bank == FSMC_NAND_BANK2)
  {
    CLEAR_BIT(Device->PCR2, FSMC_PCRx_ECCEN);
  }
  else
  {
    CLEAR_BIT(Device->PCR3, FSMC_PCRx_ECCEN);
  } 

  return HAL_OK;  
}
/**
  * @brief  Initializes the FSMC_NAND device according to the specified
  *         control parameters in the FSMC_NAND_HandleTypeDef
  * @param  Device: Pointer to NAND device instance
  * @param  Init: Pointer to NAND Initialization structure
  * @retval HAL status
  */
HAL_StatusTypeDef FSMC_NAND_Init(FSMC_NAND_TypeDef *Device, FSMC_NAND_InitTypeDef *Init)
{
  /* Check the parameters */
  assert_param(IS_FSMC_NAND_DEVICE(Device));
  assert_param(IS_FSMC_NAND_BANK(Init->NandBank));
  assert_param(IS_FSMC_WAIT_FEATURE(Init->Waitfeature));
  assert_param(IS_FSMC_NAND_MEMORY_WIDTH(Init->MemoryDataWidth));
  assert_param(IS_FSMC_ECC_STATE(Init->EccComputation));
  assert_param(IS_FSMC_ECCPAGE_SIZE(Init->ECCPageSize));
  assert_param(IS_FSMC_TCLR_TIME(Init->TCLRSetupTime));
  assert_param(IS_FSMC_TAR_TIME(Init->TARSetupTime));   

  if(Init->NandBank == FSMC_NAND_BANK2)
  {
    /* NAND bank 2 registers configuration */
    MODIFY_REG(Device->PCR2, PCR_CLEAR_MASK, (Init->Waitfeature                  |\
                   FSMC_PCR_MEMORY_TYPE_NAND                                     |\
                   Init->MemoryDataWidth                                         |\
                   Init->EccComputation                                          |\
                   Init->ECCPageSize                                             |\
                   ((Init->TCLRSetupTime) << POSITION_VAL(FSMC_PCRx_TCLR))       |\
                   ((Init->TARSetupTime) << POSITION_VAL(FSMC_PCRx_TAR))));  
  }
  else
  {
    /* NAND bank 3 registers configuration */
    MODIFY_REG(Device->PCR3, PCR_CLEAR_MASK, (Init->Waitfeature                  |\
                   FSMC_PCR_MEMORY_TYPE_NAND                                     |\
                   Init->MemoryDataWidth                                         |\
                   Init->EccComputation                                          |\
                   Init->ECCPageSize                                             |\
                   ((Init->TCLRSetupTime) << POSITION_VAL(FSMC_PCRx_TCLR))       |\
                   ((Init->TARSetupTime) << POSITION_VAL(FSMC_PCRx_TAR))));  
  }
  
  return HAL_OK;

}