/*=======================================================================*/
/*                       LOCAL FUNCTION PROTOTYPES                       */
/*=======================================================================*/
INT32  drv_3rd_party_custom_cust_spec_set(
    DRV_CUSTOM_CUST_SPEC_TYPE_T    e_cust_spec_type,
    VOID*                          pv_set_info,
    SIZE_T                         z_size,
    BOOL                           b_store
);
INT32  drv_3rd_party_custom_cust_spec_get(
    DRV_CUSTOM_CUST_SPEC_TYPE_T    e_cust_spec_type,
    VOID*                          pv_get_info,
    SIZE_T*                        pz_size
);

#define DRV_3RD_PARTY_CUSTOM_CUST_SPEC_SET  drv_3rd_party_custom_cust_spec_set
#define DRV_3RD_PARTY_CUSTOM_CUST_SPEC_GET  drv_3rd_party_custom_cust_spec_get

typedef struct{
    UINT16  offset;
    UINT8   bit_width;
    UINT32  init;
    UINT32  min;
    UINT32  max;
    UINT8   shift;
}ST_ECS_SOPQ_SREG_INFO;

static const UINT32 bit_mask[33] = {
    0x00000000,
    0x00000001,
    0x00000003,
    0x00000007,
    0x0000000F,
    0x0000001F,
    0x0000003F,
    0x0000007F,
    0x000000FF,
    0x000001FF,
    0x000003FF,
    0x000007FF,
    0x00000FFF,
    0x00001FFF,
    0x00003FFF,
    0x00007FFF,
    0x0000FFFF,
    0x0001FFFF,
    0x0003FFFF,
    0x0007FFFF,
    0x000FFFFF,
    0x001FFFFF,
    0x003FFFFF,
    0x007FFFFF,
    0x00FFFFFF,
    0x01FFFFFF,
    0x03FFFFFF,
    0x07FFFFFF,
    0x0FFFFFFF,
    0x1FFFFFFF,
    0x3FFFFFFF,
    0x7FFFFFFF,
    0xFFFFFFFF,
};

/*
 * Id: //Assets/Muffin/PqCtrl/software/2015/develop/sony_pqctrl_ko/Data/include/gen/sopq_sreg.h#38  
 * DateTime: 2014/12/10 18:11:32 
 */
enum { 
    BL_AGING_GAIN       , //      = 0x00000001, 
    WB_BL_ON            , //      = 0x0000010F, 
    WB_A_GAIN_R         , //      = 0x0000011A, 
    WB_A_GAIN_G         , //      = 0x0000011B, 
    WB_A_GAIN_B         , //      = 0x0000011C, 
    WB_3D_GAIN_R        , //      = 0x0000013A, 
    WB_3D_GAIN_G        , //      = 0x0000013B, 
    WB_3D_GAIN_B        , //      = 0x0000013C, 
    WB_BL_GAIN_R_TOP    , //      = 0x0000014A, 
    WB_BL_GAIN_G_TOP    , //      = 0x0000014B, 
    WB_BL_GAIN_B_TOP    , //      = 0x0000014C, 
    WB_BL_GAIN_R_CEN    , //      = 0x0000014D, 
    WB_BL_GAIN_G_CEN    , //      = 0x0000014E, 
    WB_BL_GAIN_B_CEN    , //      = 0x0000014F, 
    WB_BL_BLCEN         , //      = 0x00000153, 
    UBL_TGT             , //      = 0x00000439, 
    BL_STATUS_DMY2      , //      = 0x00000469, 
    WB_BL_BL_LVL        , //      = 0x000006D0, 
    WB_BL_GAIN_R        , //      = 0x000006D1, 
    WB_BL_GAIN_G        , //      = 0x000006D2, 
    WB_BL_GAIN_B        , //      = 0x000006D3, 
    WB_SUM_GAIN_R       , //      = 0x000006D4, 
    WB_SUM_GAIN_G       , //      = 0x000006D5, 
    WB_SUM_GAIN_B       , //      = 0x000006D6, 
    AUTO_DATA_REFRESH   , //      = 0x00000838, 
};

/*
 *  Id: //Assets/Muffin/PqCtrl/software/2015/develop/sony_pqctrl_ko/Data/src/gen/sopq_sreg.c#47  
 *  DateTime: 2014/12/10 18:11:32  
 */
static const ST_ECS_SOPQ_SREG_INFO s_ecs_sopq_sreg_info_array[] = {
 /* [ offset,  width,       init,        min,        max,     shift ] */
    { 0xB004,     32,       1024,          0,       66536UL,      0 }, //BL_AGING_GAIN           PQP_BL_CONFIG[31:0]
    { 0xB030,      1,          1,          0,           1UL,      1 }, //WB_BL_ON                PQP_WB_SWITCH[1:1]
    { 0xB040,     10,        512,          0,        1023UL,      0 }, //WB_A_GAIN_R             PQP_WB_A[9:0]
    { 0xB040,     10,        512,          0,        1023UL,     16 }, //WB_A_GAIN_G             PQP_WB_A[25:16]
    { 0xB044,     10,        512,          0,        1023UL,      0 }, //WB_A_GAIN_B             PQP_WB_A[9:0]
    { 0xB060,     10,        512,          0,        1023UL,      0 }, //WB_3D_GAIN_R            PQP_WB_3D[9:0]
    { 0xB060,     10,        512,          0,        1023UL,     16 }, //WB_3D_GAIN_G            PQP_WB_3D[25:16]
    { 0xB064,     10,        512,          0,        1023UL,      0 }, //WB_3D_GAIN_B            PQP_WB_3D[9:0]
    { 0xB080,     10,        512,          0,        1023UL,      0 }, //WB_BL_GAIN_R_TOP        PQP_BL_WB[9:0]
    { 0xB080,     10,        512,          0,        1023UL,     16 }, //WB_BL_GAIN_G_TOP        PQP_BL_WB[25:16]
    { 0xB084,     10,        512,          0,        1023UL,      0 }, //WB_BL_GAIN_B_TOP        PQP_BL_WB[9:0]
    { 0xB084,     10,        512,          0,        1023UL,     16 }, //WB_BL_GAIN_R_CEN        PQP_BL_WB[25:16]
    { 0xB088,     10,        512,          0,        1023UL,      0 }, //WB_BL_GAIN_G_CEN        PQP_BL_WB[9:0]
    { 0xB088,     10,        512,          0,        1023UL,     16 }, //WB_BL_GAIN_B_CEN        PQP_BL_WB[25:16]
    { 0xB090,     16,        512,          0,       65535UL,     16 }, //WB_BL_BLCEN             PQP_BL_WB[31:16]
    { 0xBA04,     16,       1024,          0,        1024UL,      0 }, //UBL_TGT                 PQP_BL_STATUS[15:0]
    { 0xBA54,      8,          0,          0,         255UL,     16 }, //BL_STATUS_DMY2          PQP_BL_STATUS[23:16]
    { 0xBA70,     11,        512,          0,        1024UL,      0 }, //WB_BL_BL_LVL            PQP_WB_STAT[10:0]
    { 0xBA70,     10,        512,          0,        1023UL,     16 }, //WB_BL_GAIN_R            PQP_WB_STAT[25:16]
    { 0xBA74,     10,        512,          0,        1023UL,      0 }, //WB_BL_GAIN_G            PQP_WB_STAT[9:0]
    { 0xBA74,     10,        512,          0,        1023UL,     16 }, //WB_BL_GAIN_B            PQP_WB_STAT[25:16]
    { 0xBA78,     10,        512,          0,        1023UL,      0 }, //WB_SUM_GAIN_R           PQP_WB_STAT[9:0]
    { 0xBA78,     10,        512,          0,        1023UL,     16 }, //WB_SUM_GAIN_G           PQP_WB_STAT[25:16]
    { 0xBA7C,     10,        512,          0,        1023UL,      0 }, //WB_SUM_GAIN_B           PQP_WB_STAT[9:0]
    { 0xC1F0,      8,          0,          0,           1UL,      0 }, //AUTO_DATA_REFRESH       PQP_SW_DEBUG[7:0]
};

static UINT32 ecs_sopq_read_sreg( UINT32 sregID );
static void ecs_sopq_write_sreg( UINT32 sregID, UINT32 value );

/*=======================================================================*/
/*                       LOCAL  FUNCTIONS                                */
/*=======================================================================*/
INT32 drv_3rd_party_custom_cust_spec_set (
    DRV_CUSTOM_CUST_SPEC_TYPE_T    e_cust_spec_type,
    VOID*                          pv_set_info,
    SIZE_T                         z_size,
    BOOL                           b_store
)
{
    INT32 i4_ret = RMR_OK;
    switch (e_cust_spec_type)
    {
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_BL_AGING_EN:
            ecs_sopq_write_sreg(BL_STATUS_DMY2, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_BL_AGING_GAIN:
            ecs_sopq_write_sreg(BL_AGING_GAIN, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_PQ_AUTO_DATA_REFRESH:
            ecs_sopq_write_sreg(AUTO_DATA_REFRESH, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_ON:
            ecs_sopq_write_sreg(WB_BL_ON, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_R:
            ecs_sopq_write_sreg(WB_BL_GAIN_R, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_G:
            ecs_sopq_write_sreg(WB_BL_GAIN_G, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_B:
            ecs_sopq_write_sreg(WB_BL_GAIN_B, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_A_GAIN_R:
            ecs_sopq_write_sreg(WB_A_GAIN_R, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_A_GAIN_G:
            ecs_sopq_write_sreg(WB_A_GAIN_G, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_A_GAIN_B:
            ecs_sopq_write_sreg(WB_A_GAIN_B, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_SUM_GAIN_R:
            ecs_sopq_write_sreg(WB_SUM_GAIN_R, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_SUM_GAIN_G:
            ecs_sopq_write_sreg(WB_SUM_GAIN_G, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_SUM_GAIN_B:
            ecs_sopq_write_sreg(WB_SUM_GAIN_B, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_BLCEN:
            ecs_sopq_write_sreg(WB_BL_BLCEN, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_BL_LVL:
            ecs_sopq_write_sreg(WB_BL_BL_LVL, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_R_TOP:
            ecs_sopq_write_sreg(WB_BL_GAIN_R_TOP, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_G_TOP:
            ecs_sopq_write_sreg(WB_BL_GAIN_G_TOP, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_B_TOP:
            ecs_sopq_write_sreg(WB_BL_GAIN_B_TOP, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_R_CEN:
            ecs_sopq_write_sreg(WB_BL_GAIN_R_CEN, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_G_CEN:
            ecs_sopq_write_sreg(WB_BL_GAIN_G_CEN, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_B_CEN:
            ecs_sopq_write_sreg(WB_BL_GAIN_B_CEN, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_3D_GAIN_R:
            ecs_sopq_write_sreg(WB_3D_GAIN_R, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_3D_GAIN_G:
            ecs_sopq_write_sreg(WB_3D_GAIN_G, (*(UINT16 *)pv_set_info));
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_3D_GAIN_B:
            ecs_sopq_write_sreg(WB_3D_GAIN_B, (*(UINT16 *)pv_set_info));
            break;
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD0:
//            // Do nothing for TemperatureSensorLevel
//            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD1:
            ecs_sopq_write_sreg(UBL_TGT, (*(UINT16 *)pv_set_info));
            break;
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD2:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD3:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD4:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD5:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD6:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD7:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD8:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD9:
        default:
            i4_ret = RMR_INV_ARG;
            break;
    }
    return i4_ret;
}

INT32 drv_3rd_party_custom_cust_spec_get (
    DRV_CUSTOM_CUST_SPEC_TYPE_T    e_cust_spec_type,
    VOID*                          pv_get_info,
    SIZE_T*                        pz_size
)
{
    INT32 i4_ret = RMR_OK;
    switch (e_cust_spec_type)
    {
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_BL_AGING_EN:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(BL_STATUS_DMY2);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_BL_AGING_GAIN:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(BL_AGING_GAIN);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_PQ_AUTO_DATA_REFRESH:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(AUTO_DATA_REFRESH);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_ON:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_ON);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_R:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_GAIN_R);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_G:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_GAIN_G);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_B:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_GAIN_B);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_A_GAIN_R:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_A_GAIN_R);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_A_GAIN_G:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_A_GAIN_G);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_A_GAIN_B:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_A_GAIN_B);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_SUM_GAIN_R:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_SUM_GAIN_R);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_SUM_GAIN_G:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_SUM_GAIN_G);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_SUM_GAIN_B:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_SUM_GAIN_B);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_BLCEN:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_BLCEN);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_BL_LVL:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_BL_LVL);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_R_TOP:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_GAIN_R_TOP);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_G_TOP:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_GAIN_G_TOP);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_B_TOP:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_GAIN_B_TOP);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_R_CEN:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_GAIN_R_CEN);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_G_CEN:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_GAIN_G_CEN);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_BL_GAIN_B_CEN:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_BL_GAIN_B_CEN);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_3D_GAIN_R:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_3D_GAIN_R);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_3D_GAIN_G:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_3D_GAIN_G);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_WB_3D_GAIN_B:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(WB_3D_GAIN_B);
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD0:
            (*(UINT16 *)pv_get_info) = (UINT16)DRVCUST_GetTemperatureSensorLevel();
            break;
        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD1:
            (*(UINT16 *)pv_get_info) = (UINT16)ecs_sopq_read_sreg(UBL_TGT);
            break;
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD2:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD3:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD4:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD5:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD6:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD7:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD8:
//        case DRV_CUSTOM_CUST_SPEC_TYPE_ECS_CMD9:
        default:
            i4_ret = RMR_INV_ARG;
            break;
    }

    return i4_ret;
}

static UINT32 ecs_sopq_read_sreg( UINT32 sregID ){
    UINT32 read_value = (*(volatile UINT32*)(u4SWReg(s_ecs_sopq_sreg_info_array[sregID].offset)));
    UINT32 read_value_bitshift = (read_value >> s_ecs_sopq_sreg_info_array[sregID].shift) & bit_mask[s_ecs_sopq_sreg_info_array[sregID].bit_width];
    return read_value_bitshift;
}

static void ecs_sopq_write_sreg( UINT32 sregID, UINT32 value ){
    volatile UINT32* target_addr = (UINT32*)(u4SWReg((s_ecs_sopq_sreg_info_array[sregID].offset)));
    UINT32 write_value_bitshift;
    UINT32 mask_bitshift = bit_mask[s_ecs_sopq_sreg_info_array[sregID].bit_width] << s_ecs_sopq_sreg_info_array[sregID].shift;
    
    if ( value > s_ecs_sopq_sreg_info_array[sregID].max ) {
        value = s_ecs_sopq_sreg_info_array[sregID].max;
    }
    write_value_bitshift = value << s_ecs_sopq_sreg_info_array[sregID].shift;
    *target_addr = ( *target_addr & (~mask_bitshift) ) | write_value_bitshift;
    
    return;
}

