ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/services/audio/libacm/acm/src/acm_aph.c b/marvell/services/audio/libacm/acm/src/acm_aph.c
new file mode 100644
index 0000000..a947a74
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_aph.c
@@ -0,0 +1,1536 @@
+/*
+* All Rights Reserved
+*
+* MARVELL CONFIDENTIAL
+* Copyright 2012 Marvell International Ltd All Rights Reserved.
+* The source code contained or described herein and all documents related to
+* the source code ("Material") are owned by Marvell International Ltd or its
+* suppliers or licensors. Title to the Material remains with Marvell International Ltd
+* or its suppliers and licensors. The Material contains trade secrets and
+* proprietary and confidential information of Marvell or its suppliers and
+* licensors. The Material is protected by worldwide copyright and trade secret
+* laws and treaty provisions. No part of the Material may be used, copied,
+* reproduced, modified, published, uploaded, posted, transmitted, distributed,
+* or disclosed in any way without Marvell's prior express written permission.
+*
+* No license under any patent, copyright, trade secret or other intellectual
+* property right is granted to or conferred upon you by disclosure or delivery
+* of the Materials, either expressly, by implication, inducement, estoppel or
+* otherwise. Any license under such intellectual property rights must be
+* express and approved by Marvell in writing.
+*
+*/
+
+#define LOG_TAG "acm_aph"
+#define LOG_NDEBUG 0
+
+#include <stdio.h>
+#include <unistd.h>     //usleep
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <cutils/log.h>
+#include "acm_aph.h"
+#include "acm_param.h"
+#include <stdlib.h>
+
+#ifdef PXA1826_AUDIO
+#include "audio_stub.h"
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#endif
+
+#ifdef TARGET_mmp_asr1901_KSTR901
+#include "audio_dsp.h"
+#include "adsp_ve.h"
+#endif
+
+#include "audioCalibration.h"
+
+//-----------------------------------------------------------------------------
+//Codec Definitions:
+//  CODEC_PM812/CODEC_PM805/CODEC_NAU8810/CODEC_ALC5616/CODEC_NONE is defined in openwrt\package\libs\pxa1826_audio
+//  CODEC_I2S_MASTER/CODEC_I2S_SLAVE/CODEC_PCM_MASTER/CODEC_PCM_SLAVE is defined in openwrt\package\libs\pxa1826_audio
+//-----------------------------------------------------------------------------
+#if defined(CODEC_PM812)
+//PM812 is connected
+#include "acm_pm812.h"
+static BOOL acm_codec_connected = TRUE;
+#elif defined(CODEC_PM805)
+//PM805 is connected
+#include "acm_pm805.h"
+static BOOL acm_codec_connected = TRUE;
+#elif defined(CODEC_NAU8810)
+//NAU8810 is connected
+#include "acm_nau8810.h"
+static BOOL acm_codec_connected = TRUE;
+#elif defined(CODEC_ALC5616)
+//ALC5616 is connected
+#include "acm_alc5616.h"
+static BOOL acm_codec_connected = TRUE;
+#else
+//No codec is connected
+static BOOL acm_codec_connected = FALSE;
+static ACMAPH_Component ACM_Enable[APH_PATH_ID_CNT]={};
+static ACMAPH_Component ACM_Disable[APH_PATH_ID_CNT]={};
+static ACMAPH_Component ACM_Mute[APH_PATH_IN_CNT]={};
+static ACMAPH_Component ACM_UnMute[APH_PATH_IN_CNT]={};
+static ACMAPH_VolumeComponent ACM_Volume[APH_PATH_OUT_CNT]={};
+static APH_ACHComponent ACH_component_table[AUDIO_COMPONENT_CNT]={};
+//Sorted as APH_AudioComponent
+static char APH_AudioComponent_Name[AUDIO_COMPONENT_CNT][16]= {} ;
+#endif
+
+
+//--------------------------------------------------------------
+//-------- Global Information Tables
+//--------------------------------------------------------------
+
+static int modem_is_wb = 0, modem_is_master = 0;
+
+const ACMAPH_AudioPathID AUDIO_PATH_ID_MAPPING[APH_PATH_ID_CNT] = {
+    {APH_PATH_ID_HIFIPLAYTOEARPHONE,   "HiFiPlayToEarphone"  },
+    {APH_PATH_ID_HIFIPLAYTOSPKR,       "HiFiPlayToSPKR"      },
+    {APH_PATH_ID_HIFIPLAYTOHP,         "HiFiPlayToHP"        },
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,   "HiFiRecordFromMic1"  },
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,  "HiFiRecordFromHsMic" },
+    {APH_PATH_ID_VOICEPLAYTOEARPHONE,  "VoicePlayToEarphone" },
+    {APH_PATH_ID_VOICEPLAYTOSPKR,      "VoicePlayToSPKR"     },
+    {APH_PATH_ID_VOICEPLAYTOHP,        "VoicePlayToHP"       },
+    {APH_PATH_ID_VOICERECORDFROMMIC1,  "VoiceRecordFromMic1" },
+    {APH_PATH_ID_VOICERECORDFROMHSMIC, "VoiceRecordFromHsMic"},
+};
+
+APH_PathStatus path_status_table[APH_PATH_ID_CNT] = {
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0}
+};
+
+/* 1:on; 0:off */
+static int g_audio_if_debug_mode = 0;
+
+int get_debug_mode(void)
+{
+    return g_audio_if_debug_mode;
+}
+
+void set_debug_mode(int onoff)
+{
+    g_audio_if_debug_mode = onoff;
+}
+
+void configCodecGainfromNVM(APH_AudioComponent Component_NVM, unsigned char Address_NVM, unsigned short Value_NVM);
+extern int NVM_Calibration_IPC(AC_IPC_Package *package);
+
+const ACMAPH_AudioPathID *ACM_GetPathConfigTable() {
+    return AUDIO_PATH_ID_MAPPING ;
+}
+
+void get_pcm_config(int *p_role, int *p_rate)
+{
+    *p_role = modem_is_master;
+    *p_rate = modem_is_wb;
+    return;
+}
+
+void set_pcm_config(int role, int rate)
+{
+    modem_is_master = role;
+    modem_is_wb = rate;
+
+#if defined(CODEC_ALC5616)
+#ifdef TARGET_mmp_asr1901_KSTR901
+    if (3 == modem_is_wb) {
+        LOGI(set_pcm_config, "%s: modem switch to 48KHz for ALC5616 in Kestrel.", __FUNCTION__);
+        system("echo 3 > /sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616_switch_rate");
+    } else  if (2 == modem_is_wb){
+        LOGI(set_pcm_config, "%s: modem switch to 32KHz for ALC5616 in Kestrel.", __FUNCTION__);
+        system("echo 2 > /sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616_switch_rate");
+    } else if (1 == modem_is_wb) {
+        LOGI(set_pcm_config, "%s: modem switch to WB for ALC5616 in Kestrel.", __FUNCTION__);
+        system("echo 1 > /sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616_switch_rate");
+    } else  if (0 == modem_is_wb) {
+        LOGI(set_pcm_config, "%s: modem switch to NB for ALC5616 in Kestrel.", __FUNCTION__);
+        system("echo 0 > /sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616_switch_rate");
+    } else {
+        LOGI(set_pcm_config, "%s: modem switch to NB for ALC5616 in Kestrel.", __FUNCTION__);
+        system("echo 0 > /sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616_switch_rate");
+    }
+#else
+    if (1 == modem_is_wb) {
+        LOGI(set_pcm_config, "%s: modem switch to WB for ALC5616.", __FUNCTION__);
+        system("echo 1 > /sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616_switch_rate");
+    } else {
+        LOGI(set_pcm_config, "%s: modem switch to NB for ALC5616.", __FUNCTION__);
+        system("echo 0 > /sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616_switch_rate");
+    }
+#endif
+#endif
+
+    LOGI(set_pcm_config, "%s: modem_is_master=%s, modem_is_wb=%s.", __FUNCTION__, modem_is_master?"TRUE":"FALSE", modem_is_wb?"WB":"NB");
+    return;
+}
+
+static int _get_path_id(const char *path) {
+    const ACMAPH_AudioPathID *ptr;
+    const char *PathName;
+    unsigned int i = 0, size;
+
+    if(path == NULL)
+        return INVALID_PATH_ID;
+
+    size = sizeof(AUDIO_PATH_ID_MAPPING)/sizeof(ACMAPH_AudioPathID);
+    ptr = &AUDIO_PATH_ID_MAPPING[0];
+    while (i < size) {
+        PathName = ptr->PathName;
+        if (strcmp((const char *)path, (const char *)PathName) == 0) {
+            LOGI(_get_path_id, "%s: path=%s, PathName=%s,PathID=%d, i=%d", __FUNCTION__, path, PathName,ptr->PathID, i);
+            return ptr->PathID;
+        }
+
+        ptr++;
+        i++;
+    }
+
+    return INVALID_PATH_ID;
+}
+
+static ACMAPH_Component *_get_APHTable(APH_PATH_ID path_id, ACMAPH_Component *pTable, unsigned char max) {
+    int i = 0;
+
+    for (i = 0; i < max; i++) {
+        if (pTable[i].PathID == path_id) {
+            LOGI(_get_APHTable, "%s: path_id=%d", __FUNCTION__, path_id);
+            return &pTable[i];
+        }
+    }
+
+    return NULL;
+}
+
+#if  !defined(CODEC_PM805) && !defined(CODEC_PM812) && !defined(CODEC_NAU8810) && !defined(CODEC_ALC5616)
+static ACMAPH_VolumeComponent *_get_APHVolumeTable(APH_PATH_ID path_id, ACMAPH_VolumeComponent *pTable, unsigned char max) {
+    int i = 0;
+
+    for (i = 0; i < max; i++) {
+        if (pTable[i].PathID == path_id) {
+            LOGI(_get_APHVolumeTable, "%s: path_id=%d", __FUNCTION__, path_id);
+            return &pTable[i];
+        }
+    }
+
+    return NULL;
+}
+#endif
+
+static ACH_ComponentHandler *_get_component_handler(APH_AudioComponent component_id) {
+    int size = sizeof(ACH_component_table) / sizeof(ACH_component_table[0]);
+    int i = 0;
+
+    for (i = 0; i < size; i++) {
+        if (ACH_component_table[i].component_id == component_id) {
+            LOGI(_get_component_handler, "%s: component_id=%d", __FUNCTION__, component_id);
+            return ACH_component_table[i].component_handler;
+        }
+    }
+
+    return NULL;
+}
+
+static void _reset_components_registers() {
+    int size = sizeof(ACH_component_table) / sizeof(ACH_component_table[0]);
+    int i = 0;
+
+    /* Disable all components when init.*/
+    for (i = 0; i < size; i++) {
+        if (ACH_component_table[i].component_handler) {
+            ACH_component_table[i].component_handler->ACH_Reset();
+        }
+    }
+}
+
+static void _reset_components_status() {
+    int size = sizeof(ACH_component_table) / sizeof(ACH_component_table[0]);
+    int i = 0;
+
+    for (i = 0; i < size; i++) {
+        ACH_component_table[i].component_handler->active = COMPONENT_INACTIVE;
+        ACH_component_table[i].component_handler->ref_count = 0;
+    }
+
+    /* Disable all components when init.*/
+    for (i = 0; i < size; i++) {
+        ACH_component_table[i].component_handler->ACH_Disable();
+    }
+}
+
+static ACM_ReturnCode _get_path_direction(const char *path, unsigned char *path_direction) {
+    ACM_ReturnCode ret =  ACM_RC_INVALID_PARAMETER;
+    if(path != NULL) {
+        if(strstr((const char *)path, "PlayTo") != NULL) {
+            *path_direction = PATH_DIRECTION_OUT;
+            ret = ACM_RC_OK;
+        }
+        if(strstr((const char *)path, "RecordFrom") != NULL) {
+            *path_direction = PATH_DIRECTION_IN;
+            ret = ACM_RC_OK;
+        }
+    }
+    return ret;
+}
+
+char * ACM_GetPathName(int PathID) {
+    const ACMAPH_AudioPathID *ptr;
+    unsigned int i = 0, size;
+
+    if(PathID >=  APH_PATH_ID_CNT) {
+        return NULL;
+    }
+
+    size = sizeof(AUDIO_PATH_ID_MAPPING)/sizeof(ACMAPH_AudioPathID);
+    ptr = &AUDIO_PATH_ID_MAPPING[0];
+    while (i < size) {
+        if (PathID == ptr->PathID) {
+            LOGI(_get_PathName, "%s: PathName=%s, PathID=%d, i=%d", __FUNCTION__, ptr->PathName,ptr->PathID, i);
+            return ptr->PathName;
+        }
+
+        ptr++;
+        i++;
+    }
+
+    return NULL;
+}
+
+ACM_ReturnCode APHAudioPathEnable(const char * path, unsigned int value) {
+    int path_id = INVALID_PATH_ID;
+    APH_AudioComponent component;
+    ACMAPH_Register *RegisterList;
+    unsigned int i, size;
+    ACH_ComponentParameter param;
+    ACH_ComponentHandler *component_handler = NULL;
+    ACMAPH_Component *pTable = NULL;
+
+    LOGI(APHAudioPathEnable, "%s/L%d: modem_is_wb=%d, modem_is_master=%d, value=0x%x", __FUNCTION__, __LINE__, modem_is_wb, modem_is_master, value);
+
+    if(acm_codec_connected == TRUE){
+        LOGI(APHAudioPathEnable, "%s/L%d: path=%s, value=0x%x", __FUNCTION__, __LINE__, path, value);
+    }
+    else {
+        LOGE(APHAudioPathEnable, "%s/L%d: path=%s, no codec connected!", __FUNCTION__, __LINE__, path);
+        return ACM_RC_INVALID_PARAMETER;
+    }
+
+    path_id = _get_path_id(path);
+    if(path_id == INVALID_PATH_ID){
+        LOGE(APHAudioPathEnable, "%s/L%d: Error path_id=%d", __FUNCTION__, __LINE__, path_id);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    pTable = _get_APHTable(path_id, ACM_Enable, APH_PATH_ID_CNT);
+    if(pTable == NULL){
+        LOGE(APHAudioPathEnable, "%s/L%d: Error pTable=%d", __FUNCTION__, __LINE__, pTable);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    if(path_status_table[path_id].enabled != 0){
+        LOGE(APHAudioPathEnable, "%s/L%d: Already enable path %s(%d)", __FUNCTION__, __LINE__, path, path_id);
+        return ACM_RC_PATH_ALREADY_ENABLED;
+    }
+    else{
+        path_status_table[path_id].enabled = 1;
+    }
+
+    size = pTable->RegisterNum;
+    RegisterList = pTable->RegisterList;
+
+    for(i = 0; i < size; i++){
+        // get matched component
+        component = RegisterList[i].Component;
+        if(component == DELAY){
+            usleep(RegisterList[i].Value * 1000);
+            continue;
+        }
+
+        if(_get_component_handler(component) != component_handler ){
+            component_handler = _get_component_handler(component);
+
+            ///update component_handler-->ref_count: it depends on registers sorting style
+            component_handler->ref_count++;
+            LOGI(APHAudioPathEnable, "%s/L%d: component=%s, ref_count=%d", __FUNCTION__, __LINE__, APH_AudioComponent_Name[component], component_handler->ref_count);
+        }
+
+        //firstly enable component
+        if(component_handler->active == COMPONENT_INACTIVE){
+            component_handler->ACH_Enable();
+            component_handler->active = COMPONENT_ACTIVE;
+        }
+
+        /*
+         * Set value according to modem_is_wb & modem_is_master
+         *
+         */
+        //The registers of PM812 are identical with PM805
+#if defined(CODEC_PM812)
+        if( RegisterList[i].Address == CODEC_PM812_VOICE_REG35){
+            LOGI(APHAudioPathEnable, "%s/L%d: modem PCM is %s", __FUNCTION__, __LINE__, modem_is_master?"master":"slave");            
+            if (1 == modem_is_master)
+                RegisterList[i].Value = CODEC_PM812_VOICE_SLAVE;
+            else
+                RegisterList[i].Value = CODEC_PM812_VOICE_MASTER;
+        }
+
+        if( RegisterList[i].Address == CODEC_PM812_VOICE_REG36){
+            LOGI(APHAudioPathEnable, "%s/L%d: modem PCM is %s", __FUNCTION__, __LINE__, modem_is_wb?"16KHz":"8KHz");
+            if (1 == modem_is_wb)
+                RegisterList[i].Value = CODEC_PM812_VOICE_WB;
+            else
+                RegisterList[i].Value = CODEC_PM812_VOICE_NB;
+        }
+#elif defined(CODEC_PM805)
+        if( RegisterList[i].Address == CODEC_PM805_AUDIO_REG30){
+            #if defined(CODEC_I2S_MASTER)
+            RegisterList[i].Value = CODEC_PM805_AUDIO_MASTER;
+            LOGI(APHAudioPathEnable, "%s/L%d: CODEC_PM805_AUDIO_MASTER.", __FUNCTION__, __LINE__);
+            #endif
+
+            #if defined(CODEC_I2S_SLAVE)
+            RegisterList[i].Value = CODEC_PM805_AUDIO_SLAVE;
+            LOGI(APHAudioPathEnable, "%s/L%d: CODEC_PM805_AUDIO_SLAVE.", __FUNCTION__, __LINE__);
+            #endif
+        }
+
+        if( RegisterList[i].Address == CODEC_PM805_VOICE_REG35){
+            LOGI(APHAudioPathEnable, "%s/L%d: modem PCM is %s", __FUNCTION__, __LINE__, modem_is_master?"master":"slave");
+            if (1 == modem_is_master)
+                RegisterList[i].Value = CODEC_PM805_VOICE_SLAVE;
+            else
+                RegisterList[i].Value = CODEC_PM805_VOICE_MASTER;
+        }
+
+        if( RegisterList[i].Address == CODEC_PM805_VOICE_REG36){
+            LOGI(APHAudioPathEnable, "%s/L%d: modem PCM is %s", __FUNCTION__, __LINE__, modem_is_wb?"16KHz":"8KHz");
+            if (1 == modem_is_wb)
+                RegisterList[i].Value = CODEC_PM805_VOICE_WB;
+            else
+                RegisterList[i].Value = CODEC_PM805_VOICE_NB;
+        }
+#elif defined(CODEC_NAU8810)
+        if( RegisterList[i].Address == CODEC_NAU8810_VOICE_REG06){
+            LOGI(APHAudioPathEnable, "%s/L%d: modem PCM is %s", __FUNCTION__, __LINE__, modem_is_master?"master":"slave");
+            if (1 == modem_is_master)
+                RegisterList[i].Value = CODEC_NAU8810_VOICE_SLAVE;
+            else
+                RegisterList[i].Value = CODEC_NAU8810_VOICE_MASTER;
+        }
+
+        if( RegisterList[i].Address == CODEC_NAU8810_VOICE_REG07){
+            LOGI(APHAudioPathEnable, "%s/L%d: modem PCM is %s", __FUNCTION__, __LINE__, modem_is_wb?"16KHz":"8KHz");
+            if (1 == modem_is_wb)
+                RegisterList[i].Value = CODEC_NAU8810_VOICE_WB;
+            else
+                RegisterList[i].Value = CODEC_NAU8810_VOICE_NB;
+        }
+#elif defined(CODEC_ALC5616)
+        if( RegisterList[i].Address == CODEC_ALC5616_VOICE_REG70){
+            LOGI(APHAudioPathEnable, "%s/L%d: modem PCM is %s", __FUNCTION__, __LINE__, modem_is_master?"master":"slave");
+            if (1 == modem_is_master)
+                RegisterList[i].Value = CODEC_ALC5616_VOICE_SLAVE;
+            else
+                RegisterList[i].Value = CODEC_ALC5616_VOICE_MASTER;
+        }
+
+        //WB/NB is set in kernel file driver/mfd/alc5616.c.
+#endif
+        //fill param
+        param.i2c.reg_index = RegisterList[i].Address;
+        param.i2c.reg_value = &RegisterList[i].Value;
+        param.i2c.reg_mask = 0xffff;
+        param.i2c.reg_shift = 0;
+        param.i2c.length = sizeof(short);
+
+        //configure component
+        component_handler->ACH_Handle(&param);
+    }
+
+    return ACM_RC_OK;
+}
+
+ACM_ReturnCode APHAudioPathDisable(const char * path) {
+    int path_id = INVALID_PATH_ID;
+    APH_AudioComponent component;
+    ACMAPH_Register *RegisterList;
+    unsigned int i, size;
+    ACH_ComponentParameter param;
+    ACH_ComponentHandler *component_handler = NULL;
+    ACMAPH_Component *pTable = NULL;
+
+    if(acm_codec_connected == TRUE){
+        LOGI(APHAudioPathDisable, "%s/L%d: path=%s", __FUNCTION__, __LINE__, path);
+    }
+    else {
+        LOGE(APHAudioPathDisable, "%s/L%d: path=%s, no codec connected!", __FUNCTION__, __LINE__, path);
+        return ACM_RC_INVALID_PARAMETER;
+    }
+
+    path_id = _get_path_id(path);
+    if(path_id == INVALID_PATH_ID){
+        LOGE(APHAudioPathDisable, "%s/L%d: Error path_id=%d", __FUNCTION__, __LINE__, path_id);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    pTable = _get_APHTable(path_id, ACM_Disable, APH_PATH_ID_CNT);
+    if(pTable == NULL){
+        LOGE(APHAudioPathDisable, "%s/L%d: Error pTable=%d", __FUNCTION__, __LINE__, pTable);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    if(path_status_table[path_id].enabled == 0){
+        LOGE(APHAudioPathDisable, "%s/L%d: Already disable path %s(%d)", __FUNCTION__, __LINE__, path, path_id);
+        return ACM_RC_PATH_ALREADY_DISABLED;
+    }
+    else{
+        path_status_table[path_id].enabled = 0;
+        ////path_status_table[path_id].value = 0;       // Save volume even after disabled
+        path_status_table[path_id].mute = 0;
+    }
+
+    size = pTable->RegisterNum;
+    RegisterList = pTable->RegisterList;
+
+    for(i = 0; i < size; i++){
+        // get matched component
+        component = RegisterList[i].Component;
+        if(component == DELAY){
+            usleep(RegisterList[i].Value * 1000);
+            continue;
+        }
+
+        if(_get_component_handler(component) != component_handler ){
+            component_handler = _get_component_handler(component);
+
+            ///update component_handler-->ref_count: it depends on registers sorting style
+            component_handler->ref_count--;
+            LOGI(APHAudioPathDisable, "%s/L%d: component=%s, ref_count=%d", __FUNCTION__, __LINE__, APH_AudioComponent_Name[component], component_handler->ref_count);
+        }
+
+        //fill param
+        param.i2c.reg_index = RegisterList[i].Address;
+        param.i2c.reg_value = &RegisterList[i].Value;
+        param.i2c.reg_mask = 0xffff;
+        param.i2c.reg_shift = 0;
+        param.i2c.length = sizeof(short);
+
+        //configure component
+        component_handler->ACH_Handle(&param);
+
+        //Last: if this component is not referred anymore,disable component
+        if(component_handler->ref_count == 0){
+            if(component_handler->active == COMPONENT_ACTIVE){
+                component_handler->ACH_Disable();
+                component_handler->active = COMPONENT_INACTIVE;
+            }
+        }
+    }
+
+    return ACM_RC_OK;
+}
+
+ACM_ReturnCode APHAudioPathCheckPathId (int path_id_Rx,  int path_id_Tx) {
+
+    if ((path_id_Rx == INVALID_PATH_ID) || (path_id_Tx == INVALID_PATH_ID))
+    {
+        LOGE(APHAudioPathCheckPathId, "%s/L%d: Error", __FUNCTION__, __LINE__);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    if (((APH_PATH_ID_HIFIPLAYTOEARPHONE == path_id_Rx) ||(APH_PATH_ID_HIFIPLAYTOSPKR == path_id_Rx))
+            && (APH_PATH_ID_HIFIRECORDFROMMIC1 == path_id_Tx))
+    {
+        return ACM_RC_OK_HIFI_MATCHED;
+    }
+    else if ((APH_PATH_ID_HIFIPLAYTOHP == path_id_Rx) && (APH_PATH_ID_HIFIRECORDFROMHSMIC == path_id_Tx))
+    {
+        return ACM_RC_OK_HIFI_MATCHED;
+    }
+    else if (((APH_PATH_ID_VOICEPLAYTOEARPHONE == path_id_Rx) ||(APH_PATH_ID_VOICEPLAYTOSPKR == path_id_Rx)
+                 || (APH_PATH_ID_VOICEPLAYTOHP == path_id_Rx))
+            && (APH_PATH_ID_VOICERECORDFROMMIC1 == path_id_Tx))
+    {
+        return ACM_RC_OK_VOICE_MATCHED;
+    }
+    else if ((APH_PATH_ID_VOICEPLAYTOHP == path_id_Rx) && (APH_PATH_ID_VOICERECORDFROMHSMIC == path_id_Tx))
+    {
+        return ACM_RC_OK_VOICE_MATCHED;
+    }
+    else
+    {
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    return ACM_RC_OK;
+}
+
+ACM_ReturnCode APHAudioPathCheck (const char * path_Rx, const char * path_Tx) {
+
+    int path_id_Rx = INVALID_PATH_ID;
+    int path_id_Tx = INVALID_PATH_ID;
+
+    if ((NULL == path_Rx) || (NULL == path_Tx))
+    {
+        LOGE(APHAudioPathCheck, "%s/L%d: Rx path or Tx path is NULL, please check it.", __FUNCTION__, __LINE__);
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    path_id_Rx = _get_path_id(path_Rx);
+    path_id_Tx = _get_path_id(path_Tx);
+
+    if((path_id_Rx == INVALID_PATH_ID) || (path_id_Tx == INVALID_PATH_ID) )
+    {
+        LOGE(APHAudioPathCheck, "%s/L%d: Error", __FUNCTION__, __LINE__);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    if (((APH_PATH_ID_HIFIPLAYTOEARPHONE == path_id_Rx) ||(APH_PATH_ID_HIFIPLAYTOSPKR == path_id_Rx))
+            && (APH_PATH_ID_HIFIRECORDFROMMIC1 == path_id_Tx))
+    {
+        return ACM_RC_OK_HIFI_MATCHED;
+    }
+    else if ((APH_PATH_ID_HIFIPLAYTOHP == path_id_Rx) && (APH_PATH_ID_HIFIRECORDFROMHSMIC == path_id_Tx))
+    {
+        return ACM_RC_OK_HIFI_MATCHED;
+    }
+    else if (((APH_PATH_ID_VOICEPLAYTOEARPHONE == path_id_Rx) ||(APH_PATH_ID_VOICEPLAYTOSPKR == path_id_Rx)
+                 || (APH_PATH_ID_VOICEPLAYTOHP == path_id_Rx))
+            && (APH_PATH_ID_VOICERECORDFROMMIC1 == path_id_Tx))
+    {
+        return ACM_RC_OK_VOICE_MATCHED;
+    }
+    else if ((APH_PATH_ID_VOICEPLAYTOHP == path_id_Rx) && (APH_PATH_ID_VOICERECORDFROMHSMIC == path_id_Tx))
+    {
+        return ACM_RC_OK_VOICE_MATCHED;
+    }
+    else
+    {
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    return ACM_RC_OK;
+}
+
+void APHDisableAllPath(void)
+{
+    int i = 0;
+
+    //disable the enabled path
+    for (i=0; i<APH_PATH_ID_CNT; i++)
+    {
+        //disable the enabled path
+        if ( path_status_table[i].enabled)
+        {
+            LOGI(APHDisableAllPath, "disable the path:%s.......", AUDIO_PATH_ID_MAPPING[i].PathName);
+            ACMAudioPathDisable(AUDIO_PATH_ID_MAPPING[i].PathName);
+        }
+    }
+
+    return;
+}
+
+ACM_ReturnCode APHAudioPathSwitch (const char * path_Rx, const char * path_Tx, unsigned int value) {
+
+    char tmp_buffer[PATHSTATUS_MAX] = {0};
+    int i = 0;
+
+    if ((APHAudioPathCheck(path_Rx, path_Tx) != ACM_RC_OK_HIFI_MATCHED)
+            && (APHAudioPathCheck(path_Rx, path_Tx) != ACM_RC_OK_VOICE_MATCHED))
+    {
+        LOGE(APHAudioPathSwitch, "%s/L%d: Rx path is not matched with Tx path.", __FUNCTION__, __LINE__);
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    if (ACM_GetPathStatus(tmp_buffer, PATHSTATUS_MAX) != ACM_RC_OK)
+    {
+        LOGE(APHAudioPathSwitch, "%s/L%d: Get paths status failed", __FUNCTION__, __LINE__);
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    //before switch, before disable, list the path status
+    LOGI(APHAudioPathSwitch, "before switch, before disable, current every path status is:%s.......", tmp_buffer);
+
+    //disable the enabled path
+    for (i=0; i<APH_PATH_ID_CNT; i++)
+    {
+        //disable the enabled path
+        if ( path_status_table[i].enabled)
+        {
+            LOGI(APHAudioPathSwitch, "disable the path:%s.......", AUDIO_PATH_ID_MAPPING[i].PathName);
+            ACMAudioPathDisable(AUDIO_PATH_ID_MAPPING[i].PathName);
+        }
+    }
+
+    memset(tmp_buffer, 0x00, sizeof(tmp_buffer));
+
+    if (ACM_GetPathStatus(tmp_buffer, PATHSTATUS_MAX) != ACM_RC_OK)
+    {
+        LOGE(APHAudioPathSwitch, "%s/L%d: Get paths status failed", __FUNCTION__, __LINE__);
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    //before switch, after disable, list the path status
+    LOGI(APHAudioPathSwitch, "before switch, after disable, current every path status is:%s.......", tmp_buffer);
+
+    //enable the Rx path, and Tx path
+    ACMAudioPathEnable(path_Rx, value);
+    ACMAudioPathEnable(path_Tx, value);
+
+    memset(tmp_buffer, 0x00, sizeof(tmp_buffer));
+
+    if (ACM_GetPathStatus(tmp_buffer, PATHSTATUS_MAX) != ACM_RC_OK)
+    {
+        LOGE(APHAudioPathSwitch, "%s/L%d: Get paths status failed", __FUNCTION__, __LINE__);
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    //before switch, after disable, list the path status
+    LOGI(APHAudioPathSwitch, "after switch, after disable, current every path status is:%s.......", tmp_buffer);
+
+    return ACM_RC_OK;
+}
+
+ACM_ReturnCode APHAudioPathMute(const char * path, unsigned int value) {
+    int path_id = INVALID_PATH_ID;
+    APH_AudioComponent component;
+    ACMAPH_Register *RegisterList;
+    unsigned int i, size;
+    ACH_ComponentParameter param;
+    ACH_ComponentHandler *component_handler = NULL;
+    ACMAPH_Component *pTable = NULL;
+
+    if(acm_codec_connected == TRUE){
+        LOGI(APHAudioPathMute, "%s/L%d: path=%s, %s", __FUNCTION__, __LINE__, path, value?"Mute":"UnMute");
+    }
+    else {
+        LOGE(APHAudioPathMute, "%s/L%d: path=%s, no codec connected!", __FUNCTION__, __LINE__, path);
+        return ACM_RC_INVALID_PARAMETER;
+    }
+
+    path_id = _get_path_id(path);
+    if(path_id == INVALID_PATH_ID){
+        LOGE(APHAudioPathMute, "%s/L%d: Error path_id=%d", __FUNCTION__, __LINE__, path_id);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    if(value == 0)
+        pTable = _get_APHTable(path_id, ACM_UnMute, APH_PATH_IN_CNT);
+    else
+        pTable = _get_APHTable(path_id, ACM_Mute, APH_PATH_IN_CNT);
+    if(pTable == NULL){
+        LOGE(APHAudioPathMute, "%s/L%d: not in pTable{ACM_Mute,ACM_UnMute}=%d, path=%s", __FUNCTION__, __LINE__, pTable, path);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    if(path_status_table[path_id].enabled == 0){
+        LOGE(APHAudioPathMute, "%s/L%d: Count not operate on disabled path %s(%d)", __FUNCTION__, __LINE__, path, path_id);
+        return ACM_RC_PATH_ALREADY_DISABLED;
+    }
+
+    if(path_status_table[path_id].mute == value){
+        LOGE(APHAudioPathMute, "%s/L%d: path %s(%d) is already %", __FUNCTION__, __LINE__, path, path_id, value?"Mute":"UnMute");
+        return ACM_RC_NO_MUTE_CHANGE_NEEDED;
+    }
+    path_status_table[path_id].mute = value;
+
+    size = pTable->RegisterNum;
+    RegisterList = pTable->RegisterList;
+
+    for(i = 0; i < size; i++){
+        // get matched component
+        component = RegisterList[i].Component;
+        if(component == DELAY){
+            usleep(RegisterList[i].Value * 1000);
+            continue;
+        }
+
+        if(_get_component_handler(component) != component_handler ){
+            component_handler = _get_component_handler(component);
+
+            ///update component_handler-->ref_count: it depends on registers sorting style
+            component_handler->ref_count--;
+            LOGI(APHAudioPathMute, "%s/L%d: component=%s, ref_count=%d", __FUNCTION__, __LINE__, APH_AudioComponent_Name[component], component_handler->ref_count);
+        }
+
+        //fill param
+        param.i2c.reg_index = RegisterList[i].Address;
+        param.i2c.reg_value = &RegisterList[i].Value;
+        param.i2c.reg_mask = 0xffff;
+        param.i2c.reg_shift = 0;
+        param.i2c.length = sizeof(short);
+
+        //configure component
+        component_handler->ACH_Handle(&param);
+    }
+
+    return ACM_RC_OK;
+}
+
+void configCodecGainfromNVM(APH_AudioComponent Component_NVM, unsigned char Address_NVM, unsigned short Value_NVM)
+{
+    ACH_ComponentHandler *component_handler = NULL;
+    APH_AudioComponent component;
+    ACH_ComponentParameter param;
+
+    LOGI(configCodecGainfromNVM,"%s/L%d:: Component=[%d], Address_NVM=[0X%x], Value_NVM=[0X%x] !",
+            __FUNCTION__, __LINE__, Component_NVM, Address_NVM, Value_NVM);
+
+    //if(volume == RegisterList[i].Volume ){
+    // get matched component
+    component = Component_NVM;
+    //component = RegisterList[i].Component;
+    if(component == DELAY)
+    {
+        //usleep(RegisterList[i].Value * 1000);
+        usleep(Value_NVM * 1000);
+        return;
+    }
+
+    if(_get_component_handler(component) != component_handler )
+    {
+        component_handler = _get_component_handler(component);
+
+        ///update component_handler-->ref_count: it depends on registers sorting style
+        component_handler->ref_count--;
+        LOGI(configCodecGainfromNVM, "%s/L%d: component=%s, ref_count=%d", __FUNCTION__, __LINE__, APH_AudioComponent_Name[component], component_handler->ref_count);
+    }
+
+    //fill param
+    param.i2c.reg_index = Address_NVM;
+    param.i2c.reg_value = &Value_NVM;
+    param.i2c.reg_mask = 0xffff;
+    param.i2c.reg_shift = 0;
+    param.i2c.length = sizeof(short);
+
+    LOGI(configCodecGainfromNVM,"%s/L%d:: Address = 0X%x, .Value=0X%x!",  __FUNCTION__, __LINE__, Address_NVM, Value_NVM);
+
+    //configure component
+    component_handler->ACH_Handle(&param);
+
+    return;
+}
+
+ACM_ReturnCode APHAudioPathVolumeSet(const char * path, unsigned int value) {
+    int path_id = INVALID_PATH_ID;
+    unsigned char volume = 0;
+    unsigned int i;
+    unsigned char index_volume = 0;
+
+#if  defined(CODEC_PM805) || defined(CODEC_PM812) || defined(CODEC_NAU8810) || defined(CODEC_ALC5616)
+    AC_IPC_Package  package;
+    ACMCodec_GainT buffer;
+    AUDIO_PROFILE_ID cur_Profile_id = HIFI_HANDSET;
+
+    APH_AudioComponent Component_NVM;
+    unsigned char Address_NVM;
+    unsigned short Value_NVM;
+
+    memset(&package, 0x00, sizeof(AC_IPC_Package));
+    memset(&buffer, 0x00, sizeof(ACMCodec_GainT));
+#else
+    ACMAPH_VolumeComponent *pTable = NULL;
+#endif
+
+    if(acm_codec_connected == TRUE){
+        LOGI(APHAudioPathVolumeSet, "%s/L%d: path=%s, value=0x%x", __FUNCTION__, __LINE__, path, value);
+    }
+    else {
+        LOGE(APHAudioPathVolumeSet, "%s/L%d: path=%s, no codec connected!", __FUNCTION__, __LINE__, path);
+        return ACM_RC_INVALID_PARAMETER;
+    }
+
+    path_id = _get_path_id(path);
+    if(path_id == INVALID_PATH_ID){
+        LOGE(APHAudioPathVolumeSet, "%s/L%d: Error path_id=%d", __FUNCTION__, __LINE__, path_id);
+        return ACM_RC_INVALID_PATH;
+    }
+
+#if  defined(CODEC_PM805) || defined(CODEC_PM812) || defined(CODEC_NAU8810) || defined(CODEC_ALC5616)
+    if ((APH_PATH_ID_HIFIRECORDFROMMIC1 == path_id) || (APH_PATH_ID_HIFIRECORDFROMHSMIC == path_id)
+            || (APH_PATH_ID_VOICERECORDFROMMIC1 == path_id) ||(APH_PATH_ID_VOICERECORDFROMHSMIC == path_id))
+    {
+        LOGI(APHAudioPathVolumeSet, "===%s/L%d: PATH ID=%d, no need to config Tx gain! ===", __FUNCTION__, __LINE__, path_id);
+        return ACM_RC_OK;
+    }
+
+    //RX path is mapping to PROFILE.
+    switch (path_id)
+    {
+        case APH_PATH_ID_HIFIPLAYTOEARPHONE:
+            cur_Profile_id = HIFI_HANDSET;
+            break;
+
+        case APH_PATH_ID_HIFIPLAYTOSPKR:
+            cur_Profile_id = HIFI_SPEAKER;
+            break;
+
+        case APH_PATH_ID_HIFIPLAYTOHP:
+            cur_Profile_id = HIFI_HEADSET;
+            break;
+
+        case APH_PATH_ID_VOICEPLAYTOEARPHONE:
+            cur_Profile_id = VC_HANDSET;
+            break;
+
+        case APH_PATH_ID_VOICEPLAYTOSPKR:
+            cur_Profile_id = VC_HANDSFREE;
+            break;
+
+        case APH_PATH_ID_VOICEPLAYTOHP:
+            cur_Profile_id = VC_HEADSET;
+            break;
+
+        default:
+            LOGI(APHAudioPathVolumeSet, "%s/L%d: PATH ID=%d, PATH is %s.", __FUNCTION__, __LINE__, path_id, path);
+            break;
+    }
+
+    package.type = AUDIO_NVM_GetGainConfigure;
+    package.body.d1 = 0;
+    package.body.d2 = cur_Profile_id;   //path ID (unsigned short)
+    package.ptr = &buffer;
+
+    NVM_Calibration_IPC(&package);
+
+    LOGI(APHAudioPathVolumeSet,"APHAudioPathVolumeSet:: profile=%d, Tx_DSPGain=%d, sizeof(AUDIO_PROFILE_ID)=%d!",
+            buffer.Profile_id, buffer.Tx_DSPGain, sizeof(AUDIO_PROFILE_ID));
+
+    for (i=0; i<AUDIOHAL_SPK_VOL_QTY; i++)
+    {
+        LOGI(APHAudioPathVolumeSet,"Rx_CodecGain[%d]:: Component_1=0x%x, RegAddr_1=0x%x, RegVal_1=0x%x !",
+                i, buffer.Rx_CodecGain[i].Component_1, buffer.Rx_CodecGain[i].RegAddr_1, buffer.Rx_CodecGain[i].RegVal_1);
+
+        LOGI(APHAudioPathVolumeSet,"Rx_CodecGain[%d]:: Component_2=0x%x, RegAddr_2=0x%x, RegVal_2=0x%x !",
+                i, buffer.Rx_CodecGain[i].Component_2, buffer.Rx_CodecGain[i].RegAddr_2, buffer.Rx_CodecGain[i].RegVal_2);
+
+        LOGI(APHAudioPathVolumeSet,"Rx_CodecGain[%d]:: Component_3=0x%x, RegAddr_3=0x%x, RegVal_3=0x%x !\n",
+                i, buffer.Rx_CodecGain[i].Component_3, buffer.Rx_CodecGain[i].RegAddr_3, buffer.Rx_CodecGain[i].RegVal_3);
+
+        LOGI(APHAudioPathVolumeSet,"Rx_CodecGain[%d]:: Component_4=0x%x, RegAddr_4=0x%x, RegVal_4=0x%x !\n",
+                i, buffer.Rx_CodecGain[i].Component_4, buffer.Rx_CodecGain[i].RegAddr_4, buffer.Rx_CodecGain[i].RegVal_4);
+    }
+
+#endif
+
+#if  !defined(CODEC_PM805) && !defined(CODEC_PM812) && !defined(CODEC_NAU8810) && !defined(CODEC_ALC5616)
+    pTable = _get_APHVolumeTable(path_id, ACM_Volume, APH_PATH_OUT_CNT);
+    if(pTable == NULL){
+        LOGE(APHAudioPathVolumeSet, "%s/L%d: Error pTable=%d", __FUNCTION__, __LINE__, pTable);
+        return ACM_RC_INVALID_PATH;
+    }
+#endif
+
+    if(path_status_table[path_id].enabled == 0){
+        LOGE(APHAudioPathVolumeSet, "%s/L%d: Path %s(%d) is not enabled", __FUNCTION__, __LINE__, path, path_id);
+        return ACM_RC_PATH_NOT_ENABLED;
+    }
+
+    if(path_status_table[path_id].value == value){
+        LOGE(APHAudioPathVolumeSet, "%s/L%d: Path %s(%d), value=%d.", __FUNCTION__, __LINE__, path, path_id, value);
+        /* when modify the value of NVM and reload the modification, need to complete the following procedure. */
+        //return ACM_RC_INVALID_VOLUME_CHANGE;
+    }
+
+    LOGI(APHAudioPathVolumeSet,"%s/L%d:: path_status_table[%d].value = %d!", __FUNCTION__, __LINE__, path_id, path_status_table[path_id].value);
+
+    path_status_table[path_id].value = value;
+    volume = (unsigned char)(value & VOLUME_MASK);
+    volume = (volume + 5) /10;
+    index_volume = volume;
+    volume *= 10;
+
+    LOGI(APHAudioPathVolumeSet,"%s/L%d:: volume = %d!", __FUNCTION__, __LINE__, volume);
+
+    if (volume > MAX_VOLUME_INDEX) {
+        LOGE(APHAudioPathVolumeSet,"%s/L%d:: too big volume = %d!", __FUNCTION__, __LINE__, volume);
+        return ACM_RC_INVALID_VOLUME_CHANGE;
+    }
+
+#if  defined(CODEC_PM805) || defined(CODEC_PM812) || defined(CODEC_NAU8810) || defined(CODEC_ALC5616)
+
+    if (0xFFFF != buffer.Rx_CodecGain[index_volume].RegAddr_1)
+    {
+        Component_NVM = buffer.Rx_CodecGain[index_volume].Component_1;
+        Address_NVM = buffer.Rx_CodecGain[index_volume].RegAddr_1;
+        Value_NVM = buffer.Rx_CodecGain[index_volume].RegVal_1;
+
+        configCodecGainfromNVM( Component_NVM, Address_NVM, Value_NVM);
+    }
+
+    if (0xFFFF != buffer.Rx_CodecGain[index_volume].RegAddr_2)
+    {
+        Component_NVM = buffer.Rx_CodecGain[index_volume].Component_2;
+        Address_NVM = buffer.Rx_CodecGain[index_volume].RegAddr_2;
+        Value_NVM = buffer.Rx_CodecGain[index_volume].RegVal_2;
+
+        configCodecGainfromNVM( Component_NVM, Address_NVM, Value_NVM);
+    }
+
+    if (0xFFFF != buffer.Rx_CodecGain[index_volume].RegAddr_3)
+    {
+        Component_NVM = buffer.Rx_CodecGain[index_volume].Component_3;
+        Address_NVM = buffer.Rx_CodecGain[index_volume].RegAddr_3;
+        Value_NVM = buffer.Rx_CodecGain[index_volume].RegVal_3;
+
+        configCodecGainfromNVM( Component_NVM, Address_NVM, Value_NVM);
+    }
+
+    if (0xFFFF != buffer.Rx_CodecGain[index_volume].RegAddr_4)
+    {
+        Component_NVM = buffer.Rx_CodecGain[index_volume].Component_4;
+        Address_NVM = buffer.Rx_CodecGain[index_volume].RegAddr_4;
+        Value_NVM = buffer.Rx_CodecGain[index_volume].RegVal_4;
+
+        configCodecGainfromNVM( Component_NVM, Address_NVM, Value_NVM);
+    }
+
+    LOGI(APHAudioPathVolumeSet,"Tx_CodecGain:: Component_1=0x%x, RegAddr_1=0x%x, RegVal_1=0x%x !\n",
+            buffer.Tx_CodecGain.Component_1, buffer.Tx_CodecGain.RegAddr_1, buffer.Tx_CodecGain.RegVal_1);
+
+    LOGI(APHAudioPathVolumeSet,"Tx_CodecGain:: Component_2=0x%x, RegAddr_2=0x%x, RegVal_2=0x%x !\n",
+            buffer.Tx_CodecGain.Component_2, buffer.Tx_CodecGain.RegAddr_2, buffer.Tx_CodecGain.RegVal_2);
+
+    LOGI(APHAudioPathVolumeSet,"Tx_CodecGain:: Component_3=0x%x, RegAddr_3=0x%x, RegVal_3=0x%x !\n",
+            buffer.Tx_CodecGain.Component_3, buffer.Tx_CodecGain.RegAddr_3, buffer.Tx_CodecGain.RegVal_3);
+
+    LOGI(APHAudioPathVolumeSet,"Tx_CodecGain:: Component_4=0x%x, RegAddr_4=0x%x, RegVal_4=0x%x !\n",
+            buffer.Tx_CodecGain.Component_4, buffer.Tx_CodecGain.RegAddr_4, buffer.Tx_CodecGain.RegVal_4);
+    //config Tx_CodecGain of acm_nvm.h here.
+    if (0xFFFF != buffer.Tx_CodecGain.RegAddr_1)
+    {
+        Component_NVM = buffer.Tx_CodecGain.Component_1;
+        Address_NVM = buffer.Tx_CodecGain.RegAddr_1;
+        Value_NVM = buffer.Tx_CodecGain.RegVal_1;
+
+        configCodecGainfromNVM( Component_NVM, Address_NVM, Value_NVM);
+    }
+
+    if (0xFFFF != buffer.Tx_CodecGain.RegAddr_2)
+    {
+        Component_NVM = buffer.Tx_CodecGain.Component_2;
+        Address_NVM = buffer.Tx_CodecGain.RegAddr_2;
+        Value_NVM = buffer.Tx_CodecGain.RegVal_2;
+
+        configCodecGainfromNVM( Component_NVM, Address_NVM, Value_NVM);
+    }
+
+    if (0xFFFF != buffer.Tx_CodecGain.RegAddr_3)
+    {
+        Component_NVM = buffer.Tx_CodecGain.Component_3;
+        Address_NVM = buffer.Tx_CodecGain.RegAddr_3;
+        Value_NVM = buffer.Tx_CodecGain.RegVal_3;
+
+        configCodecGainfromNVM( Component_NVM, Address_NVM, Value_NVM);
+    }
+
+    if (0xFFFF != buffer.Tx_CodecGain.RegAddr_4)
+    {
+        Component_NVM = buffer.Tx_CodecGain.Component_4;
+        Address_NVM = buffer.Tx_CodecGain.RegAddr_4;
+        Value_NVM = buffer.Tx_CodecGain.RegVal_4;
+
+        configCodecGainfromNVM( Component_NVM, Address_NVM, Value_NVM);
+    }
+    return ACM_RC_OK;
+#else
+    return ACM_RC_OK;
+#endif
+}
+
+
+ACM_ReturnCode ACM_GetPathStatus(char *buff, unsigned int maxsize) {
+    unsigned int index = 0, size = 0, total = 0;
+    char *ptr = buff;
+
+    for(index = 0; index < APH_PATH_ID_CNT; index++){
+        //Prevent buff overwritten: reserve 100 bytes for this time
+        if(total > maxsize - 100)
+            return ACM_RC_INVALID_PARAMETER;
+
+        size = sprintf(ptr, "  : %-30s:%9s,%8s, volume=%d\n", AUDIO_PATH_ID_MAPPING[index].PathName, path_status_table[index].enabled?"enabled":"disabled", path_status_table[index].mute?"muted":"unmuted", path_status_table[index].value);
+        if(size > 0)
+            ptr += size;
+        else
+            return ACM_RC_INVALID_PARAMETER;
+        total += size;
+    }
+
+    return ACM_RC_OK;
+}
+
+unsigned int ACM_GetEnabledPathVolume(void)
+{
+    int i;
+    unsigned int enabled_path_id_Rx = INVALID_PATH_ID;
+    unsigned int enabled_path_id_Tx = INVALID_PATH_ID;
+    unsigned int enabled_volume_Rx = 80;//refer to the value: madev->voice_volume = 0.8f;
+    unsigned int enabled_mute_Tx = 0;
+
+    for (i=0; i<APH_PATH_ID_CNT; i++)
+    {
+        //save the enabled path.
+        if ( path_status_table[i].enabled)
+        {
+            if ((i != APH_PATH_ID_HIFIRECORDFROMMIC1) && (i != APH_PATH_ID_HIFIRECORDFROMHSMIC)
+                    && (i !=APH_PATH_ID_VOICERECORDFROMMIC1) && (i !=APH_PATH_ID_VOICERECORDFROMHSMIC))
+            {
+                enabled_path_id_Rx = i;//record Rx path.
+                enabled_volume_Rx = path_status_table[i].value;
+            }
+            else
+            {
+                enabled_path_id_Tx = i;//record Tx path.
+                enabled_mute_Tx = path_status_table[i].mute;
+            }
+        }
+    }
+
+    LOGI(ACM_GetEnabledPathVolume, "%s/L%d: enabled_path_id_Rx=%d, enabled_path_id_Tx=%d, enabled_volume_Rx=%d, enabled_mute_Tx=%d,",
+            __FUNCTION__, __LINE__,enabled_path_id_Rx,enabled_path_id_Tx, enabled_volume_Rx, enabled_mute_Tx);
+
+    return enabled_volume_Rx;
+}
+
+ACM_ReturnCode ACM_GetPathDirection(const char *path, unsigned char *path_direction) {
+    return _get_path_direction(path, path_direction);
+}
+
+ACM_ReturnCode APHGetMSAGain(const char *out_path, const char *path, unsigned char *volume, unsigned short id, signed short *gain, signed short *sidetone_gain) {
+
+#if  defined(CODEC_PM805) || defined(CODEC_PM812) || defined(CODEC_NAU8810) || defined(CODEC_ALC5616)
+    int path_id = INVALID_PATH_ID;
+    AC_IPC_Package  package;
+    ACMCodec_GainT buffer;
+    unsigned char Volume_value;
+    unsigned char index_volume;
+    AUDIO_PROFILE_ID cur_Profile_id = HIFI_HANDSET;
+
+    memset(&package, 0x00, sizeof(AC_IPC_Package));
+    memset(&buffer, 0x00, sizeof(ACMCodec_GainT));
+
+    LOGI(APHGetMSAGain, "%s/L%d: out_path=%s, path=%s, volume=%d, id=%d", __FUNCTION__, __LINE__, out_path, path, *volume, id);
+
+    //If not equal between out_path and path, it is input device, we need to use out_path to get gain from NVM.
+    path_id = _get_path_id(out_path);
+    if(path_id == INVALID_PATH_ID)
+    {
+        LOGE(APHGetMSAGain, "%s: ERROR: can not find matched path id", __FUNCTION__);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    //RX path is mapping to PROFILE.
+    switch (path_id)
+    {
+        case APH_PATH_ID_HIFIPLAYTOEARPHONE:
+            cur_Profile_id = HIFI_HANDSET;
+            break;
+
+        case APH_PATH_ID_HIFIPLAYTOSPKR:
+            cur_Profile_id = HIFI_SPEAKER;
+            break;
+
+        case APH_PATH_ID_HIFIPLAYTOHP:
+            cur_Profile_id = HIFI_HEADSET;
+            break;
+
+        case APH_PATH_ID_VOICEPLAYTOEARPHONE:
+            cur_Profile_id = VC_HANDSET;
+            break;
+
+        case APH_PATH_ID_VOICEPLAYTOSPKR:
+            cur_Profile_id = VC_HANDSFREE;
+            break;
+
+        case APH_PATH_ID_VOICEPLAYTOHP:
+            cur_Profile_id = VC_HEADSET;
+            break;
+
+        default:
+            LOGI(APHGetMSAGain, "%s/L%d: PATH ID=%d, PATH is %s.", __FUNCTION__, __LINE__, path_id, path);
+            break;
+    }
+
+    package.type = AUDIO_NVM_GetGainConfigure;
+    package.body.d1 = 0;
+    package.body.d2 = cur_Profile_id;   //path ID (unsigned short)
+    package.ptr = &buffer;
+
+    NVM_Calibration_IPC(&package);
+
+    Volume_value = (unsigned char)((*volume) & VOLUME_MASK);
+    Volume_value = (Volume_value + 5) /10;
+    index_volume = Volume_value;
+    Volume_value *= 10;
+
+    if (strcmp(out_path, path))
+    {//MIC, HSMIC...
+        *gain = buffer.Tx_DSPGain;
+        *sidetone_gain = 0;
+        LOGI(APHGetMSAGain,"APHGetMSAGain::profile=%d, Tx DSP gain = 0x%hx, sidetone = 0x%hx!", buffer.Profile_id, *gain, *sidetone_gain);
+    }
+    else
+    {//EARPHONE, SPEAKER...
+        *gain = buffer.Rx_DSPGain[index_volume];
+        *sidetone_gain = buffer.Rx_DSPSideToneGain;
+        LOGI(APHGetMSAGain,"APHGetMSAGain::profile=%d, Rx DSP gain = 0x%hx, sidetone = 0x%hx!", buffer.Profile_id, *gain, *sidetone_gain);
+    }
+
+    return ACM_RC_OK;
+
+#else
+
+    *gain = 0;
+    *sidetone_gain = 0x8080;//0x8080=disable sidetone
+    LOGI(APHGetMSAGain,"Not supported codec! APHGetMSAGain:: DSP gain = 0x%hx, sidetone = 0x%hx!", *gain, *sidetone_gain);
+    return ACM_RC_OK;
+
+#endif
+
+}
+
+#ifdef PXA1826_AUDIO
+ACM_ReturnCode APHSetMSAGain(AC_Digital_Gain *gain) {
+    VolumeCtlMsg volume_cmd;
+    int ioctl_fd;
+
+    // If no voice path actived, will not configure DSP
+    if((gain->path_direction_Rx > 1) || (gain->path_direction_Tx > 1))
+    {
+        LOGI(APHSetMSAGain, "no voice path actived, will not configure DSP: Rx=%d,Tx=%d", gain->path_direction_Rx, gain->path_direction_Tx);    
+        return ACM_RC_OK;
+    }
+
+    ioctl_fd = open("/dev/audiostub_ctl", O_RDONLY);
+    if(ioctl_fd < 0)
+    {
+        LOGI(APHSetMSAGain, "failed to open audiostub_ctl: %s", strerror(errno));
+        return ACM_RC_PATH_NOT_ENABLED;
+    }
+
+    //Rx
+    memset(&volume_cmd, 0, sizeof(volume_cmd));
+    volume_cmd.direction = gain->path_direction_Rx;
+    volume_cmd.gain = gain->digital_gain_Rx;
+    volume_cmd.misc_volume = gain->volume_Rx;
+    if(ioctl(ioctl_fd, AUDIOSTUB_VOLUMECTL, &volume_cmd) < 0)
+    {
+        LOGI(APHSetMSAGain, "audio_stub ioctl error: %s", strerror(errno));
+        close(ioctl_fd);
+        return ACM_RC_INVALID_PARAMETER;
+    }
+
+    //Tx
+    memset(&volume_cmd, 0, sizeof(volume_cmd));
+    volume_cmd.direction = gain->path_direction_Tx;
+    volume_cmd.gain = gain->digital_gain_Tx;
+    volume_cmd.misc_volume = gain->volume_Tx;
+    if(ioctl(ioctl_fd, AUDIOSTUB_VOLUMECTL, &volume_cmd) < 0)
+    {
+        LOGI(APHSetMSAGain, "audio_stub ioctl error: %s", strerror(errno));
+        close(ioctl_fd);
+        return ACM_RC_INVALID_PARAMETER;
+    }
+
+    //SideTone
+    memset(&volume_cmd, 0, sizeof(volume_cmd));
+    volume_cmd.direction = gain->path_direction_SideTone;
+    volume_cmd.gain = gain->digital_gain_SideTone;
+    volume_cmd.misc_volume = gain->volume_SideTone;
+    if(ioctl(ioctl_fd, AUDIOSTUB_VOLUMECTL, &volume_cmd) < 0)
+    {
+        LOGI(APHSetMSAGain, "audio_stub ioctl error: %s", strerror(errno));
+        close(ioctl_fd);
+        return ACM_RC_INVALID_PARAMETER;
+    }
+
+    close(ioctl_fd);
+    LOGI(APHSetMSAGain, "APHSetMSAGain success!");
+
+    return ACM_RC_OK;
+}
+#endif
+
+#ifdef TARGET_mmp_asr1901_KSTR901
+extern int audio_dsp_send_ve(void* ve);
+
+void ACM_SendVEtoADSP(void) {
+    AC_IPC_Package package;
+    EnhanceParmsT buffer;
+
+    memset(&package, 0x00, sizeof(AC_IPC_Package));
+    memset(&buffer, 0x00, sizeof(EnhanceParmsT));
+
+    LOGI(ACM_SendVEtoADSP, "%s/%d\n", __FUNCTION__, __LINE__);
+
+    package.type = AUDIO_NVM_GetVEConfigure;
+    package.body.d1 = 0;
+    package.body.d2 = 0;
+    package.ptr = &buffer;
+
+    NVM_Calibration_IPC(&package);
+    audio_dsp_send_ve(&buffer);
+}
+#endif
+
+ACM_ReturnCode ACM_GetEnabledPathId(int *path_id_Rx, int *path_id_Tx, int *volume_Rx, int *mute_Tx)
+{
+    int i;
+
+    int enabled_path_id_Rx = INVALID_PATH_ID;
+    int enabled_path_id_Tx = INVALID_PATH_ID;
+    int enabled_volume_Rx = 0;
+    int enabled_mute_Tx = 0;
+
+    for (i=0; i<APH_PATH_ID_CNT; i++)
+    {
+        //save the enabled path.
+        if ( path_status_table[i].enabled)
+        {
+            if ((i != APH_PATH_ID_HIFIRECORDFROMMIC1) && (i != APH_PATH_ID_HIFIRECORDFROMHSMIC)
+                    && (i !=APH_PATH_ID_VOICERECORDFROMMIC1) && (i !=APH_PATH_ID_VOICERECORDFROMHSMIC))
+            {
+                enabled_path_id_Rx = i;//record Rx path.
+                enabled_volume_Rx = path_status_table[i].value;
+            }
+            else
+            {
+                enabled_path_id_Tx = i;//record Tx path.
+                enabled_mute_Tx = path_status_table[i].mute;
+            }
+        }
+    }
+
+    LOGI(ACM_GetEnabledPathId, "%s/L%d: enabled_path_id_Rx=%d, enabled_path_id_Tx=%d, enabled_volume_Rx=%d, enabled_mute_Tx=%d,",
+            __FUNCTION__, __LINE__,enabled_path_id_Rx,enabled_path_id_Tx, enabled_volume_Rx, enabled_mute_Tx);
+
+    *path_id_Rx = enabled_path_id_Rx;
+    *path_id_Tx = enabled_path_id_Tx;
+    *volume_Rx = enabled_volume_Rx;
+    *mute_Tx = enabled_mute_Tx;
+
+    return ACM_RC_OK;
+}
+
+ACM_ReturnCode ACM_ReloadCalibrationData(void) {
+    char tmp_buffer[PATHSTATUS_MAX] = {0};
+    int i = 0, value;
+    int path_id_Rx = INVALID_PATH_ID;
+    int path_id_Tx = INVALID_PATH_ID;
+    int volume_Rx = 0;
+    char mute_Tx = 0;
+    AUDIO_PROFILE_ID cur_Profile_id = HIFI_HANDSET;
+    AC_IPC_Package  package;
+
+    /*
+        First: send message "AUDIO_NVM_ReloadCalibrationData" to NVM server, trigger reload nvm.
+        No matter whether there is enabled path.
+    */
+    memset(&package, 0x00, sizeof(AC_IPC_Package));
+    package.type = AUDIO_NVM_ReloadCalibrationData;
+    package.body.d1 = 0;
+    package.body.d2 = 0;
+    package.ptr = &value;
+    NVM_Calibration_IPC(&package);
+
+    //Second: get path status.
+    if (ACM_GetPathStatus(tmp_buffer, PATHSTATUS_MAX) != ACM_RC_OK)
+    {
+        LOGE(ACM_ReloadCalibrationData, "%s/L%d: Get paths status failed", __FUNCTION__, __LINE__);
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    //list the path status, before ReloadCalibrationData
+    LOGI(ACM_ReloadCalibrationData, "before ReloadCalibrationData, record the path status, current every path status is:\n%s.......", tmp_buffer);
+
+    for (i=0; i<APH_PATH_ID_CNT; i++)
+    {
+        //save the enabled path.
+        if ( path_status_table[i].enabled)
+        {
+            if ((i != APH_PATH_ID_HIFIRECORDFROMMIC1) && (i != APH_PATH_ID_HIFIRECORDFROMHSMIC)
+                    && (i !=APH_PATH_ID_VOICERECORDFROMMIC1) && (i !=APH_PATH_ID_VOICERECORDFROMHSMIC))
+            {
+                path_id_Rx = i;//record Rx path.
+                volume_Rx = path_status_table[i].value;
+            }
+            else
+            {
+                path_id_Tx = i;//record Tx path.
+                mute_Tx = path_status_table[i].mute;
+            }
+        }
+    }
+
+    if ((INVALID_PATH_ID == path_id_Rx) || (INVALID_PATH_ID == path_id_Tx))
+    {
+        LOGI(ACM_ReloadCalibrationData, "%s/L%d: no enabled path.", __FUNCTION__, __LINE__);
+        return ACM_RC_OK;
+    }
+
+    LOGI(ACM_ReloadCalibrationData, "%s/L%d: actived path:Rx path:%s, Tx path:%s",
+            __FUNCTION__, __LINE__, AUDIO_PATH_ID_MAPPING[path_id_Rx].PathName, AUDIO_PATH_ID_MAPPING[path_id_Tx].PathName);
+
+    if ((APHAudioPathCheck(AUDIO_PATH_ID_MAPPING[path_id_Rx].PathName, AUDIO_PATH_ID_MAPPING[path_id_Tx].PathName) != ACM_RC_OK_HIFI_MATCHED)
+            && (APHAudioPathCheck(AUDIO_PATH_ID_MAPPING[path_id_Rx].PathName, AUDIO_PATH_ID_MAPPING[path_id_Tx].PathName) != ACM_RC_OK_VOICE_MATCHED))
+    {
+        LOGE(ACM_ReloadCalibrationData, "%s/L%d: Rx path is not matched with Tx path.", __FUNCTION__, __LINE__);
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    //RX path is mapping to PROFILE.
+    switch (path_id_Rx)
+    {
+        case APH_PATH_ID_HIFIPLAYTOEARPHONE:
+            cur_Profile_id = HIFI_HANDSET;
+            break;
+
+        case APH_PATH_ID_HIFIPLAYTOSPKR:
+            cur_Profile_id = HIFI_SPEAKER;
+            break;
+
+        case APH_PATH_ID_HIFIPLAYTOHP:
+            cur_Profile_id = HIFI_HEADSET;
+            break;
+
+        case APH_PATH_ID_VOICEPLAYTOEARPHONE:
+            cur_Profile_id = VC_HANDSET;
+            break;
+
+        case APH_PATH_ID_VOICEPLAYTOSPKR:
+            cur_Profile_id = VC_HANDSFREE;
+            break;
+
+        case APH_PATH_ID_VOICEPLAYTOHP:
+            cur_Profile_id = VC_HEADSET;
+            break;
+
+        default:
+            LOGI(ACM_ReloadCalibrationData, "%s/L%d.", __FUNCTION__, __LINE__);
+            break;
+    }
+
+    LOGI(ACM_ReloadCalibrationData,"AUDIO_NVM_ReloadCalibrationData:: profile=%d, sizeof(AUDIO_PROFILE_ID)=%d!",
+            cur_Profile_id, sizeof(AUDIO_PROFILE_ID));
+
+    //Third:enable the saved path using new config.
+    APHAudioPathDisable(AUDIO_PATH_ID_MAPPING[path_id_Rx].PathName);
+    APHAudioPathDisable(AUDIO_PATH_ID_MAPPING[path_id_Tx].PathName);
+
+    ACMAudioPathEnable(AUDIO_PATH_ID_MAPPING[path_id_Rx].PathName, volume_Rx);
+    ACMAudioPathEnable(AUDIO_PATH_ID_MAPPING[path_id_Tx].PathName, volume_Rx);
+    APHAudioPathMute(AUDIO_PATH_ID_MAPPING[path_id_Tx].PathName, mute_Tx);
+
+    //Forth: List the path status.
+    memset(tmp_buffer, 0x00, sizeof(tmp_buffer));
+
+    if (ACM_GetPathStatus(tmp_buffer, PATHSTATUS_MAX) != ACM_RC_OK)
+    {
+        LOGE(ACM_ReloadCalibrationData, "%s/L%d: Get paths status failed", __FUNCTION__, __LINE__);
+        return ACM_RC_PATH_CONFIG_NOT_EXIST;
+    }
+
+    //After recover the enabled path, list the path status
+    LOGI(ACM_ReloadCalibrationData, "After recover the enabled path, list the path status is:%s.......", tmp_buffer);
+
+    return ACM_RC_OK;
+}
+
+void ACM_enable_headset_detection_ALC5616(void)
+{
+#ifdef TARGET_mmp_asr1901_KSTR901
+    system("echo 1 > /sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.1/i2c-1/1-001b/alc5616-headset/enable_headset_detection");
+#else
+    system("echo 1 > /sys/devices/platform/soc/d4000000.apb/pxa2xx-i2c.0/i2c-0/0-001b/alc5616-headset/enable_headset_detection");
+#endif
+    return;
+}
+
+void ACM_APHInit(void) {
+#ifdef PXA1826_AUDIO
+    int ret = 0;
+    int err, ioctl_fd, status = 0;
+#endif
+    int value;
+    AC_IPC_Package  package;
+
+    if (0 == get_debug_mode())
+    {
+        /* 1:on; 0:off, default. if g_audio_if_debug_mode is on, no need to send msg to NVMProxy. */
+
+        //Reload AP Audio NVM
+        package.type = AUDIO_NVM_ReloadCalibrationData;
+        package.body.d1 = 0;
+        package.body.d2 = 0;
+        package.ptr = &value;
+        NVM_Calibration_IPC(&package);
+    }
+
+    //reset components status
+    if(acm_codec_connected == TRUE){
+        _reset_components_status();
+        _reset_components_registers();
+    }
+
+    /*
+      * From audio_stub, get the properties of nb/wb, master/slave
+     */
+#ifdef PXA1826_AUDIO
+    ioctl_fd = open("/dev/audiostub_ctl", O_RDONLY);
+    if (ioctl_fd < 0) {
+        err = errno;
+        ALOGE(ACM_APHInit9, "failed to open audiostub_ctl:%s\n", strerror(err));
+        return;
+    }
+
+    ret = ioctl(ioctl_fd, AUDIOSTUB_GET_STATUS, &status);
+    if (ret < 0) {
+        ALOGE(ACM_APHInit10, "Warning, audio_stub ioctl error: %s", strerror(errno));
+    }
+    modem_is_wb = IS_WB(status);
+    modem_is_master = IS_PCM_MASTER(status);
+
+    LOGI(ACM_APHInit, "%s/L%d: modem_is_wb=%d, modem_is_master=%d", __FUNCTION__, __LINE__, modem_is_wb, modem_is_master);
+
+    //close the file after got status report
+    close(ioctl_fd);
+#endif
+}
+
+void ACM_APHDeInit(void) {
+}
+
+
+/* Audio uses PROPERTY_AUDIO_CODEC which is not created by PXA1826 init
+ * Call from ACMInit() to set property with default value "1"
+ * depending upon the AUDIO package is better than in init.rc
+ * (No other setprop are present for now)
+ */
+void ACM_Init_Property(void)
+{
+	char property_value[PROPERTY_VALUE_MAX];
+	int i = property_get(PROPERTY_AUDIO_CODEC, property_value, NULL);
+	if (i <= 0) {
+        LOGD(ACM_Init_Property, "Not found %s. Create with default value=%d", PROPERTY_AUDIO_CODEC, (modem_is_master == 0)?1:0);
+        if(modem_is_master == 0)
+            property_set(PROPERTY_AUDIO_CODEC, "1");    //persist.audio.codecmaster = 1
+        else
+            property_set(PROPERTY_AUDIO_CODEC, "0");    //persist.audio.codecmaster = 0
+	}
+    else
+        LOGD(ACM_Init_Property, "Found %s. value=%s", PROPERTY_AUDIO_CODEC, property_value);
+}
+