/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * 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.
 *  * 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.
 *
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 *
 * $Author: dtvbm11 $
 * $Date: 2016/02/29 $
 * $RCSfile: aud_cust_amp_5760.c,v $
 * $Revision: #1 $
 *
 *---------------------------------------------------------------------------*/

//---------------------------------------------------------------------------
// Include files
//---------------------------------------------------------------------------

/* =======================================================
 [**CAUTION**] 
 You can only include header files in 
 \target\mtxxxx\xxxx_driver\drv_inc\  
 or files in \vm_linux\output\sysbuild\xxxx\rel or debug\inc\drv_inc\
 or files in the same directory.
========================================================= */
#include "aud_cust_amp_if.h"
#include "sif_if.h"
#include "aud_if.h"
#include "drvcust_if.h"
#include "sakura_aud_aq_data.h"

//---------------------------------------------------------------------------
// Configurations
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Constant definitions
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Type definitions
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Macro definitions
//---------------------------------------------------------------------------
#define NTFY_ERR_NUM_5760       16

//---------------------------------------------------------------------------
// Imported variables
//---------------------------------------------------------------------------
static AQ_FS _gPrevFS = AQ_FS_DONT;

//---------------------------------------------------------------------------
// Imported functions
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Static function forward declarations
//---------------------------------------------------------------------------
static void AUD_CUST_AMP_5760_Mute(AMP_DATA_T* pAmp, AUD_CUST_AMP_MUTE_T mute);

//---------------------------------------------------------------------------
// Static variables
//---------------------------------------------------------------------------
#ifdef CC_AUD_SAKURA_RENDER
static HANDLE_T _hAudAmpMuteSema=NULL_HANDLE;
#endif /* CC_AUD_SAKURA_RENDER */

//---------------------------------------------------------------------------
// Static functions
//---------------------------------------------------------------------------
static void AUD_CUST_AMP_5760_Init(AMP_DATA_T* pAmp)
{
    UINT8 S_Data;
    UINT8 readData;
    
    DrvCust_AQ_SetGet(AUD_DrvCust_AQ_Get_DA_GEN_CFG, 0, 0, _gu4CurrentAqKey/*key*/, 0);
    DrvCust_AQ_SetGet(AUD_DrvCust_AQ_Get_DA_5760_CFG1, 0, 0, _gu4CurrentAqKey, 0);
    DrvCust_AQ_SetGet(AUD_DrvCust_AQ_Get_DA_5760_CFG2, 0, 0, _gu4CurrentAqKey, 0);    

    x_thread_delay(10);
#ifdef CC_AUD_SAKURA_RENDER
    VERIFY(x_sema_create(&_hAudAmpMuteSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK) == OSR_OK);
#endif /* CC_AUD_SAKURA_RENDER */
    AUD_CUST_AMP_5760_Mute(pAmp, AUD_CUST_AMP_MUTE);
    
    UINT32 num = 0;
    while(1){
        LOG(1, "read %dst time\n", num);
        if(AUD_CUST_AMP_RegRead(pAmp, 0x00, &readData) != 0 && readData == 0x00){
            x_os_drv_set_timestamp("KD_READ_AMP5760_OK");
            break;
        }
        
        x_thread_delay(50);
        num++;
    }
       
    
    if(pAmp->u1AmpTable == 0)
    {
        LOG(1, "5890 Data type is 0\n");
        // Power control
        if(AUD_CUST_AMP_RegRead(pAmp, 0x1, &readData) != 0){
            S_Data = (gDa5760Cfg1Data.m_Da1DigitalClip3 & 0xFC) + (readData & 0x3);
            AUD_CUST_AMP_RegWrite(pAmp, 0x1, &S_Data, 1);
        }
        else{
            LOG(0, "Amp Read Error! Skip RegWrite\n");
        }
        // Digital control
        if(AUD_CUST_AMP_RegRead(pAmp, 0x2, &readData) != 0){
            S_Data = (gDa5760Cfg1Data.m_Da1DigitalControl & 0xF7) + (readData & 0x08);
            AUD_CUST_AMP_RegWrite(pAmp, 0x2, &S_Data, 1);
        }
        else{
            LOG(0, "Amp Read Error! Skip RegWrite\n");
        }
        //Left channel volume control
        AUD_CUST_AMP_RegWrite(pAmp, 0x4, &gDa5760Cfg1Data.m_Da1Volume, 1);
        //Right channel volume control
        AUD_CUST_AMP_RegWrite(pAmp, 0x5, &gDa5760Cfg1Data.m_Da1Volume, 1);
        //Analog control
        AUD_CUST_AMP_RegWrite(pAmp, 0x6, &gDa5760Cfg1Data.m_Da1AnalogControl, 1);
        //Digital clipper2
        AUD_CUST_AMP_RegWrite(pAmp, 0x10, &gDa5760Cfg1Data.m_Da1DigitalClip2, 1);
        //Digital clipper1
        AUD_CUST_AMP_RegWrite(pAmp, 0x11, &gDa5760Cfg1Data.m_Da1DigitalClip1, 1);
    }
    else if(pAmp->u1AmpTable == 1)
    {
        LOG(1, "5890 Data type is 1\n");
        // Power control
        if(AUD_CUST_AMP_RegRead(pAmp, 0x1, &readData) != 0){
            S_Data = (gDa5760Cfg2Data.m_Da2DigitalClip3 & 0xFC) + (readData & 0x3);
            AUD_CUST_AMP_RegWrite(pAmp, 0x1, &S_Data, 1);
        }
        else{
            LOG(0, "Amp Read Error! Skip RegWrite\n");
        }
        // Digital control
        if(AUD_CUST_AMP_RegRead(pAmp, 0x2, &readData) != 0){
            S_Data = (gDa5760Cfg2Data.m_Da2DigitalControl & 0xF7) + (readData & 0x08);
            AUD_CUST_AMP_RegWrite(pAmp, 0x2, &S_Data, 1);
        }
        else{
            LOG(0, "Amp Read Error! Skip RegWrite\n");
        }
        //Left channel volume control
        AUD_CUST_AMP_RegWrite(pAmp, 0x4, &gDa5760Cfg2Data.m_Da2Volume, 1);
        //Right channel volume control
        AUD_CUST_AMP_RegWrite(pAmp, 0x5, &gDa5760Cfg2Data.m_Da2Volume, 1);
        //Analog control
        AUD_CUST_AMP_RegWrite(pAmp, 0x6, &gDa5760Cfg2Data.m_Da2AnalogControl, 1);
        //Digital clipper2
        AUD_CUST_AMP_RegWrite(pAmp, 0x10, &gDa5760Cfg2Data.m_Da2DigitalClip2, 1);
        //Digital clipper1
        AUD_CUST_AMP_RegWrite(pAmp, 0x11, &gDa5760Cfg2Data.m_Da2DigitalClip1, 1);
    }

    _gPrevFS = AQ_FS_48KHZ;
}


void AUD_CUST_AMP_5760_FS_Change(AMP_DATA_T* pAmp, AQ_FS fs){
    
    UINT8 S_Data;
    
    if(pAmp->u1DevAddrAQAmp != 0x34){
        if(fs == AQ_FS_48KHZ){
            S_Data = (gDa5760Cfg2Data.m_Da2DigitalControl & 0xF7);
        }
        else{
            S_Data = (gDa5760Cfg2Data.m_Da2DigitalControl & 0xF7) + 0x08;
        }
        
        AUD_CUST_AMP_RegWrite(pAmp, 0x02, &S_Data, 1);
    }
}
    
    
void AUD_CUST_AMP_5760_Mute(AMP_DATA_T* pAmp, AUD_CUST_AMP_MUTE_T mute){

    UINT8 S_Data;
    
#ifdef CC_AUD_SAKURA_RENDER
    if(_hAudAmpMuteSema != NULL_HANDLE){
        VERIFY(x_sema_lock(_hAudAmpMuteSema, X_SEMA_OPTION_WAIT) == OSR_OK);
    }
#endif /* CC_AUD_SAKURA_RENDER */
    if( mute == AUD_CUST_AMP_MUTE ){
        S_Data = (gDa5760Cfg1Data.m_Da1DigitalClip3 & 0xFC) + 0x03;
        AUD_CUST_AMP_RegWrite(pAmp, 0x1, &S_Data, 1);
    }
    else if( mute == AUD_CUST_AMP_UNMUTE ){//Unmute
        S_Data = (gDa5760Cfg1Data.m_Da1DigitalClip3 & 0xFC) + 0x01;
        AUD_CUST_AMP_RegWrite(pAmp, 0x1, &S_Data, 1);
    }
    else{
        LOG(0, "Nothing done. Pass Mute or Unmute value!\n");
    }
#ifdef CC_AUD_SAKURA_RENDER
    if(_hAudAmpMuteSema != NULL_HANDLE){
        VERIFY(x_sema_unlock(_hAudAmpMuteSema) == OSR_OK);
    }
#endif /* CC_AUD_SAKURA_RENDER */
}

void AUD_CUST_AMP_5760_Refresh(AMP_DATA_T* pAmp)
{
    UINT8 S_Data = 0;
    UINT8 readData;
    BOOL fsChange=FALSE;

    if( (_gu4CurrentAqKey & 0xf) != 1 && (_gu4CurrentAqKey & 0xf) != 2){
        LOG(1, "unsupported fs\n");
        return;
    }
    if( _gPrevFS != (_gu4CurrentAqKey & 0xf) ){
        _gPrevFS = (_gu4CurrentAqKey & 0xf);
        fsChange = TRUE;
    }
    
    DrvCust_AQ_SetGet(AUD_DrvCust_AQ_Get_DA_GEN_CFG, 0, 0, _gu4CurrentAqKey/*key*/, 0);
    DrvCust_AQ_SetGet(AUD_DrvCust_AQ_Get_DA_5760_CFG1, 0, 0, _gu4CurrentAqKey, 0);
    DrvCust_AQ_SetGet(AUD_DrvCust_AQ_Get_DA_5760_CFG2, 0, 0, _gu4CurrentAqKey, 0);
    
    if(fsChange){
        AUD_CUST_AMP_5760_Mute(pAmp, AUD_CUST_AMP_MUTE);
        x_thread_delay(50);
        AUD_GPIOOutput(205, 0);
        x_thread_delay(50);
        AUD_CUST_AMP_5760_FS_Change(pAmp, _gPrevFS);
        x_thread_delay(3);
    }
    if(pAmp->u1AmpTable == 0)
    {
        LOG(1, "5760 Data type is 0\n");
        // Power control
#ifdef CC_AUD_SAKURA_RENDER
        if(_hAudAmpMuteSema != NULL_HANDLE){
            VERIFY(x_sema_lock(_hAudAmpMuteSema, X_SEMA_OPTION_WAIT) == OSR_OK);
        }
#endif /* CC_AUD_SAKURA_RENDER */
        if(AUD_CUST_AMP_RegRead(pAmp, 0x1, &readData) != 0){
            S_Data = (gDa5760Cfg1Data.m_Da1DigitalClip3 & 0xFC) + (readData & 0x3);
            AUD_CUST_AMP_RegWrite(pAmp, 0x1, &S_Data, 1);
        }
        else{
            LOG(0, "Amp Read Error! Skip RegWrite\n");
        }
#ifdef CC_AUD_SAKURA_RENDER
        if(_hAudAmpMuteSema != NULL_HANDLE){
            VERIFY(x_sema_unlock(_hAudAmpMuteSema) == OSR_OK);
        }
#endif /* CC_AUD_SAKURA_RENDER */
        // Digital control
        if(AUD_CUST_AMP_RegRead(pAmp, 0x2, &readData) != 0){
            S_Data = (gDa5760Cfg1Data.m_Da1DigitalControl & 0xF7) + (readData & 0x08);
            AUD_CUST_AMP_RegWrite(pAmp, 0x2, &S_Data, 1);
        }
        else{
            LOG(0, "Amp Read Error! Skip RegWrite\n");
        }
        //Left channel volume control
        AUD_CUST_AMP_RegWrite(pAmp, 0x4, &gDa5760Cfg1Data.m_Da1Volume, 1);
        //Right channel volume control
        AUD_CUST_AMP_RegWrite(pAmp, 0x5, &gDa5760Cfg1Data.m_Da1Volume, 1);
        //Analog control
        AUD_CUST_AMP_RegWrite(pAmp, 0x6, &gDa5760Cfg1Data.m_Da1AnalogControl, 1);
        //Digital clipper2
        AUD_CUST_AMP_RegWrite(pAmp, 0x10, &gDa5760Cfg1Data.m_Da1DigitalClip2, 1);
        //Digital clipper1
        AUD_CUST_AMP_RegWrite(pAmp, 0x11, &gDa5760Cfg1Data.m_Da1DigitalClip1, 1);
    }
    else if(pAmp->u1AmpTable == 1)
    {
        LOG(1, "5760 Data type is 1\n");
        // Power control
        if(AUD_CUST_AMP_RegRead(pAmp, 0x1, &readData) != 0){
            S_Data = (gDa5760Cfg2Data.m_Da2DigitalClip3 & 0xFC) + (readData & 0x3);
            AUD_CUST_AMP_RegWrite(pAmp, 0x1, &S_Data, 1);
        }
        else{
            LOG(0, "Amp Read Error! Skip RegWrite\n");
        }
        // Digital control
        if(AUD_CUST_AMP_RegRead(pAmp, 0x2, &readData) != 0){
            S_Data = (gDa5760Cfg2Data.m_Da2DigitalControl & 0xF7) + (readData & 0x08);
            AUD_CUST_AMP_RegWrite(pAmp, 0x2, &S_Data, 1);
        }
        else{
            LOG(0, "Amp Read Error! Skip RegWrite\n");
        }
        //Left channel volume control
        AUD_CUST_AMP_RegWrite(pAmp, 0x4, &gDa5760Cfg2Data.m_Da2Volume, 1);
        //Right channel volume control
        AUD_CUST_AMP_RegWrite(pAmp, 0x5, &gDa5760Cfg2Data.m_Da2Volume, 1);
        //Analog control
        AUD_CUST_AMP_RegWrite(pAmp, 0x6, &gDa5760Cfg2Data.m_Da2AnalogControl, 1);
        //Digital clipper2
        AUD_CUST_AMP_RegWrite(pAmp, 0x10, &gDa5760Cfg2Data.m_Da2DigitalClip2, 1);
        //Digital clipper1
        AUD_CUST_AMP_RegWrite(pAmp, 0x11, &gDa5760Cfg2Data.m_Da2DigitalClip1, 1);
    }

    if(fsChange){        
        x_thread_delay(50);
        AUD_GPIOOutput(205, 1);
        x_thread_delay(50);
        AUD_CUST_AMP_5760_Mute(pAmp, AUD_CUST_AMP_UNMUTE);
        
        LOG(1, "FS changed, change setting complete\n");
    }
}

static struct aud_cust_amp_func_tbl _r5760Funcs = 
{
    AUD_CUST_AMP_5760_Init,      //pfnCustInit
    NULL,                        //pfnCustSuspend
    NULL,                        //pfnCustResume
    AUD_CUST_AMP_5760_Mute,      //pfnCustMute
    AUD_CUST_AMP_5760_Refresh,   //pfnCustRefresh
};

void AUD_CUST_AMP_RegistAmp_5760(AMP_DATA_T* pAmp)
{
    strncpy(pAmp->name,"T5760", sizeof(pAmp->name)-1);
    pAmp->u4NotifyErrThreshold = NTFY_ERR_NUM_5760;

    pAmp->funcTbl = &_r5760Funcs;
}
