/*
 * @file exo_io_al_stm32f7xx_qspi.c
 *
 * @brief This file contains wrapper function definition for QSPI interface
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */




#include "exo_io_al_stm32f7xx_qspi.h"
#include "exo_io_al_stm32f7xx_common.h"

#ifndef LINUX_TEMP_PORT
#include "stm32f7xx_hal.h"
#endif

/*
 * Global handle to hold qspi config info
 */
QSPI_HandleTypeDef hqspi;



/**
 * @brief TX complete callback event function
 */
static void io_hal_stm32f7xx_qspi_tx_cplt_cb(QSPI_HandleTypeDef *hqspi);

/**
 * @brief RX complete callback event function
 */
static void io_hal_stm32f7xx_qspi_rx_cplt_cb(QSPI_HandleTypeDef *hqspi);

/**
 * @brief TX and RX complete callback event function
 */
static void io_hal_stm32f7xx_qspi_cmd_cplt_cb(QSPI_HandleTypeDef *hqspi);

/**
 * @brief Abort complete callback event function
 */
static void io_hal_stm32f7xx_qspi_abort_cplt_cb(QSPI_HandleTypeDef *hqspi);

/**
 * @brief Error callback event function
 */
static void io_hal_stm32f7xx_qspi_error_cb(QSPI_HandleTypeDef *hqspi);





/**
 * @brief TX complete callback event function
 */
static void io_hal_stm32f7xx_qspi_tx_cplt_cb(QSPI_HandleTypeDef *hqspi)
{
	ioal_qspi_hdle *ioal_hqspi = NULL;
	if(HAL_SCS == get_ioal_inst_from_vd_inst(hqspi, (void**)&ioal_hqspi))
	{
		ioal_hqspi->qspi_tx_cplt_cb(ioal_hqspi);
	}
	else
	{

	}
}

/**
 * @brief RX complete callback event function
 */
static void io_hal_stm32f7xx_qspi_rx_cplt_cb(QSPI_HandleTypeDef *hqspi)
{
	ioal_qspi_hdle *ioal_hqspi = NULL;
	if(HAL_SCS == get_ioal_inst_from_vd_inst(hqspi, (void**)&ioal_hqspi))
	{
		ioal_hqspi->qspi_rx_cplt_cb(ioal_hqspi);
	}
	else
	{

	}
}

/**
 * @brief TX and RX complete callback event function
 */
static void io_hal_stm32f7xx_qspi_cmd_cplt_cb(QSPI_HandleTypeDef *hqspi)
{
	ioal_qspi_hdle *ioal_hqspi = NULL;
	if(HAL_SCS == get_ioal_inst_from_vd_inst(hqspi, (void**)&ioal_hqspi))
	{
		ioal_hqspi->qspi_cmd_cplt_cb(ioal_hqspi);
	}
	else
	{

	}
}

/**
 * @brief Abort complete callback event function
 */
static void io_hal_stm32f7xx_qspi_abort_cplt_cb(QSPI_HandleTypeDef *hqspi)
{
	ioal_qspi_hdle *ioal_hqspi = NULL;
	if(HAL_SCS == get_ioal_inst_from_vd_inst(hqspi, (void**)&ioal_hqspi))
	{
		ioal_hqspi->qspi_abort_cplt_cb(ioal_hqspi);
	}
	else
	{

	}
}

/**
 * @brief Error callback event function
 */
static void io_hal_stm32f7xx_qspi_error_cb(QSPI_HandleTypeDef *hqspi)
{
	ioal_qspi_hdle *ioal_hqspi = NULL;
	if(HAL_SCS == get_ioal_inst_from_vd_inst(hqspi, (void**)&ioal_hqspi))
	{
		ioal_hqspi->qspi_error_cb(ioal_hqspi);
	}
	else
	{

	}
}


/**
 * @brief This API initialize the control block memory of SPI1
 */
hal_ret_sts io_hal_stm32f7xx_qspi_init(ioal_qspi_hdle *ioal_hqspi)
{

	/*
	 * Initialize QSPI interface with clock, fifo length, flash memory size, etc
	 */
	hqspi.Instance = QUADSPI;
	hqspi.Init.ClockPrescaler = 2;   						// HCLK = 200 ; 200/(2+1) = 66MHZ
	hqspi.Init.FifoThreshold = 4;
	hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
    hqspi.Init.FlashSize = 25;  							//  2 power (25+1) = 64MB
	hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
	hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
	hqspi.Init.FlashID = QSPI_FLASH_ID_1;
	hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;

	if (HAL_QSPI_Init(&hqspi) != HAL_OK)
	{
		ioal_error_handler();
	}

	ioal_hqspi->intf_gen_info.vdp_intf_inst_hdle = (void*)&hqspi;
	ioal_hqspi->intf_gen_info.state = IO_FREE_STATE;


	return HAL_SCS;
}


/**
 * @brief This API initialize the control block memory of SPI1
 */
hal_ret_sts io_hal_stm32f7xx_qspi_deInit(ioal_qspi_hdle *ioal_hqspi)
{
	  if (HAL_QSPI_DeInit((QSPI_HandleTypeDef*)ioal_hqspi->intf_gen_info.vdp_intf_inst_hdle) != HAL_OK)
	  {
		  ioal_error_handler();
	  }

//	  ioal_hqspi->intf_gen_info.vdp_intf_inst_hdle = NULL;
//	  ioal_hqspi->intf_gen_info.state = IO_INVLD_STATE;
	  return HAL_SCS;
}

/**
 * @brief This API transmit the data in blocking mode
 */
hal_ret_sts io_hal_stm32f7xx_qspi_transmit(ioal_qspi_hdle *ioal_hqspi, uint8 *pdata, uint32 timeout)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	QSPI_HandleTypeDef *qspi = ioal_hqspi->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_QSPI_Transmit(qspi, pdata, timeout))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}




/**
 * @brief This API transmit the data in blocking mode
 */
hal_ret_sts io_hal_stm32f7xx_qspi_receive(ioal_qspi_hdle *ioal_hqspi, uint8 *pdata, uint32 timeout)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	QSPI_HandleTypeDef *qspi = ioal_hqspi->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_QSPI_Receive(qspi, pdata, timeout))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}


/**
 * @brief This function set the command configuration
 */
hal_ret_sts io_hal_stm32f7xx_qspi_command(ioal_qspi_hdle *ioal_hqspi, ioal_qspi_CommandTypeDef *cmd, uint32 timeout)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	QSPI_HandleTypeDef *qspi = ioal_hqspi->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_QSPI_Command(qspi, (QSPI_CommandTypeDef*)cmd, timeout))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}



/**
 * @brief This function enable memory mapped mode
 */
hal_ret_sts io_hal_stm32f7xx_qspi_memory_mapped(ioal_qspi_hdle *ioal_hqspi, ioal_qspi_CommandTypeDef *cmd, ioal_qspi_MemoryMappedTypeDef *cfg)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	QSPI_HandleTypeDef *qspi = ioal_hqspi->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_QSPI_MemoryMapped(qspi, (QSPI_CommandTypeDef*)cmd, (QSPI_MemoryMappedTypeDef*)cfg))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}


/**
 * @brief This function enable the auto polling mode
 */
hal_ret_sts io_hal_stm32f7xx_qspi_auto_polling(ioal_qspi_hdle *ioal_hqspi, ioal_qspi_CommandTypeDef *cmd, ioal_qspi_AutoPollingTypeDef *cfg, uint32 timeout)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	QSPI_HandleTypeDef *qspi = ioal_hqspi->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_QSPI_AutoPolling(qspi, (QSPI_CommandTypeDef*)cmd, (QSPI_AutoPollingTypeDef*)cfg, timeout))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}


/**
 * @brief This API register the callback event
 */
hal_ret_sts io_hal_stm32f7xx_qspi_reg_cb(ioal_qspi_hdle *ioal_hqspi, iohal_stm32_qspi_cbid cbid)
{
	hal_ret_sts sts = HAL_SCS;
	QSPI_HandleTypeDef *hqspi = ioal_hqspi->intf_gen_info.vdp_intf_inst_hdle;

	switch (cbid)
	{
	case IOHAL_STM32_QSPI_TX_CPLT_CB_ID :
		sts = HAL_QSPI_RegisterCallback(hqspi, HAL_QSPI_TX_CPLT_CB_ID, io_hal_stm32f7xx_qspi_tx_cplt_cb);
		break;

	case IOHAL_STM32_QSPI_RX_CPLT_CB_ID :
		sts = HAL_QSPI_RegisterCallback(hqspi, HAL_QSPI_RX_CPLT_CB_ID, io_hal_stm32f7xx_qspi_rx_cplt_cb);
		break;

	case IOHAL_STM32_QSPI_CMD_CPLT_CB_ID :
		sts = HAL_QSPI_RegisterCallback(hqspi, HAL_QSPI_CMD_CPLT_CB_ID, io_hal_stm32f7xx_qspi_cmd_cplt_cb);
		break;

	case IOHAL_STM32_QSPI_ABORT_CB_ID :
		sts = HAL_QSPI_RegisterCallback(hqspi, HAL_QSPI_ABORT_CB_ID, io_hal_stm32f7xx_qspi_abort_cplt_cb);
		break;

	case IOHAL_STM32_QSPI_ERROR_CB_ID :
		sts = HAL_QSPI_RegisterCallback(hqspi, HAL_QSPI_ERROR_CB_ID, io_hal_stm32f7xx_qspi_error_cb);
		break;

	default :

		sts =  HAL_IO_INVLD_CB_FN;
		break;
	}
	return sts;
}





