/**
 * \addtogroup BSP
 * \{
 * \addtogroup DEVICES
 * \{
 * \addtogroup QSPI
 * \{
 */

/**
 *****************************************************************************************
 *
 * @file hw_qspi.h
 *
 * @brief Definition of API for the QSPI Low Level Driver.
 *
 * Copyright (c) 2016, Dialog Semiconductor
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors 
 *    may be used to endorse or promote products derived from this software without 
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 *****************************************************************************************
 */

#ifndef HW_QSPI_H_
#define HW_QSPI_H_

#if dg_configUSE_HW_QSPI

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


/**
 * \brief Get the mask of a field of an QSPIC register.
 *
 * \param [in] reg is the register to access
 * \param [in] field is the register field to access
 *
 */
#define HW_QSPIC_REG_FIELD_MASK(reg, field) \
        (QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Msk)

/**
 * \brief Get the bit position of a field of an QSPIC register.
 *
 * \param [in] reg is the register to access
 * \param [in] field is the register field to access
 *
 */
#define HW_QSPIC_REG_FIELD_POS(reg, field) \
        (QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Pos)

/**
 * \brief Get the value of a field of an QSPIC register.
 *
 * \param [in] reg is the register to access
 * \param [in] field is the register field to write
 *
 * \return the value of the register field
 *
 */
#define HW_QSPIC_REG_GETF(reg, field) \
        ((QSPIC->QSPIC_##reg##_REG & (QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Msk)) >> (QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Pos))

/**
 * \brief Set the value of a field of an QSPIC register.
 *
 * \param [in] reg is the register to access
 * \param [in] field is the register field to write
 * \param [in] new_val is the value to write
 *
 */
#define HW_QSPIC_REG_SETF(reg, field, new_val) \
        QSPIC->QSPIC_##reg##_REG = ((QSPIC->QSPIC_##reg##_REG & ~(QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Msk)) | \
        ((QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Msk) & ((new_val) << (QSPIC_QSPIC_##reg##_REG_##QSPIC_##field##_Pos))))


/*
 * ENUMERATION DEFINITIONS
 *****************************************************************************************
 */

/**
 * \brief Bus mode
 *
 */
typedef enum {
        HW_QSPI_BUS_MODE_SINGLE,   /**< Bus mode in single mode */
        HW_QSPI_BUS_MODE_DUAL,     /**< Bus mode in dual mode */
        HW_QSPI_BUS_MODE_QUAD      /**< Bus mode in quad mode */
} HW_QSPI_BUS_MODE;

/**
 * \brief Flash memory address size
 *
 */
typedef enum {
        HW_QSPI_ADDR_SIZE_24,      /**< QSPI flash memory uses 24 bits address */
        HW_QSPI_ADDR_SIZE_32       /**< QSPI flash memory uses 32 bits address */
} HW_QSPI_ADDR_SIZE;

/**
 * \brief Idle clock state
 *
 */
typedef enum {
        HW_QSPI_POL_LOW = 0,        /**< SPI clock will be low at idle */
        HW_QSPI_POL_HIGH = 1        /**< SPI clock will be high at idle */
} HW_QSPI_POL;

/**
 * \brief Type of QSPI_CLK edge for sampling received data
 *
 */
typedef enum {
        HW_QSPI_SAMPLING_EDGE_POSITIVE = 0,        /**< Sample the received data with the positive edge of the QSPI_SCK */
        HW_QSPI_SAMPLING_EDGE_NEGATIVE = 1         /**< Sample the received data with the negative edge of the QSPI_SCK */
} HW_QSPI_SAMPLING_EDGE;

/**
 * \brief Selected data size of a wrapping burst
 *
 */
typedef enum {
        HW_QSPI_WRAP_SIZE_8BITS = 0,       /**< Byte access (8-bits) */
        HW_QSPI_WRAP_SIZE_16BITS = 1,      /**< Half word access (8-bits) */
        HW_QSPI_WRAP_SIZE_32BITS = 2,      /**< Word access (8-bits) */
} HW_QSPI_WRAP_SIZE;

/**
 * \brief Selected data length of a wrapping burst
 *
 */
typedef enum {
        HW_QSPI_WRAP_LEN_4BEAT = 0,        /**< 4 beat wrapping burst */
        HW_QSPI_WRAP_LEN_8BEAT = 1,        /**< 8 beat wrapping burst */
        HW_QSPI_WRAP_LEN_16BEAT = 2,       /**< 16 beat wrapping burst */
} HW_QSPI_WRAP_LEN;

/**
 * \brief Size of Burst Break Sequence
 *
 */
typedef enum {
        HW_QSPI_BREAK_SEQ_SIZE_1B = 0,     /**< One byte */
        HW_QSPI_BREAK_SEQ_SIZE_2B = 1      /**< Two bytes */
} HW_QSPI_BREAK_SEQ_SIZE;

/**
 * \brief QSPI pads slew rate control
 *
 */
typedef enum {
        HW_QSPI_SLEW_RATE_0,       /**< xx V/ns (weak) */
        HW_QSPI_SLEW_RATE_1,       /**< xx V/ns */
        HW_QSPI_SLEW_RATE_2,       /**< xx V/ns */
        HW_QSPI_SLEW_RATE_3        /**< xx V/ns (strong) */
} HW_QSPI_SLEW_RATE;

/**
 * \brief QSPI pads drive current
 *
 */
typedef enum {
        HW_QSPI_DRIVE_CURRENT_4,   /**< 4 mA */
        HW_QSPI_DRIVE_CURRENT_8,   /**< 8 mA */
        HW_QSPI_DRIVE_CURRENT_12,  /**< 12 mA */
        HW_QSPI_DRIVE_CURRENT_16,  /**< 16 mA */
} HW_QSPI_DRIVE_CURRENT;

/**
 * \brief QSPI clock divider setting
 *
 */
typedef enum {
        HW_QSPI_DIV_1 = 0,      /**< divide by 1 */
        HW_QSPI_DIV_2 = 1,      /**< divide by 2 */
        HW_QSPI_DIV_4 = 2,      /**< divide by 4 */
        HW_QSPI_DIV_8 = 3       /**< divide by 8 */
} HW_QSPI_DIV;

/**
 * \brief QSPI configuration
 *
 */
typedef struct {
        HW_QSPI_ADDR_SIZE address_size;
        HW_QSPI_POL idle_clock;
        HW_QSPI_SAMPLING_EDGE sampling_edge;
} qspi_config;

/**
 * \brief Enable CS on QSPI bus
 *
 * Use this in manual mode.
 *
 */
#if (dg_configFLASH_POWER_DOWN == 1)
__attribute__((section("text_retained")))
#endif
static inline void hw_qspi_cs_enable(void)
{
        QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_EN_CS_Msk;
}

/**
 * \brief Disable CS on QSPI bus
 *
 * Use this in manual mode.
 *
 */
#if (dg_configFLASH_POWER_DOWN == 1)
__attribute__((section("text_retained")))
#endif
static inline void hw_qspi_cs_disable(void)
{
        QSPIC->QSPIC_CTRLBUS_REG = QSPIC_QSPIC_CTRLBUS_REG_QSPIC_DIS_CS_Msk;
}

/**
 * \brief Select QSPI bus mode
 *
 * Use this in manual mode.
 *
 * \note Selecting QUAD mode will automatically configure pins IO2 and IO3 to input.
 *
 * \param [in] mode selects single/dual/quad mode for QSPI bus
 *
 */
void hw_qspi_set_bus_mode(HW_QSPI_BUS_MODE mode);

/**
 * \brief Check is SPI Bus is busy
 *
 * \return 0 - SPI Bus is idle,
 *         1 - SPI Bus is active. ReadData, WriteData or DummyData activity is in progress
 *
 */
static inline uint8_t hw_qspi_is_busy(void)
{
        return (uint8_t) QSPIC->QSPIC_STATUS_REG;
}

/**
 * \brief Generate 32 bits read transfer on QSPI bus
 *
 * The data is transferred using the selected mode of the SPI bus (SPI, Dual
 * SPI, Quad SPI).
 *
 * \return data read during read transfer
 *
 */
static inline uint32_t hw_qspi_read32(void)
{
        return QSPIC->QSPIC_READDATA_REG;
}

/**
 * \brief Generate 16 bits read transfer on QSPI bus
 *
 * The data is transferred using the selected mode of the SPI bus (SPI, Dual
 * SPI, Quad SPI).
 *
 * \return data read during read transfer
 *
 */
static inline uint16_t hw_qspi_read16(void)
{
        return *((volatile uint16_t *) &(QSPIC->QSPIC_READDATA_REG));
}

/**
 * \brief Generate 8 bits read transfer on QSPI bus
 *
 * The data is transferred using the selected mode of the SPI bus (SPI, Dual
 * SPI, Quad SPI).
 *
 * \return data read during read transfer
 *
 */
static inline uint8_t hw_qspi_read8(void)
{
        return *((volatile uint8_t *) &(QSPIC->QSPIC_READDATA_REG));
}

/**
 * \brief Generate 32 bits write transfer on QSPI bus
 *
 * The data is transferred using the selected mode of the SPI bus (SPI, Dual
 * SPI, Quad SPI).
 *
 * param [in] data data to transfer
 *
 */
static inline void hw_qspi_write32(uint32_t data)
{
        QSPIC->QSPIC_WRITEDATA_REG = data;
}

/**
 * \brief Generate 16 bits write transfer on QSPI bus
 *
 * The data is transferred using the selected mode of the SPI bus (SPI, Dual
 * SPI, Quad SPI).
 *
 * param [in] data data to transfer
 *
 */
static inline void hw_qspi_write16(uint16_t data)
{
        *((volatile uint16_t *) &(QSPIC->QSPIC_WRITEDATA_REG)) = data;
}

/**
 * \brief Generate 8 bits write transfer on QSPI bus
 *
 * The data is transferred using the selected mode of the SPI bus (SPI, Dual
 * SPI, Quad SPI).
 *
 * param [in] data data to transfer
 *
 */
#if (dg_configFLASH_POWER_DOWN == 1)
__attribute__((section("text_retained")))
#endif
static inline void hw_qspi_write8(uint8_t data)
{
        *((volatile uint8_t *) &(QSPIC->QSPIC_WRITEDATA_REG)) = data;
}

/**
 * \brief Generate a clock pulses to the SPI bus for 32 bits transfer
 *
 * During this activity in the SPI bus, the QSPI_IOx data pads are in hi-z state.
 * Number of pulses depends on selected mode of the SPI bus (SPI, Dual SPI, Quad SPI).
 *
 */
static inline void hw_qspi_dummy32(void)
{
        QSPIC->QSPIC_DUMMYDATA_REG = 0;
}

/**
 * \brief Generate a clock pulses to the SPI bus for 16 bits transfer
 *
 * During this activity in the SPI bus, the QSPI_IOx data pads are in hi-z state.
 * Number of pulses depends on selected mode of the SPI bus (SPI, Dual SPI, Quad SPI).
 *
 */
static inline void hw_qspi_dummy16(void)
{
        *((volatile uint16_t *) &(QSPIC->QSPIC_DUMMYDATA_REG)) = 0;
}

/**
 * \brief Generate a clock pulses to the SPI bus for 8 bits transfer
 *
 * During this activity in the SPI bus, the QSPI_IOx data pads are in hi-z state.
 * Number of pulses depends on selected mode of the SPI bus (SPI, Dual SPI, Quad SPI).
 *
 */
static inline void hw_qspi_dummy8(void)
{
        *((volatile uint8_t *) &(QSPIC->QSPIC_DUMMYDATA_REG)) = 0;
}

/**
 * \brief Specifies address with that flash memory uses
 *
 * The controller uses 32 of 24 bits for address during Auto mode transfer.
 *
 * \param [in] size selects 32 or 24 address size
 *
 */
static inline void hw_qspi_set_address_size(HW_QSPI_ADDR_SIZE size)
{
        HW_QSPIC_REG_SETF(CTRLMODE, USE_32BA, (size == HW_QSPI_ADDR_SIZE_32 ? 1 : 0));
}

/**
 * \brief Get address size that flash memory uses
 *
 * The controller uses 32 of 24 bits for address during Auto mode transfer.
 *
 * \return currently selected address size
 *
 * \sa hw_qspi_set_address_size
 *
 */
static inline HW_QSPI_ADDR_SIZE hw_qspi_get_address_size(void)
{
        return (HW_QSPI_ADDR_SIZE) HW_QSPIC_REG_GETF(CTRLMODE, USE_32BA);
}

/**
 * \brief Controls translation of burst accesses form AMBA bus to the QSPI bus
 *
 * \param [in] force 0 - controller translates a burst access on the AMBA bus
 *                       to a burst access on the QSPI bus. That results to a minimum
 *                       command/address phases, but the QSPI_CS is low for as
 *                       long as the access occures,
 *                   1 - controller will split a burst access on the AMBA bus
 *                       into single accesses on the qspi bus. This results to a separate
 *                       read command to the FLASH memory foreach data
 *                       required. A 4-beat word incremental AMBA access will be
 *                       split into 4 different sequences of reading (command/address/
 *                       extra clock/read data). QSPI_CS will be only high while a qspi
 *                       access occures. This results to lower power dissipation with
 *                       respect to QSPIC_FORCENSEQ_EN=0 at cost of performance
 *
 */
static inline void hw_qspi_force_nseq(uint8_t force)
{
        HW_QSPIC_REG_SETF(CTRLMODE, FORCENSEQ_EN, force);
}

/**
 * \brief Enable or disable auto mode on QSPI
 *
 * \note Selecting auto mode when any command previously configured has chosen
 * QUAD mode for any phase will automatically configure pins IO2 and IO3 to input.
 *
 * \param [in] automode true auto mode selected,
 *                      false manual mode selected
 *
 * \sa hw_qspi_set_read_instruction
 * \sa hw_qspi_set_read_status_instruction
 * \sa hw_qspi_set_suspend_resume_instructions
 * \sa hw_qspi_set_write_enable_instruction
 * \sa hw_qspi_set_extra_byte
 * \sa hw_qspi_set_erase_instruction
 * \sa hw_qspi_set_break_sequence
 *
 */
void hw_qspi_set_automode(bool automode);

/**
 * \brief Read automode state
 *
 * \return true auto mode is selected,
 *         false manual mode is selected
 *
 */
static inline bool hw_qspi_get_automode(void)
{
        return HW_QSPIC_REG_GETF(CTRLMODE, AUTO_MD);
}

/**
 * \brief Get read pipe clock delay
 *
 * \return read pipe clock delay relative to the falling edge of QSPI_SCK
 *
 */
static inline uint8_t hw_qspi_get_read_pipe_clock_delay(void)
{
        return HW_QSPIC_REG_GETF(CTRLMODE, PCLK_MD);
}

/**
 * \brief Set read pipe clock delay
 *
 * \param [in] delay read pipe clock delay relative to the falling edge of QSPI_SCK
 *                   value should be in range 0..7
 *
 */
static inline void hw_qspi_set_read_pipe_clock_delay(uint8_t delay)
{
        HW_QSPIC_REG_SETF(CTRLMODE, PCLK_MD, delay);
}

/**
 * \brief Check if read pipe is enabled
 *
 * \return 1 if read pipe is enabled, 0 otherwise
 *
 */
static inline uint8_t hw_qspi_is_read_pipe_clock_enabled(void)
{
        return HW_QSPIC_REG_GETF(CTRLMODE, RPIPE_EN);
}

/**
 * \brief Enable read pipe
 *
 * \param [in] enable 1 enable read pipe,
 *                    0 disable read pipe
 *
 */
static inline void hw_qspi_enable_readpipe(uint8_t enable)
{
        HW_QSPIC_REG_SETF(CTRLMODE, RPIPE_EN, enable);
}

/**
 * \brief Get read sampling edge
 *
 * \return type of QSPI_CLK edge for sampling received data
 *
 */
static inline HW_QSPI_SAMPLING_EDGE hw_qspi_get_read_sampling_edge(void)
{
        return HW_QSPIC_REG_GETF(CTRLMODE, RXD_NEG);
}

/**
 * \brief Set read sampling edge
 *
 * \param [in] edge sets whether read samples or taken on rising or falling edge
 *                  of QSPI_SCK
 *
 */
static inline void hw_qspi_set_read_sampling_edge(HW_QSPI_SAMPLING_EDGE edge)
{
        HW_QSPIC_REG_SETF(CTRLMODE, RXD_NEG, edge);
}

/**
 * \brief Check if hready signal is used
 *
 * \return 0 - when wait states are not added via hready signal during access to
 *             QSPIC_WRITEDATA, QSPIC_READDATA and QSPIC_DUMMYDATA registers,
 *         1 - when wait states are added via hready signal during access to
 *             QSPIC_WRITEDATA, QSPIC_READDATA and QSPIC_DUMMYDATA registers.
 *             In this case read read QSPI_STATUS register to check the end of
 *             activity at the SPI bus
 *
 */
static inline uint8_t hw_qspi_is_hready_enabled(void)
{
        return HW_QSPIC_REG_GETF(CTRLMODE, HRDY_MD);
}

/**
 * \brief Enable/disable adding wait states during register access
 *
 * \param [in] enable 0 - wait states will be added in hready signal during access to
 *                        QSPIC_WRITEDATA, QSPIC_READDATA and QSPIC_DUMMYDATA registers
 *
 */
static inline void hw_qspi_enable_hready(uint8_t enable)
{
        HW_QSPIC_REG_SETF(CTRLMODE, HRDY_MD, enable);
}

/**
 * \brief Get clock mode
 *
 * \return 0 - SPI mode 0 is used for QSPI_CLK, the QSPI_SCK is low when QSPI_CS is high (idle),
 *         1 - SPI mode 3 is used for QSPI_CLK, the QSPI_SCK is high when QSPI_CS is high (idle)
 *
 */
static inline uint8_t hw_qspi_get_clock_mode(void)
{
        return HW_QSPIC_REG_GETF(CTRLMODE, CLK_MD);
}

/**
 * \brief Set clock mode
 *
 * \param [in] mode HW_SPI_POL_LOW - SPI mode 0 is used for QSPI_CLK,
 *                      The QSPI_SCK is low when QSPI_CS is high (idle),
 *                  HW_SPI_POL_HIGH - SPI mode 3 is used for QSPI_CLK,
 *                      The QSPI_SCK is high when QSPI_CS is high (idle)
 *
 */
static inline void hw_qspi_set_clock_mode(HW_QSPI_POL mode)
{
        HW_QSPIC_REG_SETF(CTRLMODE, CLK_MD, mode);
}

/**
 * \brief Set IO2 direction
 *
 * \param [in] output QSPI_IO2 output enable. Use this only in SPI or Dual SPI
 *                    mode to control /WP signal. When the Auto Mode is selected
 *                    and the QUAD SPI is used, set this to false.
 *                    false: The QSPI_IO2 pad is input
 *                    true: The QSPI_IO2 pad is output
 *
 */
#if (dg_configFLASH_POWER_DOWN == 1)
__attribute__((section("text_retained")))
#endif
static inline void hw_qspi_set_io2_output(bool output)
{
        HW_QSPIC_REG_SETF(CTRLMODE, IO2_OEN, output);
}

/**
 * \brief Set IO3 direction
 *
 * \param [in] output Use this only in SPI or Dual SPI mode to control /HOLD signal.
 *                    When the Auto Mode is selected and the QUAD SPI is used,
 *                    set this to false.
 *                    false: The QSPI_IO3 pad is input,
 *                    true: The QSPI_IO3 pad is output
 *
 */
#if (dg_configFLASH_POWER_DOWN == 1)
__attribute__((section("text_retained")))
#endif
static inline void hw_qspi_set_io3_output(bool output)
{
        HW_QSPIC_REG_SETF(CTRLMODE, IO3_OEN, output);
}

/**
 * \brief Set state for IO2 when it's configured as output
 *
 * \param [in] val QSPI_IO2 value to set (0 or 1)
 *
 * \sa hw_qspi_set_io2_direction
 *
 */
static inline void hw_qspi_set_io2(uint8_t val)
{
        HW_QSPIC_REG_SETF(CTRLMODE, IO2_DAT, val);
}

/**
 * \brief Set state for IO3 when it's configured as output
 *
 * \param [in] val QSPI_IO3 value to set (0 or 1)
 *
 * \sa hw_qspi_set_io3_direction
 *
 */
static inline void hw_qspi_set_io3(uint8_t val)
{
        HW_QSPIC_REG_SETF(CTRLMODE, IO3_DAT, val);
}

/**
 * \brief Read state of IO2 when not in QUAD mode
 *
 * \return value of IO2 pin (0 or 1)
 *
 */
static inline uint8_t hw_qspi_get_io2(void)
{
        return HW_QSPIC_REG_GETF(CTRLMODE, IO2_DAT);
}

/**
 * \brief Read state of IO3 when not in QUAD mode
 *
 * \return value of IO3 pin (0 or 1)
 *
 */
static inline uint8_t hw_qspi_get_io3(void)
{
        return HW_QSPIC_REG_GETF(CTRLMODE, IO3_DAT);
}

/**
 * \brief Set read instructions for QSPI flash
 *
 * This function sets up instruction to be sent to flash memory when data is requested
 * on AHB bus.
 *
 * \param [in] inst instruction for Incremental Burst or Single read access.
 *                  This value is the selected instruction at the cases of incremental
 *                  burst or single read access. Also this value is used when a wrapping
 *                  burst is not supported.
 * \param [in] send_once 0 - transmit instruction at any burst access,
 *                       1 - transmit instruction only in the first access after the
 *                       selection of Auto Mode.
 * \param [in] dummy_count number of dummy bytes to send 0..4
 * \param [in] inst_phase describes the mode of the SPI bus during the instruction phase
 * \param [in] addr_phase describes the mode of the SPI bus during the address phase
 * \param [in] dummy_phase describes the mode of the SPI bus during the dummy phase
 * \param [in] data_phase describes the mode of the SPI bus during the data phase
 *
 * \sa hw_qspi_set_extra_byte
 * \sa hw_qspi_set_wrapping_burst_instruction
 *
 */
void hw_qspi_set_read_instruction(uint8_t inst, uint8_t send_once, uint8_t dummy_count,
                                                                HW_QSPI_BUS_MODE inst_phase,
                                                                HW_QSPI_BUS_MODE addr_phase,
                                                                HW_QSPI_BUS_MODE dummy_phase,
                                                                HW_QSPI_BUS_MODE data_phase);

/**
 * \brief Set wrapping burst read instructions for QSPI flash
 *
 * Calling this function will set up wrapping burst instruction to use.
 * Use this feature only when the serial FLASH memory supports a special
 * instruction for wrapping burst access.
 *
 * \param [in] inst instruction for Wrapping Burst
 * \param [in] len describes the selected length of a wrapping burst
 * \param [in] size describes the selected data size of a wrapping burst
 *
 */
void hw_qspi_set_wrapping_burst_instruction(uint8_t inst, HW_QSPI_WRAP_LEN len,
                                                                        HW_QSPI_WRAP_SIZE size);

/**
 * \brief Set extra byte to use in read instruction
 *
 * \param [in] extra_byte the value of an extra byte which will be transferred after
 *                        address. This byte is used for telling memory if it should stay
 *                        in continuous read mode or wait for normal instruction after CS
 *                        goes inactive
 * \param [in] bus_mode describes the mode of the SPI bus during the extra byte phase.
 * \param [in] half_disable_out 1 - disable (hi-z) output during the transmission
 *                              of bits [3:0] of extra byte
 *
 * \sa hw_qspi_set_read_instruction
 *
 */
void hw_qspi_set_extra_byte(uint8_t extra_byte, HW_QSPI_BUS_MODE bus_mode,
                                                                        uint8_t half_disable_out);

/**
 * \brief Set dummy byte count
 *
 * Number of dummy bytes to send when read instruction is executed.
 *
 * \param [in] count number of dummy bytes to send 0..4
 *
 */
void hw_qspi_set_dummy_bytes_count(uint8_t count);

/**
 * \brief Set number of clock when CS stays high
 *
 * \param [in] clock_count between the transmission of two different instructions to the
 *                         flash memory, the qspi bus stays in idle state (QSPI_CS high)
 *                         for at least this number of spi clock cycles. See the QSPIC_ERS_CS_HI
 *                         register for an exception
 *
 */
static inline void hw_qspi_set_min_cs_high(uint8_t clock_count)
{
        HW_QSPIC_REG_SETF(BURSTCMDB, CS_HIGH_MIN, clock_count);
}

/**
 * \brief Set up erase instructions
 *
 * Instruction will be send after call to hw_qspi_erase_block.
 *
 * \param [in] inst code value of the erase instruction
 * \param [in] inst_phase mode of the QSPI Bus during the instruction phase of the erase instruction
 * \param [in] addr_phase the mode of the QSPI Bus during the address phase of the erase instruction
 * \param [in] hclk_cycles the controller must stay without flash memory reading
 *                         requests for this number of AMBA AHB hclk cycles, before
 *                         performs the command of erase or resume 15 - 0
 * \param [in] cs_hi_cycles after the execution of instructions: write enable, erase, erase
 *                          suspend and erase resume, the QSPI_CS remains high for at
 *                          least this number of qspi bus clock cycles
 *
 * \sa hw_qspi_erase_block
 *
 */
void hw_qspi_set_erase_instruction(uint8_t inst, HW_QSPI_BUS_MODE inst_phase,
                        HW_QSPI_BUS_MODE addr_phase, uint8_t hclk_cycles, uint8_t cs_hi_cycles);

/**
 * \brief Set up write enable instruction
 *
 * Instruction setup by this function will be executed before erase.
 *
 * \param [in] write_enable code value of the write enable instruction
 * \param [in] inst_phase mode of the QSPI Bus during the instruction phase
 *
 * \sa hw_qspi_erase_block
 * \sa hw_qspi_set_erase_instruction
 *
 */
void hw_qspi_set_write_enable_instruction(uint8_t write_enable, HW_QSPI_BUS_MODE inst_phase);

/**
 * \brief Set up erase suspend/resume instructions
 *
 * \param [in] erase_suspend_inst code value of the erase suspend instruction.
 * \param [in] suspend_inst_phase mode of the QSPI Bus during the instruction phase
 *                                of the suspend instruction
 * \param [in] erase_resume_inst code value of the erase resume instruction.
 * \param [in] resume_inst_phase mode of the QSPI Bus during the instruction phase
 *                               of the resume instruction
 * \param [in] minimum_delay defines the minimum time distance between the instruction
 *                           erase suspend and the previous instruction erase resume.
 *                           This delay will be also applied after the Erase command.
 *                           0 - don't wait. The controller starts the erase suspend procedure
 *                               immediately,
 *                           1..63 - controller waits at least this number of 288kHz clock cycles
 *                                   before the suspension of erasing. Time starts counting after
 *                                   the end of the previous erase resume
 *
 */
void hw_qspi_set_suspend_resume_instructions(uint8_t erase_suspend_inst,
                                                                HW_QSPI_BUS_MODE suspend_inst_phase,
                                                                uint8_t erase_resume_inst,
                                                                HW_QSPI_BUS_MODE resume_inst_phase,
                                                                uint8_t minimum_delay);

/**
 * \brief Set status command
 *
 * This command will be send by QSPI controller when it needs to check status of flash memory.
 * This command is also send indirectly when hw_qspi_get_erase_status is called.
 *
 * \param [in] inst instruction for read status
 * \param [in] inst_phase mode of the QSPI Bus during the instruction phase of the read
 *                        status instruction
 * \param [in] receive_phase mode of the QSPI Bus during the receive status phase of
 *                           the read status instruction
 * \param [in] busy_pos it describes which bit from the bits of status represents
 *                      the Busy bit (7 - 0)
 * \param [in] busy_val defines the value of the Busy bit which means that the flash is busy
 *                      0 - flash is busy when the Busy bit is equal to 0,
 *                      1 - flash is busy when the Busy bit is equal to 1
 * \param [in] read_delay defines the minimum time distance between the instruction
 *                        read status register and previous instructions like erase or
 *                        resume. The same delay will be also applied after the Erase command.
 *                        0 - don't wait. The controller starts to read the Flash memory
 *                            status register immediately.
 *                        1..63 - controller waits at least the number of QSPI_CLK
 *                                cycles and afterwards it starts to read the Flash memory status
 *                                register. Time starts counting after the end of the previous
 *                                erase/resume.
 * \param [in] sts_delay defines the register to count the delay to wait for the FLASH Status
 *                       Register read after an erase or erase/ resume command.
 *                       0 - delay is controlled by the \p read_dealy (QSPIC_RESSTS_DLY)
 *                           which counts on the qspi clock,
 *                       1 - delay is controlled by the \p minimum_delay value passed to
 *                           hw_qspi_set_suspend_resume_instructions (QSPIC_RESSUS_DLY) which
 *                           counts on the 288 kHz clock
 *
 * \sa hw_qspi_set_suspend_resume_instructions
 * \sa hw_qspi_get_erase_status
 *
 */
void hw_qspi_set_read_status_instruction(uint8_t inst, HW_QSPI_BUS_MODE inst_phase,
                                                                HW_QSPI_BUS_MODE receive_phase,
                                                                uint8_t busy_pos,
                                                                uint8_t busy_val,
                                                                uint8_t read_delay,
                                                                uint8_t sts_delay);

/**
 * \brief Erase block/sector of flash memory
 *
 * For this function to work, erase instructions must be set up
 * with hw_qspi_set_erase_instruction.
 * User should call hw_qspi_get_erase_status to check if block erased.
 *
 * \note If user doesn't call hw_qspi_get_erase_status that returns status 0
 * QSPI controller will not be able to switch to manual mode.
 *
 * \param [in] addr memory address of block/sector thats is requested to be erased
 *                  for 24 bits addressing, bits [23:12] determine the block/sector
 *                  address bits. Bits [11:0] are ignored by the controller.
 *                  For 32 bits addressing, bits [31:12] determine the block/sectors
 *                  address bits. Bits [11:0] are ignored by the controller
 *
 * \sa hw_qspi_set_erase_instruction
 * \sa hw_qspi_get_erase_status
 * \sa hw_qspi_set_automode
 *
 */
void hw_qspi_erase_block(uint32_t addr);

/**
 * \brief Get erase status
 *
 * \return progress of sector/block erasing
 *         0 = no erase,
 *         1 = pending erase request,
 *         2 = erase procedure is running,
 *         3 = suspended erase procedure,
 *         4 = finishing the erase procedure
 *
 */
static inline uint8_t hw_qspi_get_erase_status(void)
{
        QSPIC->QSPIC_CHCKERASE_REG = 0;
        return HW_QSPIC_REG_GETF(ERASECTRL, ERS_STATE);
}

/**
 * \brief Set burst break sequence
 *
 * \param [in] sequence value will be transmitted as the burst break sequence
 * \param [in] mode mode of the QSPI Bus during the transmission of the burst break sequence
 * \param [in] size size of Burst Break Sequence
 * \param [in] dis_out disable output during the transmission of the second half (sequence[3:0]).
 *                     Setting this bit is only useful if size = 1.
 *                     0 - controller drives the QSPI bus during the transmission
 *                         of the sequence[3:0],
 *                     1 - controller leaves the QSPI bus in Hi-Z during the transmission
 *                         of the sequence[3:0]
 *
 */
void hw_qspi_set_break_sequence(uint16_t sequence, HW_QSPI_BUS_MODE mode,
                                                HW_QSPI_BREAK_SEQ_SIZE size, uint8_t dis_out);

/**
 * \brief Disable burst break sequence
 *
 */
static inline void hw_qspi_disable_burst_break_sequence(void)
{
        HW_QSPIC_REG_SETF(BURSTBRK, BRK_EN, 0);
}

/**
 * \brief Set configuration of QSPI pads
 *
 * \param [in] rate QSPI pads slew rate control
 * \param [in] current QSPI pads drive current
 *
 */
void hw_qspi_set_pads(HW_QSPI_SLEW_RATE rate, HW_QSPI_DRIVE_CURRENT current);

/**
 * \brief QSPI controller initialization
 *
 * This function will enable QSPI controller in manual mode.
 *
 * \note This function doesn't change QSPI_DIV
 *
 */
void hw_qspi_init(const qspi_config *cfg);

/**
 * \brief Enable QSPI controller clock
 *
 */
static inline void hw_qspi_enable_clock(void)
{
        CRG_TOP->CLK_AMBA_REG |= 1 << REG_POS(CRG_TOP, CLK_AMBA_REG, QSPI_ENABLE);
}

/**
 * \brief Disable QSPI controller clock
 *
 */
static inline void hw_qspi_disable_clock(void)
{
        CRG_TOP->CLK_AMBA_REG &= ~REG_MSK(CRG_TOP, CLK_AMBA_REG, QSPI_ENABLE);
}

/**
 * \brief Set the QSPI clock divider
 *
 * \param [in] div QSPI clock divider
 *
 * \sa HW_QSPI_DIV
 */
void hw_qspi_set_div(HW_QSPI_DIV div);

/**
 * \brief Get the QSPI clock divider
 *
 * \return the QSPI clock divider setting
 *
 * \sa HW_QSPI_DIV
 */
static inline HW_QSPI_DIV hw_qspi_get_div(void)
{
        return REG_GETF(CRG_TOP, CLK_AMBA_REG, QSPI_DIV);
}

#endif /* dg_configUSE_HW_QSPI */

#endif /* HW_QSPI_H_ */

/**
 * \}
 * \}
 * \}
 */
