/**
 * \file    dpm_qc.h
 * \brief   Quick Charge process
 *
 * \par     Copyright (c) 2019 UWE Technologies Corp., Ltd. All Rights Reserved.
 * \author  James
 * \date    2019-05-29
 * \version 
 * 
 * \history 
 *  Date        Note
 *  2019-05-29  Original Creation
 * 
 */
 
#ifndef __DPM_QC_H_
#define __DPM_QC_H_


#include "types.h"
#include "usbpd_timer_defs.h"


#define DPM_BC_APPLE_SAMSUNG_MODE_ENABLED   (1)
#define DPM_QC_SNK_MODE_ENABLED             (1)


/** \name  Quick Charge Version definitions
 * \{ 
 */
#define DPM_QC_V2                           (0)         ///< 2.0
#define DPM_QC_V3                           (1)         ///< 3.0
#define DPM_QC_VER                          DPM_QC_V3   ///< default version
/** \} */

#define DPM_QC3_SRC_VOLT_INC_STEP            (200U)

/** \name Quick Charge Connection State definitions
 * \{ 
 */

#define DPM_QC_IDLE                 0x00
#define DPM_QC_SRC_STARTUP          0x01
#define DPM_QC_SRC_WAITDM           0x02
#define DPM_QC_SRC_CONNECTED        0x03
#define DPM_QC_SRC_CONNECTED_9V     0x04
#define DPM_QC_SRC_CONNECTED_12V    0x05
#define DPM_QC_SRC_CONNECTED_20V    0x06
#define DPM_QC_SRC_CONNECTED_QC3    0x07
#define DPM_QC_DISABLED             0x08
#define DPM_QC_SNK_STARTUP          0x09
#define DPM_QC_SNK_CONNECTING       0x0A
#define DPM_QC_SNK_CONNECTED_9V     0x0B
#define DPM_QC_SNK_CONNECTED_12V    0x0C
#define DPM_QC_SNK_CONNECTED_QC3    0x0D
#define DPM_QC_SNK_QC3_INC_REQ      0x0E
#define DPM_QC_SNK_QC3_DEC_REQ      0x0F

/** \}*/

/** Unit is millivolt, 200 mV */
#define DPM_QC_DM_0P325V_MIN    (200U)

/** Unit is millivolt, 900 mV */
#define DPM_QC_DM_0P325V_MAX    (900U)

/** Unit is millivolt, 300 mV */
#define DPM_QC_DM_0P6V_MIN      (300U)

/** Unit is millivolt, 900 mV */
#define DPM_QC_DM_0P6V_MAX      (900U)

/** Unit is millivolt, 2290 mV */
#define DPM_QC_DM_3P3V_MIN      (2290U)

/** Unit is millivolt, 3300 mV */
#define DPM_QC_DM_3P3V_MAX      (3600U)

/** Unit is millivolt, 2000 mV */
#define DPM_APPLE_DISCONNECT_DM_MIN    (2000U)

/** Unit is millivolt, 2875 mV */
#define DPM_APPLE_DISCONNECT_DM_MAX    (2875U)

/** Unit is millivolt, 400 mV */
#define DPM_SAMSUNG_DM_DISCONNECT_MIN  (400U)

/** Unit is millivolt, 1050 mV */
#define DPM_SAMSUNG_DM_DISCONNECT_MAX  (1050U)

/** Unit is millivolt, 900 mV */
#define DPM_SAMSUNG_DM_CONNECTED_MIN  (900U)

/** Unit is millivolt, 1400 mV */
#define DPM_SAMSUNG_DM_CONNETED_MAX  (1400U)


#define DPM_QC_VBUS_VOLT_MARGIN (500U)

#define DPM_QC_VBUS_CHANGE_STEP (200U)
#define DPM_QC_VBUS_CHANGE_MIN  (100U)
#define DPM_QC_VBUS_CHANGE_MAX  (256U)

#define DPM_QC_VBUS_5V_MIN      (4500U)
#define DPM_QC_VBUS_5V_MAX      (5500U)

#define DPM_QC_VBUS_9V_MIN      (8500U)
#define DPM_QC_VBUS_9V_MAX      (9500U)

#define DPM_QC_VBUS_12V_MIN     (11400U)
#define DPM_QC_VBUS_12V_MAX     (12600U)

#define DPM_QC_MAX_POWER        (18000000UL)

#pragma pack(1)

typedef enum DPM_QC_VOLT_INTF_TYPE_e
{
    DPM_QC_VOLT_INTF_TYPE_DP,
    DPM_QC_VOLT_INTF_TYPE_DM,
    DPM_QC_VOLT_INTF_TYPE_VBUS,
    DPM_QC_VOLT_INTF_TYPE_END
} DPM_QC_VOLT_INTF_TYPE_t;

typedef enum DPM_SRC_DPDM_MODE_e
{
    DPM_SRC_DPDM_MODE_OFF,      /* DP DM open, DM without pull down */
    DPM_SRC_DPDM_MODE_APPLE,    /* DP DM short, DP = 2.7V, DM without pull down */
    DPM_SRC_DPDM_MODE_SAMSUNG,  /* DP DM short, DP = 1.2V, DM without pull down */
    DPM_SRC_DPDM_MODE_BC,       /* DP DM short, DM without pull down */
    DPM_SRC_DPDM_MODE_QC2,      /* DP DM open, DM pull down */
    DPM_SRC_DPDM_MODE_QC3,      /* DP DM open, DM pull down, Need to enable 
                                 * interrupt trigger for DP and DM PINs, 
                                 * DP raising edge, DM falling edge
                                 */
} DPM_SRC_DPDM_MODE_t;

typedef enum DPM_QC_SNK_DPDM_MODE_e
{
    DPM_QC_SNK_DPDM_MODE_INPUT,
    DPM_QC_SNK_DPDM_MODE_LOAD_GND,
    DPM_QC_SNK_DPDM_MODE_LOAD_0P325V,
    DPM_QC_SNK_DPDM_MODE_LOAD_0P6V,
    DPM_QC_SNK_DPDM_MODE_LOAD_3P3V,
    DPM_QC_SNK_DPDM_MODE_END
} DPM_QC_SNK_DPDM_MODE_t;

typedef struct DPM_QC_INFO_s
{
    // 32 bits
    u32_t state:5;              ///< QC runtime state
    u32_t apple_samsung_mode_enabled:1; ///< Apple Samsung mode enabled flag
    u32_t dm_falling_entered:1; ///< QC src runtime flag, DM falling entered
    u32_t vbus_volt_change_req:1;   ///< QC runtime flag, vbus change request
    u32_t vbus_volt_changed:1;  ///< QC runtime flag, vbus changed flag
    u32_t is_snk:1;             ///< Indicate if it is sink mode
#if DPM_QC_SNK_MODE_ENABLED
    u32_t snk_operating_volt:15;///< QC snk operating voltage, system configuration, 20V max
    u32_t snk_qc3_req:1;        ///< QC snk runtime flag, QC3.0 request
    u32_t snk_qc3_failed:1;     ///< QC snk runtime flag, QC3.0 failed
    u32_t snk_reset_req:1;      ///< QC snk runtime flag, reset request
    u32_t snk_load_0p6v:1;      ///< QC snk runtime flag, need to try load 0.6v
    u32_t snk_change_volt_miss_cnt:3;   ///< QC snk runtime variable, miss count of changing voltage 
#else 
    u32_t reserved1:23;
#endif /* DPM_QC_SNK_MODE_ENABLED */

    // 32 bits
    u32_t src_dp_dm_mode:3;     ///< QC src runtime DP DM mode
    u32_t dm_volt:13;           ///< DM current voltage
    u32_t dm_volt_pre:13;       ///< DM previous voltage
    u32_t samsung_mode_disabled:1;
    u32_t dpm_qc_disable:1;
    u32_t qc_2p8v_judge_apple_mode_dis:1; ///< apple mode no judge 2.8v

    // 32 bits
    u32_t dp_volt:13;           ///< DP ADC current value
    u32_t dp_volt_pre:13;       ///< DP ADC previous value
    u32_t state_pre:5;          ///< QC runtime previous state
    u32_t src_v3_int_mode:1;    ///< if support interrupt mode, please set to 1

    // 32 bits
    u32_t vbus_volt:16;         ///< vbus current value
    u32_t vbus_volt_pre:16;     ///< vbus previous value

    // 64 bits
    sys_tick_t state_entered_time;
    // 64 bits
    //sys_tick_t dpdm_mode_entered_time;
    // 32 bits
    drv_timer_t dpdm_mode_timer;

    // 32 bits
    /** Get voltage callback, type: dm = 0, dp = 1, vbus = 2 */
    u32_t (*volt_get)(DPM_QC_VOLT_INTF_TYPE_t type);

    // 32 bits
    /** Get vbus voltage callback */
    bool_t (*vbus_set)(u32_t volt);

    // 32 bits
    /** QC dp dm mode, Set mode callback */
    void (*src_dpdm_mode_set)(DPM_SRC_DPDM_MODE_t mode);

#if DPM_QC_SNK_MODE_ENABLED
    // 32 bits
    /** QC dp dm mode, Set mode callback */
    void (*snk_dpdm_mode_set)(DPM_QC_SNK_DPDM_MODE_t dp, DPM_QC_SNK_DPDM_MODE_t dm);
#endif /* DPM_QC_SNK_MODE_ENABLED */

} DPM_QC_INFO_t;

#pragma pack()

#define dpm_qc_state_get(ptr) \
    (((DPM_QC_INFO_t *)(ptr))->state)

#define dpm_qc_state_set(ptr,v) \
    do { \
        ((DPM_QC_INFO_t *)(ptr))->state = v; \
    } while(0)


#if DPM_QC_SNK_MODE_ENABLED
#define dpm_qc_io_init(ptr) \
    do { \
        if (((DPM_QC_INFO_t *)(ptr))->snk_dpdm_mode_set) { \
            ((DPM_QC_INFO_t *)(ptr))->snk_dpdm_mode_set(DPM_QC_SNK_DPDM_MODE_INPUT, DPM_QC_SNK_DPDM_MODE_INPUT); \
        } \
    } while(0)

#define dpm_qc_snk_io_init(ptr) \
    do { \
        if (((DPM_QC_INFO_t *)(ptr))->snk_dpdm_mode_set) { \
            ((DPM_QC_INFO_t *)(ptr))->snk_dpdm_mode_set(DPM_QC_SNK_DPDM_MODE_LOAD_0P325V, DPM_QC_SNK_DPDM_MODE_INPUT); \
        } \
    } while(0)
#else
#define dpm_qc_io_init(ptr)
#define dpm_qc_snk_io_init(ptr)
#endif /* DPM_QC_SNK_MODE_ENABLED */

#if (!DPM_BC_APPLE_SAMSUNG_MODE_ENABLED)
#define dpm_qc_src_io_init(ptr) \
    do { \
    	((DPM_QC_INFO_t *)(ptr))->src_dpdm_mode_set(DPM_SRC_DPDM_MODE_BC); \
    } while(0)
#else
#define dpm_qc_src_io_init(ptr) \
    do { \
    	((DPM_QC_INFO_t *)(ptr))->src_dpdm_mode_set(DPM_SRC_DPDM_MODE_APPLE); \
    } while(0)
#endif /* (!DPM_BC_APPLE_SAMSUNG_MODE_ENABLED) */

bool_t dpm_qc_enable_get(volatile DPM_QC_INFO_t *p_qc_info);
void dpm_qc_enable_set(volatile DPM_QC_INFO_t *p_qc_info, bool_t on, bool_t snk);
void dpm_qc_state_init(volatile DPM_QC_INFO_t *p_qc_info, bool_t snk);
void dpm_qc_state_machine(volatile DPM_QC_INFO_t *p_qc_info);
void qc_state_to_snk_connecting(volatile DPM_QC_INFO_t *p_qc_info);
#endif /* #ifndef __DPM_QC_H_ */

