/*
 * Copyright 2022 MindMotion Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef __X25Q_H__
#define __X25Q_H__

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

#include "x25q_conf.h"

/*!
 * @addtogroup X25Q
 * @{
 */

/*!
 * @addtogroup X25Q_REGISTER
 * @{
 */

#define X25Q_REGISTER1_BUSY_MASK    (1u << 0u) /*!< X25Q BSUY bit in register 1. */
#define X25Q_REGISTER2_QE_MASK      (1u << 1u) /*!< X25Q QE bit in register 2. */

/*!
 * @}
 */

/*!
 * @brief Cmd of X25Q, defines the X25Q instruction.
 */
typedef enum
{
    /* read data cmd. */
    X25Q_Cmd_FaseRead       = 0x0B, /*!< Fast read by std spi or qpi. */
    X25Q_Cmd_FaseReadDual   = 0x3B, /*!< Fast read by dual spi. */
    X25Q_Cmd_FaseReadQuad   = 0x6B, /*!< Fast read by quad spi. */

    /* write enable cmd. */
    X25Q_Cmd_EnableWrite    = 0x06, /*!< Enable write. */
    X25Q_Cmd_DisableWrite   = 0x04, /*!< Disable write. */

    /* write data cmd. */
    X25Q_Cmd_WritePage      = 0x02, /*!< Write page by std spi or qpi. */
    X25Q_Cmd_WritePageQuad  = 0x32, /*!< Write page by quad spi. */

    /* erase cmd. */
    X25Q_Cmd_EraseSector    = 0x20, /*!< Erase sector. */
    X25Q_Cmd_EraseChip      = 0xC7, /*!< Erase chip. */

    /* read register cmd. */
    X25Q_Cmd_ReadRegister1  = 0x05, /*!< Read register1 value. */
    X25Q_Cmd_ReadRegister2  = 0x35, /*!< Read register2 value. */
    X25Q_Cmd_ReadRegister3  = 0x15, /*!< Read register3 value. */

    /* write register cmd. */
    X25Q_Cmd_WriteRegister1 = 0x01, /*!< Write register1 value. */
    X25Q_Cmd_WriteRegister2 = 0x31, /*!< Write register2 value. */
    X25Q_Cmd_WriteRegister3 = 0x11, /*!< Write register3 value. */

    /* get info cmd. */
    X25Q_Cmd_GetManuId      = 0x90, /*!< Get manufactor id. */

    /* qpi cmd.*/
    X25Q_Cmd_EnableQpi      = 0x38, /*!< Enable QPI mode. */
    X25Q_Cmd_DisableQpi     = 0xFF, /*!< Disable QPI mode. */
}   X25Q_Cmd_Type;

/*!
 * @brief Bus width or line mode, defines the bus width when xfer content.
 */
typedef enum
{
    X25Q_BusWidth_None  = 0u, /*!< No more content in this phase. */
    X25Q_BusWidth_1b    = 1u, /*!< Xfer content by signal line. (using MOSI or MISO xfer content). */
    X25Q_BusWidth_2b    = 2u, /*!< Xfer content by dual lines.  (using DA0 & DA1 xfer content). */
    X25Q_BusWidth_4b    = 3u, /*!< Xfer content by quad lines.  (using DA0, DA1, DA2 & DA3 xfer content). */
}   X25Q_BusWidth_Type;

/*!
 * @brief Word width, defines the word width when xfer content.
 */
typedef enum
{
    X25Q_WordWidth_8b   = 0u, /*!< The word wide is 8 bit. */
    X25Q_WordWidth_16b  = 1u, /*!< The word wide is 16 bit. */
    X25Q_WordWidth_24b  = 2u, /*!< The word wide is 24 bit. */
    X25Q_WordWidth_32b  = 3u, /*!< The word wide is 32 bit. */
}   X25Q_WordWidth_Type;

/*!
 * @brief Operation of X25Q, defines the X25Q operation mode.
 */
typedef enum
{
    X25Q_OperationMode_SPI  = 0u, /*!< Std spi, using MOSI or MISO to xfer content in data phase. */
    X25Q_OperationMode_DSPI = 1u, /*!< Dual spi, using IO0 & IO1 to xfer content in data phase. */
    X25Q_OperationMode_QSPI = 2u, /*!< Qual spi, using IO0, IO1, IO2 & IO3 to xfer content in data phase. */
    X25Q_OperationMode_QPI  = 3u, /*!< Qpi, using IO0, IO1, IO2 & IO3 to xfer content in all phase. */
}   X25Q_OperationMode_Type;

/*!
 * @brief This type of structure instance is used to record the information of X25Q device.
 */
typedef struct
{
    uint32_t                MemSize;    /*!< Record the device memory size. */
    uint32_t                SectorSize; /*!< Record the device sector size. */
    uint32_t                PageSize;   /*!< Record the device page size. */
    X25Q_OperationMode_Type OperationMode;
} X25Q_DeviceInfo_Type;

/*!
 * @brief This type of structure instance is used to keep the settings when calling the @ref X25Q_HAL_Read() or @ref X25Q_HAL_Write() to xfer data.
 */
typedef struct
{
    uint32_t            DeviceIndex;    /*!< The device index of X25Q. */

    /* cmd phase. */
    X25Q_BusWidth_Type  CmdBusWidth;    /*!< The bus width for instruction phase in this xfer process. */
    uint32_t            CmdValue;       /*!< The instruction value in this xfer process. */

    /* addr phase. */
    X25Q_BusWidth_Type  AddrBusWidth;   /*!< The bus width for addr phase in this xfer process. */
    X25Q_WordWidth_Type AddrWordWidth;  /*!< The word width for addr phase in this xfer process. */
    uint32_t            AddrValue;      /*!< The addr value in this xfer process. */

    /* dummy phase. */
    uint32_t            DummyBytes;     /*!< The num of dummy byte in this xfer process. */

    /* data phase. */
    X25Q_BusWidth_Type  DataBusWidth;   /*!< The bus width for data phase in this xfer process. */
    uint32_t            DataLen;        /*!< The length of xfer data in this xfer process. */
    uint8_t           * DataBuf;        /*!< The buffer of xfer data in this xfer process. */
} X25Q_Xfer_Type;

/* x25q_port. *****************************************************************/

/*!
 * @brief Initialize the X25Q hardware.
 *
 * @return None.
 */
void X25Q_HAL_Init(void);

/*!
 * @brief X25Q hardware read content.
 *
 * @param xfer Information of xfer data, See to @ref X25Q_Xfer_Type.
 * @return None.
 */
void X25Q_HAL_Read(X25Q_Xfer_Type * xfer);

/*!
 * @brief X25Q hardware write content.
 *
 * @param xfer Information of xfer data, See to @ref X25Q_Xfer_Type.
 * @return None.
 */
void X25Q_HAL_Write(X25Q_Xfer_Type * xfer);

/* x25q_api. ******************************************************************/

/*!
 * @brief Initialize the X25Q.
 *
 * @return None.
 */
void X25Q_Init(void);

/*!
 * @brief Get X25Q manufactor id.
 *
 * @param dev_index Device index of X25Q.
 * @return Manufactor id.
 */
uint32_t X25Q_ReadManuId(uint32_t dev_index);

/*!
 * @brief Erase X25Q chip.
 *
 * This function takes dozens of seconds to complete.
 *
 * @param dev_index Device index of X25Q.
 * @return None.
 */
void X25Q_EraseChip(uint32_t dev_index);

/*!
 * @brief Erase X25Q sector.
 *
 * @param dev_index Device index of X25Q.
 * @param addr The address of erase sector.
 * @return None.
 */
void X25Q_EraseSector(uint32_t dev_index, uint32_t addr);

/*!
 * @brief Write page to X25Q.
 *
 * The addr and size of the written data must be within the page range.
 *
 * @param dev_index Device index of X25Q.
 * @param addr The address of write data.
 * @param size The size of write data.
 * @param buf The buffer of write data.
 * @return None.
 */
void X25Q_WritePage(uint32_t dev_index, uint32_t addr, uint32_t size, uint8_t * buf);

/*!
 * @brief Write data to X25Q.
 *
 * Data of any size can be written at any address within the memsize range.
 *
 * @param dev_index Device index of X25Q.
 * @param addr The address of write data.
 * @param size The size of write data.
 * @param buf The buffer of write data.
 * @return None.
 */
void X25Q_WriteData(uint32_t dev_index, uint32_t addr, uint32_t size, uint8_t * buf);

/*!
 * @brief Read data from X25Q.
 *
 * @param dev_index Device index of X25Q.
 * @param addr The address of write data.
 * @param size The size of read data.
 * @param buf The buffer of read data.
 * @return None.
 */
void X25Q_ReadData(uint32_t dev_index, uint32_t addr, uint32_t size, uint8_t * buf);

/*!
 *@}
 */

#endif /* __X25Q_H__ */
