/*
 * Copyright 2020-2023 Yuntu Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
/*!
 * @file mspwm_driver.h
 */

#ifndef MSPWM_DRIVER_H
#define MSPWM_DRIVER_H

#include <stdint.h>
#include <stdbool.h>
#include "status.h"

/*!
 * @addtogroup mspwm_driver
 * @brief mspwm driver
 * @{
 */

/*******************************************************************************
 * Macro Definitions
 ******************************************************************************/
/*! @brief Maximum value of PWM duty cycle */
#define MSPWM_MAX_DUTY_CYCLE (0x8000U)
/*! @brief Shift value which converts duty to ticks */
#define MSPWM_DUTY_TO_TICKS_SHIFT (15U)

/*******************************************************************************
 * Enumeration & Struct
 ******************************************************************************/
/*!
 * @brief loading trigger source for MOD, VAL0, VAL1, Counter and CHMASK.
 *
 * Implements : mspwm_load_trig_src_t_Class
 */
typedef enum
{
    MSPWM_DISABLE_TRIG, /*!< Disable trigger */
    MSPWM_SW_TRIG,      /*!< Select software trigger */
    MSPWM_HW_TRIG,      /*!< Select hardware trigger */
    MSPWM_SW_HW_TRIG,   /*!< Both software and hardware trigger are valid */
} mspwm_load_trig_src_t;

/*!
 * @brief loading point for MOD, VAL0 and VAL1
 *
 * Implements : mspwm_reg_load_point_t_Class
 */
typedef enum
{
    MSPWM_REG_LOAD_DISABLE,   /*!< Loading is disabled */
    MSPWM_REG_LOAD_WITH_MOD,  /*!< Loading occurs when counter matches MOD */
    MSPWM_REG_LOAD_WITH_TRIG, /*!< Loading occurs when selected trigger event happened */
} mspwm_reg_load_point_t;

/*!
 * @brief loading point for counter and CHMASK
 *
 * Implements : mspwm_load_point_t_Class
 */
typedef enum
{
    MSPWM_LOAD_WITH_REG,  /*!< Loading together with MOD, VAL0 and VAL1 */
    MSPWM_LOAD_WITH_MOD,  /*!< Loading occurs when counter matches with MOD */
    MSPWM_LOAD_WITH_TRIG, /*!< Loading occurs when selected trigger event happened */
} mspwm_load_point_t;

/*!
 * @brief window source selection
 *
 * Implements : mspwm_win_src_t_Class
 */
typedef enum
{
    MSPWM_WIN_SRC_PWM0,           /*!< Select PWM0 as the output window */
    MSPWM_WIN_SRC_PWM1,           /*!< Select PWM1 as the output window */
    MSPWM_WIN_SRC_PWM2,           /*!< Select PWM2 as the output window */
    MSPWM_WIN_SRC_PWM3,           /*!< Select PWM3 as the output window */
    MSPWM_WIN_SRC_PWM4,           /*!< Select PWM4 as the output window */
    MSPWM_WIN_SRC_PWM5,           /*!< Select PWM5 as the output window */
    MSPWM_WIN_SRC_PWM6,           /*!< Select PWM6 as the output window */
    MSPWM_WIN_SRC_PWM7,           /*!< Select PWM7 as the output window */
    MSPWM_WIN_SRC_PWM0_XNOR_PWM7, /*!< Select PWM0 xnor PWM7 as the output window */
    MSPWM_WIN_SRC_PWM2_XNOR_PWM7, /*!< Select PWM2 xnor PWM7 as the output window */
    MSPWM_WIN_SRC_PWM4_XNOR_PWM7, /*!< Select PWM4 xnor PWM7 as the output window */
    MSPWM_WIN_SRC_PWM6_XNOR_PWM7, /*!< Select PWM6 xnor PWM7 as the output window */
} mspwm_win_src_t;

/*!
 * @brief Debug mode
 *
 * Implements : mspwm_dbg_mode_t_Class
 */
typedef enum
{
    MSPWM_COUNTER_STOP, /*!< Counter stops under debug mode */
    MSPWM_COUNTER_RUN,  /*!< Counter keeps running under debug mode */
} mspwm_dbg_mode_t;

/*!
 * @brief Select PWM source in PWM mode
 *
 * Implements : mspwm_pwm_src_t_Class
 */
typedef enum
{
    MSPWM_PWM_NORMAL,        /*!< Normal mode, generated by VAL0 and VAL1 */
    MSPWM_PWM_INVERT,        /*!< Invert mode, invert PWM in normal mode */
    MSPWM_PWM_SOFTWARE,      /*!< Software mode, generated by CHSWV register */
    MSPWM_PWM_DOUBLE_SWITCH, /*!< Double switch */
} mspwm_pwm_src_t;

/*!
 * @brief Select align mode in PWM mode
 *
 * Implements : mspwm_pwm_align_mode_t_Class
 */
typedef enum
{
    MSPWM_PWM_LEFT_ALIGN,   /*!< Left align */
    MSPWM_PWM_RIGHT_ALIGN,  /*!< Right align */
    MSPWM_PWM_CENTER_ALIGN, /*!< Center align */
    MSPWM_PWM_ASYM_ALIGN,   /*!< Asymmetrical align */
} mspwm_pwm_align_mode_t;

/*!
 * @brief The unit of loading
 *
 * Implements : mspwm_load_unit_t_Class
 */
typedef enum
{
    MSPWM_LOAD_IN_DUTY_CYCLE, /*!< Unit in duty cycle, 0: always low, 0x8000: always high, 0x4000: 50% */
    MSPWM_LOAD_IN_TICKS,      /*!< Unit in ticks, that is counts */
} mspwm_load_unit_t;

/*!
 * @brief MSPWM synchronous configuration struct
 *
 * Implements : mspwm_sync_config_t_Class
 */
typedef struct
{
    uint8_t regLoadFreq; /*!< Registers loading occurs at the reloading point that meets this specified frequency */
    bool hwTrigEn;       /*!< Hardware trigger enable */
    mspwm_load_trig_src_t regLoadTrigSrc;  /*!< Loading trigger source for registers(MOD, VAL0 and VAL1) */
    mspwm_load_trig_src_t cntLoadTrigSrc;  /*!< Loading trigger source for counter */
    mspwm_load_trig_src_t maskLoadTrigSrc; /*!< Loading trigger source for CHMASK register */
    mspwm_reg_load_point_t regLoadPoint;   /*!< Loading point for registers(MOD, VAL0 and VAL1) */
    mspwm_load_point_t cntLoadPoint;       /*!< Loading point for counter */
    mspwm_load_point_t maskLoadPoint;      /*!< Loading point for CHMASK register */
} mspwm_sync_config_t;

/*!
 * @brief MSPWM output trigger channel configuration struct
 *
 * Implements : mspwm_out_trig_ch_config_t_Class
 */
typedef struct
{
    uint8_t hwChannelId; /*!< Hardware channel ID */
    bool complModeEn;    /*!< Complementary mode enable or not */
    uint16_t secVal0;    /*!< VAL0 value for trigger0/1 in complementary mode for channel n+1(second channel) */
    uint16_t secVal1;    /*!< VAL1 value for trigger0/1 in complementary mode for channel n+1(second channel) */
    bool val0Trig0En;    /*!< VAL0 trigger 0 enable */
    bool val1Trig0En;    /*!< VAL1 trigger 0 enable */
    bool val0Trig1En;    /*!< VAL0 trigger 1 enable */
    bool val1Trig1En;    /*!< VAL1 trigger 1 enable */
} mspwm_out_trig_ch_config_t;

/*!
 * @brief MSPWM output window configuration struct
 *
 * Implements : mspwm_out_win_config_t_Class
 */
typedef struct
{
    bool winEn;             /*!< Output window enable or disable */
    mspwm_win_src_t winSrc; /*!< Output window source selection */
} mspwm_out_win_config_t;

/*!
 * @brief MSPWM output trigger configuration struct
 *
 * Implements : mspwm_out_trig_config_t_Class
 */
typedef struct
{
    bool modTrig0En;    /*!< MOD trigger 0 enable */
    uint8_t trig0Freq;   /*!< Trigger 0 output occurs at the opportunity which meets the specified frequency */
    bool modTrig1En;    /*!< MOD trigger 1 enable */
    uint8_t trig1Freq;   /*!< Trigger 1 output occurs at the opportunity which meets the specified frequency */
    uint8_t channelNum; /*!< The number of channel */
    mspwm_out_trig_ch_config_t *outTrigChConfig; /*!< MSPWM output trigger channel configuration struct */
    mspwm_out_win_config_t *outWinConfig;        /*!< MSPWM output window configuration struct */
} mspwm_out_trig_config_t;

/*!
 * @brief MSPWM channel configuration struct
 *
 * Implements : mspwm_pwm_ch_config_t_Class
 */
typedef struct
{
    uint8_t hwChannelId;          /*!< Hardware channel ID */
    bool chEn;                    /*!< Channel enable or not */
    mspwm_pwm_src_t pwmSrc;       /*!< PWM source */
    bool complModeEn;             /*!< Complementary mode enable or not */
    mspwm_pwm_align_mode_t align; /*!< PWM align mode */
    mspwm_load_unit_t unit;       /*!< The unit of loading */
    uint16_t dutyCycle;           /*!< PWM duty cycle */
    uint16_t offset;              /*!< PWM rising edge offset in asymmetrical align mode */
    bool outInitVal;              /*!< Output initial value */
    bool outSwVal;                /*!< Output software value */
    bool outMaskVal;              /*!< Output mask value */
    bool outMaskEn;               /*!< Output mask enable */
    bool intEn;                   /*!< Channel interrupt when matching val0 or val1 */
} mspwm_pwm_ch_config_t;

/*!
 * @brief MSPWM module PWM configuration struct
 *
 * Implements : mspwm_pwm_config_t_Class
 */
typedef struct
{
    uint8_t channelNum;                 /*!< The number of channel */
    uint32_t freqHz;                    /*!< Counter frequency in Hz */
    bool tofIntEn;                      /*!< Timer overflow interrupt enable or not */
    mspwm_pwm_ch_config_t *pwmChConfig; /*!< Channel configuration struct array */
} mspwm_pwm_config_t;

/*!
 * @brief MSPWM module configuration struct
 *
 * Implements : mspwm_config_t_Class
 */
typedef struct
{
    uint8_t prs;                            /*!< Clock prescaler for counter */
    mspwm_dbg_mode_t dbgMode;               /*!< Debug mode */
    mspwm_sync_config_t *syncConfig;        /*!< MSPWM synchronous configuration struct */
    mspwm_pwm_config_t *pwmConfig;          /*!< MSPWM pwm configuration struct */
    mspwm_out_trig_config_t *outTrigConfig; /*!< MSPWM output trigger configuration struct */
} mspwm_config_t;

/*!
 * @brief MSPWM module state struct
 *
 * Implements : mspwm_state_t_Class
 */
typedef struct
{
    uint32_t mspwmClkSrcFreq;         /*!< MSPWM module clock source frequency(bus clock frequency) */
    uint16_t mspwmPeriod;             /*!< MSPWM module period ticks */
    uint16_t mspwmModValue;           /*!< MSPWM module MOD value */
    mspwm_load_unit_t loadUnit[8];       /*!< The unit of loading */
    mspwm_pwm_align_mode_t alignMode[8]; /*!< PWM align mode */
    uint16_t dutyCycle[8];               /*!< PWM duty cycle */
    uint16_t offset[8];                  /*!< PWM rising edge offset in asymmetrical align mode */
} mspwm_state_t;

/*!
 * @brief List of MSPWM flags
 *
 * Implements : mspwm_status_flag_t_Class
 */
typedef enum
{
    MSPWM_CHANNEL0_FLAG = 0x00000001U,      /*!< Channel 0 Flag */
    MSPWM_CHANNEL1_FLAG = 0x00000002U,      /*!< Channel 1 Flag */
    MSPWM_CHANNEL2_FLAG = 0x00000004U,      /*!< Channel 2 Flag */
    MSPWM_CHANNEL3_FLAG = 0x00000008U,      /*!< Channel 3 Flag */
    MSPWM_CHANNEL4_FLAG = 0x00000010U,      /*!< Channel 4 Flag */
    MSPWM_CHANNEL5_FLAG = 0x00000020U,      /*!< Channel 5 Flag */
    MSPWM_CHANNEL6_FLAG = 0x00000040U,      /*!< Channel 6 Flag */
    MSPWM_CHANNEL7_FLAG = 0x00000080U,      /*!< Channel 7 Flag */
    MSPWM_RELOAD_FLAG = 0x00000100U,        /*!< Reload Flag */
    MSPWM_TIME_OVERFLOW_FLAG = 0x00000200U, /*!< Time overflow Flag */
} mspwm_status_flag_t;

/*******************************************************************************
 * API Declaration
 ******************************************************************************/
/*!
 * @brief Deinitialize MSPWM module
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @return status_t
 */
status_t MSPWM_DRV_Deinit(uint32_t instance);

/*!
 * @brief Initialize MSPWM module
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] config  MSPWM module configuration struct
 * @param[in] state  MSPWM state struct
 * @return status_t
 */
status_t MSPWM_DRV_Init(uint32_t instance, const mspwm_config_t *config, mspwm_state_t *state);

/*!
 * @brief Deinitialize PWM
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] config  PWM configuration struct
 * @return status_t
 */
status_t MSPWM_DRV_DeinitPwm(uint32_t instance, mspwm_pwm_config_t *config);

/*!
 * @brief Initialize PWM
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] config  PWM configuration struct
 * @return status_t
 */
status_t MSPWM_DRV_InitPwm(uint32_t instance, const mspwm_pwm_config_t *config);

/*!
 * @brief Update duty cycle of PWM
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] channel  MSPWM channel
 * @param[in] unit  MSPWM load unit
 * @param[in] align  PWM align mode
 * @param[in] dutyCycle  Duty cycle
 * @param[in] offset  Offset of firstEdge for asymmetrical align
 * @return status_t
 */
status_t MSPWM_DRV_UpdatePwmDutyCycle(uint32_t instance,
                                      uint8_t channel,
                                      mspwm_load_unit_t unit,
                                      mspwm_pwm_align_mode_t align,
                                      uint16_t dutyCycle,
                                      uint16_t offset);

/*!
 * @brief Update the period of PWM
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] channel  MSPWM channel
 * @param[in] newFreqHz  New frequency in Hz
 * @return status_t
 */
status_t MSPWM_DRV_UpdatePwmPeriod(uint32_t instance, uint8_t channel, uint32_t newFreqHz);

/*!
 * @brief Update the period and duty cycle of PWM
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] channel  MSPWM channel
 * @param[in] newFreqHz  New frequency in Hz
 * @param[in] unit  MSPWM load unit
 * @param[in] align  PWM align mode
 * @param[in] dutyCycle  Duty cycle
 * @param[in] offset  Offset of firstEdge for asymmetrical align
 * @return status_t
 */
status_t MSPWM_DRV_UpdatePwm(uint32_t instance,
                             uint8_t channel,
                             uint32_t newFreqHz,
                             mspwm_load_unit_t unit,
                             mspwm_pwm_align_mode_t align,
                             uint16_t dutyCycle,
                             uint16_t offset);

/*!
 * @brief Set synchronous configuration
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] config  Synchronous configuration struct
 * @return status_t
 */
status_t MSPWM_DRV_SetSync(uint32_t instance, mspwm_sync_config_t *config);

/*!
 * @brief Set output trigger configuration
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] *config  Output trigger configuration struct
 * @return status_t
 */
status_t MSPWM_DRV_SetOutTrig(uint32_t instance, mspwm_out_trig_config_t *config);

/*!
 * @brief Enable MSPWM module
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_Enable(uint32_t instance);

/*!
 * @brief Disable MSPWM module
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_Disable(uint32_t instance);

/*!
 * @brief Set load ok
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_SetLdok(uint32_t instance);

/*!
 * @brief Clear load ok
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_ClearLdok(uint32_t instance);

/*!
 * @brief Set one pulse of software trigger
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_SetSoftwareTrigger(uint32_t instance);

/*!
 * @brief Set output mask
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] maskValSet  The set of output mask value
 * @param[in] maskEnSet  The set of output mask enable
 * @param[in] softwareTrigger  Software trigger enable signal
 */
void MSPWM_DRV_SetOutputMask(uint32_t instance, uint8_t maskValSet, uint8_t maskEnSet, bool softwareTrigger);

/*!
 * @brief Set output value by software
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] channel  MSPWM channel
 * @param[in] set  0 or 1 for channel
 * @return status_t
 */
void MSPWM_DRV_SetOutputSoftwareValue(uint32_t instance, uint8_t channel, uint8_t set);

/*!
 * @brief Enable overflow interrupt
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_EnableTofInt(uint32_t instance);

/*!
 * @brief Disable overflow interrupt
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_DisableTofInt(uint32_t instance);

/*!
 * @brief Enable channel n interrupt
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] channel  MSPWM channel
 */
void MSPWM_DRV_EnableChnInt(uint32_t instance, uint8_t channel);

/*!
 * @brief Disable channel n interrupt
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] channel  MSPWM channel
 */
void MSPWM_DRV_DisableChnInt(uint32_t instance, uint8_t channel);

/*!
 * @brief Clear overflow interrupt flag
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_ClearTofFlag(uint32_t instance);

/*!
 * @brief Clear reload flag
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_ClearReloadFlag(uint32_t instance);

/*!
 * @brief Clear channel n interrupt flag
 *
 * @param[in] instance  The MSPWM peripheral instance
 * @param[in] channel  MSPWM channel
 */
void MSPWM_DRV_ClearChnFlag(uint32_t instance, uint8_t channel);

/*!
 * @brief Get status flags
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
uint32_t MSPWM_DRV_GetStatusFlags(uint32_t instance);

/*!
 * @brief Enable global base
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_EnableGlobalBase(uint32_t instance);

/*!
 * @brief Disable global base
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_DisableGlobalBase(uint32_t instance);

/*!
 * @brief Generate global base signal
 *
 * @param[in] instance  The MSPWM peripheral instance
 */
void MSPWM_DRV_GenGlobalSignal(uint32_t instance);

/*! @}*/

#endif /* MSPWM_DRIVER_H */
