#ifndef __QSPI_FLASH_H__
#define __QSPI_FLASH_H__

#include "stm32h7xx_hal.h"

/* Definition for QSPI clock resources */
#define QSPI_CLK_ENABLE()              __HAL_RCC_QSPI_CLK_ENABLE()
#define QSPI_CLK_DISABLE()             __HAL_RCC_QSPI_CLK_DISABLE()
#define QSPI_CLK_GPIO_CLK_ENABLE()     __HAL_RCC_GPIOB_CLK_ENABLE()
#define QSPI_BK1_CS_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOB_CLK_ENABLE()
#define QSPI_BK1_D0_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D1_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D2_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOE_CLK_ENABLE()
#define QSPI_BK1_D3_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOD_CLK_ENABLE()

#define QSPI_MDMA_CLK_ENABLE()         __HAL_RCC_MDMA_CLK_ENABLE()

#define QSPI_FORCE_RESET()             __HAL_RCC_QSPI_FORCE_RESET()
#define QSPI_RELEASE_RESET()           __HAL_RCC_QSPI_RELEASE_RESET()

/* Definition for QSPI Pins */
#define QSPI_CLK_PIN               GPIO_PIN_2
#define QSPI_CLK_GPIO_PORT         GPIOB
/* Bank 1 */
#define QSPI_BK1_CS_PIN            GPIO_PIN_6
#define QSPI_BK1_CS_GPIO_PORT      GPIOB
#define QSPI_BK1_D0_PIN            GPIO_PIN_11
#define QSPI_BK1_D0_GPIO_PORT      GPIOD
#define QSPI_BK1_D1_PIN            GPIO_PIN_12
#define QSPI_BK1_D1_GPIO_PORT      GPIOD
#define QSPI_BK1_D2_PIN            GPIO_PIN_2
#define QSPI_BK1_D2_GPIO_PORT      GPIOE
#define QSPI_BK1_D3_PIN            GPIO_PIN_13
#define QSPI_BK1_D3_GPIO_PORT      GPIOD

/* W25Q64JV memory */
/* Size of the flash */
#define QSPI_FLASH_SIZE                      22
#define QSPI_PAGE_SIZE                       256

/* Reset Operations */
#define RESET_ENABLE_CMD                     0x66
#define RESET_MEMORY_CMD                     0x99

/* Identification Operations */
#define READ_ID_CMD                          0x9F
#define READ_SERIAL_FLASH_DISCO_PARAM_CMD    0x5A

/* Read Operations */
#define READ_CMD                             0x03
#define FAST_READ_CMD                        0x0B
#define DUAL_OUT_FAST_READ_CMD               0x3B
#define DUAL_INOUT_FAST_READ_CMD             0xBB
#define QUAD_OUT_FAST_READ_CMD               0x6B
#define QUAD_INOUT_FAST_READ_CMD             0xEB

/* Write Operations */
#define WRITE_ENABLE_CMD                     0x06
#define WRITE_DISABLE_CMD                    0x04

/* Register Operations */
#define READ_STATUS_REG_CMD                  0x05
#define WRITE_STATUS_REG_CMD                 0x01

/* Program Operations */
#define PAGE_PROG_CMD                        0x02
#define QUAD_IN_FAST_PROG_CMD                0x32

/* Erase Operations */
#define SECTOR_ERASE_CMD                     0x20 /* 4K-bytes */
#define SUBBLOCK_ERASE_CMD                   0x52 /* 32K-bytes */
#define BLOCK_ERASE_CMD                      0xD8 /* 64K-bytes */
#define CHIP_ERASE_CMD                       0xC7

#define PROG_ERASE_RESUME_CMD                0x7A
#define PROG_ERASE_SUSPEND_CMD               0x75

/* Quad Operations */
#define ENTER_QUAD_CMD                       0x38
#define EXIT_QUAD_CMD                        0xFF

/* Default dummy clocks cycles */
#define DUMMY_CLOCK_CYCLES_READ              8
#define DUMMY_CLOCK_CYCLES_READ_QUAD         8

/* End address of the QSPI memory */
#define QSPI_END_ADDR                        (1 << (QSPI_FLASH_SIZE + 1))

#ifdef __cplusplus
 extern "C" {
#endif

void qspi_flash_init(uint32_t div);
void qspi_flash_deinit(void);
uint32_t qspi_flash_write(uint32_t addr, uint8_t *data, uint32_t length);
uint32_t qspi_flash_read(uint32_t addr, uint8_t *data, uint32_t length);
uint32_t qspi_flash_erase_4kbytes(uint32_t addr);
uint32_t qspi_flash_erase_32kbytes(uint32_t addr);
uint32_t qspi_flash_erase_64kbytes(uint32_t addr);

#ifdef __cplusplus
}
#endif

#endif /* __QSPI_FLASH_H__ */
